]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
merge upstream changes to svn r2096
authorMichael Jerris <mike@jerris.com>
Fri, 20 Nov 2009 22:00:51 +0000 (22:00 +0000)
committerMichael Jerris <mike@jerris.com>
Fri, 20 Nov 2009 22:00:51 +0000 (22:00 +0000)
commit 84cd8df5775fa8349c05f6ed81de752931d8ac31
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 20 06:34:01 2009 +0000

    Provided a bit cleaner solution to adjust scheduler rate (if needed).

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

commit 2a83967881043cc98f097eb7e3680fc0424811c7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 19 19:00:47 2009 +0000

    Introduced an option to run mpf scheduler n (rate) times faster that real-time.

    By default everything remains as is. This option aims to workaround a particular issue. Do not use this option, unless you know what you're doing.

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

commit adb09a70e3c5c8b4df1284419d8d38613079cacf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 19 18:16:06 2009 +0000

    Added an engine for recorder resource in default config, which I forgot to do before

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

commit 7f450dd3a0f38ea22ec26a700ab494256f669657
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 18 18:16:03 2009 +0000

    Implemented RTCP receiving procedure, made other RTCP related enhancements

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

commit c2a5dc114f639eebff0e8a2583105d51311fd743
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 18 17:59:52 2009 +0000

    Fixed timers (nodes of the list) to be properly sorted by scheduled to elapse time

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

commit 47d6df92a8c76567a80667f1a556f930cf9718d4
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 18 17:50:07 2009 +0000

    Set one-8kHz.pcm instead of old one.pcm as default input for asrclient application

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

commit 1ac5e6c2677bdf0da009c0bd729ea9ce3c265b18
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 17 20:11:32 2009 +0000

    Loading RTCP related settings from config files (unimrcpclient.xml and unimrcpserver.xml respectively)

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

commit 9587d418d1e528d7b590280aef25dc89441d55cf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 17 20:09:28 2009 +0000

    Added policies for RTCP BYE transmission and
    also added optional reason string generation

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

commit 707c89631ea5f03bb0944fa14acde98abc942cc0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 17 13:18:36 2009 +0000

    Added more checking not to crash on wild pointers passed from user space

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

commit 8b447a59c3939a1ca8bb78da7ca18dcea2680e92
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 16 16:12:19 2009 +0000

    Properly tracking the state of RTP/RTCP session to send compound RTCP BYE message when needed.
    Using local and remote sockaddr in traces.

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

commit ec172c46622e9b9d332caef9989358453669a3c8
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 14 21:24:08 2009 +0000

    Filled fields of RTCP RR report

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

commit 8dc2333148cfda12658a1b6d0eaf4521a15173bf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 14 18:39:05 2009 +0000

    MPF timer related fixes and enhancements

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

commit 3e63923d6d1e5962205e4abba5e6e5b8a364bb68
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 14 16:29:54 2009 +0000

    Added debug trace to indicate waiting for new messages state

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

commit 9a7937cb5cf2ed669bc193ded4cd389282b42230
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 13 20:37:39 2009 +0000

    Sending first RTCP reports

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

commit ebe5ccbdb032edfb8a45cbdd29cc4271b72b1b8f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 13 20:36:23 2009 +0000

    Added an utility function to get current NTP time

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

commit 4421f92ed549842252616802ce46e2bc3716652c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 13 18:17:02 2009 +0000

    Fixed RTCP packet fields and alignments

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

commit 28ec22508d517720a52c5a98a5cdb252df604363
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 20:17:05 2009 +0000

    Set RTCP transmission timer if RTCP is enabled

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

commit a7d91738c0d024600050ebc3955642f955eb6aeb
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 18:56:33 2009 +0000

    Made timer manager available for media terminations

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

commit 4940bee339c41206af57ff2b623f8211a4c11c07
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 18:50:32 2009 +0000

    Do not destroy audio streams while destroying media context, which still contains terminations. Instead just subtract terminations.

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

commit a24d8e814e4fe8d587b87c7a0103e3ecc8cabb6b
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 18:41:00 2009 +0000

    Added timer manager (missing from prev commit)

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

commit bc132cbae6e761630960797234ffc76bfcd76897
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 18:38:44 2009 +0000

    Reworked timer/clock related entities.

    mpf_scheduler provides clock for media processing and timers
    mpf_engine uses media processing clock as it was before
    mpf_timer_manager uses timer clock to provide timers management routine (set/kill/elapse) for mpf layer

    mpf_timers can be used only from the context of mpf_scheduler thread (context, streams, callbacks)

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

commit f7765d18eeabb7f3d61c51f78c47f1a2667405fc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 14:59:13 2009 +0000

    Removed array of multimedia timers, only one of them is actually used.

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

commit 5997acf00aebc18c78294e574d3614fcbc794ac4
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 12 14:56:34 2009 +0000

    Basically implemented RTCP session scheduler

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

commit 9ab5014493a35e1f8f8ba34031e8a884c06afc4c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 11 21:19:04 2009 +0000

    Added new methods to mpf_termination interface such as add() and subtract(). These methods are called when termination is added and subtracted from mpf_context

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

commit 6b7a388da519acbbc6ecec4ead0e381c63346402
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 11 19:18:59 2009 +0000

    Separated mpf_termination and mpf_termination_factory in order to hide mpf_termination in mpf layer and not to expose it to user space.

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

commit 2148e6a7bfd42f9c9b662a2a107349476d2a4fa1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 11 18:11:20 2009 +0000

    Implemented creation of socket pair (RTP/RTCP).

    RTCP socket is created next to RTP. It's reasonable to create RTCP socket even in case RTCP isn't used to avoid sending ICMP packets to remote peer.

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

commit c48e8e1f286ba5e433c7a961587ced8039cde3fd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 11 05:10:03 2009 +0000

    Fixed compilation

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

commit 99e186b3d4e7e74da4cdbfebf141b13e611d7d1c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 10 20:30:16 2009 +0000

    Added RTCP related params to rtp_config (yet to be loaded from config file)

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

commit f43ef8c5c9a8d168b38784b5a2f95df8aa9af932
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 10 20:21:52 2009 +0000

    Added skeleton for RTCP session scheduler

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

commit c7359c5e3fe1f577a18e9dd9321865697da064cc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 10 18:39:55 2009 +0000

    Added RTCP packet

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

commit d013ea92461e21803803707d171c63b8f163dee8
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 10 18:32:40 2009 +0000

    Fixed minor typos in comments

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

commit 1b1f313769f1375eb3eeea8c1378463a226182fa
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 21:56:33 2009 +0000

    Set jitter and ssrc of rr_stat.

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

commit a09883271b921d5ff649b66af65b91f0aab8aeaf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 21:29:21 2009 +0000

    Calculated not only number of packets sent, but also octets (payload bytes) sent.

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

commit de157f9cf11eae33485e820cf6d32aee0a4ce739
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 20:52:38 2009 +0000

    Fixed typo in file name (rtpc -> rtcp)

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

commit c4363f25417e045fa56ef05ee5a1ef27c847a02d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 20:48:41 2009 +0000

    Added RTCP header and stats used in SR and RR reports

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

commit f8a10bb46185567c68fd9785cd351f3931519d2e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 17:23:26 2009 +0000

    Reset frame type and marker before read_frame() in decoder

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

commit a8ac67a6ee566b0b3535a4cb4ea98ca18021c077
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 16:03:45 2009 +0000

    Fixed simultaneous transmission of named events and regular audio stream

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

commit b8fb271257862c817eae069dc65093eebdcb9ff6
Author: tomas.valenta@speechtech.cz <tomas.valenta@speechtech.cz@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 9 00:18:41 2009 +0000

    DTMF generator now fully supports out-of-band digits, including long-lasting events.
    DTMF detector now fully supports both in-band and out-of-band digits.
    To do: Simultaneous in-band and out-of-band transfer (at generator side) and events' ptime support (currently CODEC_FRAME_TIME_BASE=10ms used).

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

commit df38c3338ddb51eedb0640a3e14c435258876115
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Nov 8 20:31:18 2009 +0000

    Defined RTP_TRACE and JB_TRACE as null_trace by default

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

commit 1b94caa54c41fb3c4cafe7f752888d96f9fbcd79
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Nov 8 20:19:43 2009 +0000

    Added JB_TRACE define

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

commit 555e2c6a9340f9cf8640abd69a37a26f3a2d17ab
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Nov 8 19:39:24 2009 +0000

    Added RTP_TRACE define

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

commit 40bc2080211e33eefc25b183e124a6c694043c90
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Nov 8 13:37:41 2009 +0000

    Do not restart rx routine if failure threshold fired on processing of named events.

    Usually these are minor errors, which can be safely ignored. Unfortunately there are still many broken implementations out in the field.

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

commit 9b7bd4b4937a1546052c26ba957f5075b6d8c9b1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 7 21:40:30 2009 +0000

    Although host/net order of named events duration was effectively handled in mpf generator, this field as well as others should in host order for user level, including
    dtmf generator and detector entities.

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

commit 3a48e36216d03459e258e4f78d314a7e12d4c4cd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 7 21:29:17 2009 +0000

    Added traces to show how to trigger start and end of named events.

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

commit 7e88afd669e77a45a175f88e09b8d68069d189bf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 7 21:17:40 2009 +0000

    Fixed processing of named events in jitter buffer

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

commit f547a0454c79e387536da276ef9dbde24ff09210
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 7 19:10:12 2009 +0000

    Reset, copy frame->marker where required

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

commit a3aa75dd7aa0128c19cdaa10d87eed0f5f7d116c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Nov 7 18:36:01 2009 +0000

    Set event descriptor based on capabilities and offer/answer

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

commit 7ee88a44a398ef9a7a9847277bd96ea7a4db5f16
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 6 20:55:57 2009 +0000

    Writing named events to jitter buffer (detection of new events, tracking of event updates, ...)

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

commit 0a0099e1b7f90b288dabfcd694e8dea0f5b5b609
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 6 18:21:42 2009 +0000

    Added sample DTMF recognizer scenario/session

    Update your umcscenarios.xml file and use 'run dtmf' from umc console

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

commit 40bfd9392b819708312effc60833fe5bf09f0418
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Nov 6 05:42:27 2009 +0000

    Added missing -lm to resolve undefined reference to 'sin' and 'cos' used from mpf_detector and mpf_generator

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

commit f6b4d75156532f6e6e8441021c3d59f4c2658634
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 5 20:57:54 2009 +0000

    Fixed compilation under gcc (redefinition of typedef struct)

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

commit 7b72a080f717628ba7a7197eef79be1adcb8ad6a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 5 18:58:42 2009 +0000

    Fixed host/net order routine for named events.

    User level is in host order.

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

commit ba65dbed0e994dce789de726921d84e5c8af19bf
Author: tomas.valenta@speechtech.cz <tomas.valenta@speechtech.cz@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 5 18:58:24 2009 +0000

    Added DTMF generator and detector into MPF.
    Currently just in-band (audio) digits only are fully supported. The generated tone length is currently limited to 0xFFFF RTP time units (approx 8 s@8 kHz); will be enhanced.
    Out-of-band generator might work, but is not complete. Out-of-band detector is not implemented yet.

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

commit e84cf0107550fe0b5df025b365bff537a3c43461
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 5 16:10:46 2009 +0000

    Set resource id if resource indeed created

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

commit f074ded9633a148305f8182ea353e583fa549e43
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Nov 5 14:15:08 2009 +0000

    Set named events in jitter buffer

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

commit a86daebb9db0b1ccd5b1400fa65b2d95e674a8c6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 4 22:02:33 2009 +0000

    Properly set timestamp on event packets. All the markers should be set from user level to make it work correctly.

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

commit 52a71c40fa19ee2210923cf1d3893b4da53054fb
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 4 21:58:24 2009 +0000

    Added new marker which indicates start of new segment in case of long-lasting events in order to properly set timestamp on event packets

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

commit a7bf0a924f924798032d65cf0c2484bab86ad6ff
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 4 19:31:41 2009 +0000

    Added frame marker which indicates either start or end of event, more markers might be added in the future

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

commit 433e5c94a0e3ee1bc39bd113bc8e0af2832df950
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Nov 4 19:09:28 2009 +0000

    Supported simultaneous transmission of events and audio data, if/when needed.

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

commit 5b9acde2754550eab6cfae7f189dfcf762166a3f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 3 19:20:06 2009 +0000

    Set Max-time and Final-silence header fields in umc record session

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

commit 25b0c6ebc7faadd3d8d15bae603d428189ee0df1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 3 19:17:20 2009 +0000

    Supported a few more header fields such as Max-time, Final-silence also set Record-URI header filed in response to STOP request or RECORD-COMPLETE event

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

commit 56d14eebe0d57d7a4eeec68e7e74075ddabd19d2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Nov 3 17:17:36 2009 +0000

    Split complete_timeout into two parts: speech (activity detection) timeout and silence (inactivity detection) timeout

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

commit f62b8529a3e174be452dca631ca94f27011cba05
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 2 21:09:48 2009 +0000

    Added recorder scenario/session to umc application framework.

    To launch basic recorder session, update your umscenarios.xml file and use "run rec" command

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

commit 3d1707440b7ce386a35802f724549212238e5126
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 2 21:02:33 2009 +0000

    Integrated recorder plugin into GNU build

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

commit 2e0071e66003ff4d73dc8e44a83000884f79af40
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 2 20:53:08 2009 +0000

    Added mrcprecorder to the solution

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

commit 965bf199a93ac7b79d7e94de8a25a5c55fa18b8d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 2 20:44:19 2009 +0000

    Initially added implementation of recorder engine (plugin)

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

commit 5e3e1dbca93ecc37593a4c8a091a4b039a97450d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Nov 2 17:48:46 2009 +0000

    Added state machine for recorder resource

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

commit 0ad71ee97050e33da4f39803de1132dcb7d95e48
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 19:06:01 2009 +0000

    Fixed core dump with large in-line grammars (Issue-52, Thanks Asackheim)

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

commit 089756fca925b818ade79e1b009612aed8af3f36
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 19:00:38 2009 +0000

    Added a few more checkings

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

commit 60e20ca963baded1e1e9e8135030d0fd6085cf83
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 14:49:23 2009 +0000

    Added missing #include <ctype.h> to compile under gcc

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

commit 7a1a5eeff14b80a795fd03f164bb03d40e586d2b
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 14:48:09 2009 +0000

    Fixed function prototypes to compile without warnings with -Wstrict-prototypes gcc option

    As John stated, int foo() is not the same as int foo(void). This is true for pure C, meantime in C++ int foo() and int foo(void) are just the same prototypes.

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

commit 744d6dc495b072f175f38ccbee4b415b88c95239
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 14:35:15 2009 +0000

    Properly processed nua's shutdown (Thanks John)

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

commit 8000fb6d6e7503b87c8046c9bb65c56b61137f08
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 27 14:27:02 2009 +0000

    Initialized codec manager a bit later with media engine.

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

commit 036cc125672f2a05cc9847436f967778d3dd8831
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 26 17:44:48 2009 +0000

    Loading MRCP resources from config.

    Resources MUST be loaded first, update your unimrcpclient.xml and unimrcpserver.xml files according
      <!-- MRCP resources -->
      <resources>
        <resource class="speechsynth" enable="1"/>
        <resource class="speechrecog" enable="1"/>
        <resource class="recorder" enable="1"/>
      </resources>

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

commit 0788e08c0a17bd2974cf75d6a0459ee4d6e947f6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 26 17:12:57 2009 +0000

    Do not initialize profile if no resource factory registered

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

commit e8cc3b89b8de07a4f7a480560616b6912059a082
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 26 14:04:31 2009 +0000

    Fixed @brief description

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

commit aed93bacf17e27f2507209a22382d700dc9d17a9
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 25 19:26:22 2009 +0000

    Separated MRCP start-line related routine

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

commit 3c71e09c365a2e252a3ce64bebffa8cfafe6081c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 25 19:06:54 2009 +0000

    Stored mrcp_resource instead of mrcp_resource_id in mrcp_message.

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

commit 90822e0d43710cdef2caf8f3761a56c333a6f9fa
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 24 15:28:44 2009 +0000

    Initialized resource for channel at earlier stage to remove no more required resource_id channel member

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

commit 1b42089957ee75a0da7f78fca442c94b1a88fde9
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 24 14:39:47 2009 +0000

    Moved resource loader to "control" folder to leave "resources" folder exclusively for resources.

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

commit 76940502830e53c99ed4f7e92e12382a973bef61
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 24 14:29:17 2009 +0000

    Arranged resource, resource factory and resource loader entities in a bit more clever way.

    Both resource name and identifier are properties of resource.

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

commit b97b51d0300668cb821b62124ab1a724b29cdbb4
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 23 18:20:10 2009 +0000

    Replaced mrcp_default_factory with mrcp_resource_loader

    Resource loader soon will be able to load resources based on configuration.

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

commit 6e8ca2e820b6282b46169935272eb10229a7ef71
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 23 15:46:08 2009 +0000

    Applied temporarily workaround to send a named event as soon as it's received regardless what the actual packetization time is (Thanks Randy)

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

commit 7fc090163d5b5eda6e12e302b4bde2729ac4cc05
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 23 13:24:53 2009 +0000

    Initialized recorder resource on start-up by default (should be configurable)

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

commit 9f66366c68461fbe2c7edfe3cd15fdf213c76f79
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 22 18:46:28 2009 +0000

    Added methods and events for MRCP recorder resource

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

commit ce024776e6f03ec578cfae108cf53aab9ec1b086
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 22 18:07:16 2009 +0000

    Hopefully finally fixed RTSP/MRCPv1 session management related issues, when multiple resources are offered using consecutive RTSP SETUP requests containing no SDP.

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

commit a72740ffe0169e87fe7a33e8403ccc61a7e5ad38
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 22 14:53:06 2009 +0000

    Added a few accessors to mrcp_application interface in order to completely hide session interface from the application context.

    Session pointer SHOULD be used as an opaque pointer from now on.

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

commit 78c223cc46fedc0a8f5a76492aea7f76049cf23f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Oct 21 20:41:49 2009 +0000

    Initially added MRCP recorder resource header

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

commit ea6b4a05b836b072cad4f2b17c312a31a516350e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Oct 21 16:19:59 2009 +0000

    Enhanced apt_task to be able to raise late start-complete event when task is not just started, but also ready to process messages.

    Some tasks are implicitly ready to process messages. The others still initialize some additional data. Thus, they should explicitly indicate ready state.
    As a result on_ready event will be raised to application context when it was intended to be raised. (Issue-49)

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

commit fecf6decb056e0b7232622abbf0240b230f4332f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 20:19:01 2009 +0000

    Better representation of abstract MRCP resource

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

commit 813442c8b6b3d2fc202e58ea9189e2e62e4232d2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 17:22:56 2009 +0000

    Updated project files according

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

commit 1bc8a5b581b78a5c31f5e2ea594e87725be9b513
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 17:13:57 2009 +0000

    Moved files as well

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

commit 3e0bd386532d66ec7d63030910b4fa62012eeb6d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 17:08:40 2009 +0000

    Moved server side state machine creation from shared between client and server stacks mrcp_resource to mrcp_engine

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

commit 07ce822cefd70b8696393ba1681179926168cb87
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 16:30:08 2009 +0000

    Renamed server_state_machine to state_machine.

    No functional changes.

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

commit 738e0b5a319f3e3c5968ffc4bc1ea649e63031c8
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 20 16:24:07 2009 +0000

    Removed client_state_machine, which was actually not implemented and unused. Renamed server_state_machine to state_machine.

    No functional changes.

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

commit 0f576df4b9a39f6e4ffaec76056e0d45e59dbaa6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 19 18:46:57 2009 +0000

    Fixed compilation under gcc

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

commit a1ef30ee7037f61ba8454e3447b675ebeb8a0d39
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 19 18:18:26 2009 +0000

    Added compile time define to support "too long" MRCP request identifiers.

    MRCPv2 specifies request-id as 32bit unsigned integer, while MRCPv1 doesn't limit this value.
    Some MRCPv1 clients use too long request-id. To support them #define TOO_LONG_MRCP_REQUEST_ID
    (Issue-48)

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

commit 8e560595461249c0924523f43a0a02a2f3106afe
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 18 17:54:05 2009 +0000

    Increased unimrcp version number

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

commit adbef71d8a6017c654fc3bc970120da81ea1d8e0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 18 17:52:55 2009 +0000

    Increased plugin version number

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

commit d19a7550d924d9482996641e7d7d617c9082c72e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 18 17:52:10 2009 +0000

    Clarified a bit plugin implementation rules

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

commit 0456d9b69f89b82b4487acb91574380eaa88b282
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 18 15:51:33 2009 +0000

    Fixed doxygen warnings

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

commit ba29c377eda8bdc3212c49c3f217d50ba98da2d8
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 18 10:34:45 2009 +0000

    Updated the INSTALL to strengthen requirement for the dependency package.

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

commit 598434417a61d48072dad7f5e52dd7d1aabcd802
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 17 17:39:54 2009 +0000

    Added Chaitanya and Vali to the contributors list

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

commit f3de0b40955ed4386e21a480e158f1557a957bdc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 16 15:04:25 2009 +0000

    Fixed header inheritance routine in order to not override fields which exist in original header (Issue-47)

    Broken since r846

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

commit 0a9d6f344d456f283d2ab9dfd112961908fcce39
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 15 15:43:17 2009 +0000

    Do not accept any messages after final TEARDOWN (session is being terminated)

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

commit 0e04171d7f00a02901b8f793288e0cdd9778e0f2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 15 15:09:04 2009 +0000

    Return JB_DISCARD_TOO_EARLY if buffer is full

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

commit cd0cd0c0f89988a841db4947c79bc584591db2fd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Oct 14 15:56:47 2009 +0000

    Spelled 'discovery'

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

commit c8ee0ead88dd52dd08d4eeab8048ad8263a55a88
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 13 18:37:43 2009 +0000

    Fixed RTPS server stack processing in case there are more than one resource in the scope of the same RTSP session

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

commit d325c4d5fa1a7b96bb47111147dde1804890d4c4
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 13 18:34:03 2009 +0000

    Set resource name for RTPS ANNOUNCE events

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

commit 6d418aa8bc5e21cd32394fecb92fc949befc56cd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Oct 13 06:09:36 2009 +0000

    Checked the return value of MrcpSessionCreate()

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

commit 7a6396943262fe550f49f8040217d4f26d39c70f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 12 18:37:17 2009 +0000

    Added convenient headers, which should be included from synth and recog plugins

    mrcp_synth_engine.h
    mrcp_recog_engine.h

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

commit d16295aee7c3518a0523de15ced333918f6feb08
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 12 18:14:10 2009 +0000

    Made changes in plugins proposed earlier (resource_engine -> engine)

    Nothing has to be done.

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

commit 27fdce12cb98e49bd61a58c93b113740d2aae1c2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 12 15:20:34 2009 +0000

    added svn props

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

commit 354b415531d0605292d8e861590ef536803a849c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 12 13:21:40 2009 +0000

    Added support for grammars supplied inline within RECOGNIZE request in PocketSphinx plugin

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

commit 9b3889df631dfa896a84d05c3eed876d87a43f9f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 12 13:19:35 2009 +0000

    Enhanced recog session/scenario to be able to supply inline grammar within RECOGNIZE request, instead of preceding DEFINE-GRAMMAR one.

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

commit 5be3d2ae0ca3ec58888bd76d46315e22671f87b3
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 11 17:19:25 2009 +0000

    Added new attribute for recog scenario to optionally specify audio source instead of default hard coded one.pcm.

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

commit 1c4e5829cf2657df49c7a98e6732c1c980fef981
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 11 15:31:38 2009 +0000

    Added a couple of new umc console commands to show running sessions and available scenarios.

    > show sessions
    > show scenarios

    It was already possible to run new session and kill it

    > run synth
    [1]

    > kill 1

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

commit 4c59fe99e7d30359f416a1544c0ee84fc6784ee2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 11 08:23:48 2009 +0000

    Fixed another potential crash of client stack (leftover from previous fix).

    Pending session termination request should not be canceled even if termination event is received.

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

commit b966e80ea53795344c4e5c1472d3173ff71765d6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 19:17:53 2009 +0000

    Install *.jsgf and *.txt as well

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

commit fb12c7c19144fced8fa684f60bd3308e7099afb7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 19:06:24 2009 +0000

    Added sample JSGF grammar and plain text contents

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

commit 5c13e452e75c506436c6327e600f11b460e61ec3
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 18:57:29 2009 +0000

    Added umcscenarios.xml

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

commit fe2d1fa156764eb0f6001b5a6d0f21cc3f99df31
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 18:16:16 2009 +0000

    Added missing stdlib.h include

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

commit c511584c906303db3eb5607dc94aae91c1fc307f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 18:12:00 2009 +0000

    Loading the attributes of predefined scenarios such as content-type, content-location, capabilities from config file.

    Predefined scenarios (Synthesizer, Recognizer) are also a bit enhanced, they are more customizable now...

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

commit b2160f787f7695bc5128137309793ba5c4913da1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Oct 10 14:18:11 2009 +0000

    Fixed return value, which should be int for bitmasks

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

commit 536460af46efc3389db9e40e584fa0331d278730
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Oct 7 13:14:47 2009 +0000

    Do not just return, but close file descriptor if config file is not a valid XML

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

commit f2f7452654a5449fc99ea5c28435fcdff651fef2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 5 17:56:42 2009 +0000

    Added umc project into the solution

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

commit 727c402ca49c98bad25e408296cf268256f3a5d1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Oct 5 17:52:07 2009 +0000

    Added umc application into GNU build

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

commit baa849da05ab3f52612ae17ea91b89ba5def954e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Oct 4 20:58:45 2009 +0000

    Added another application (umc) built on top of libunimrcpclient.

    This application will eventually replace demo unimrcpclient ...

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

commit e962a729e315cf54051d5b2eb5abbe0c6d72d4bc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 2 18:34:42 2009 +0000

    Fixed plugin_version_hdr in configure.ac (Thanks, John)

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

commit cd46e9c59102734fa2c64097857b86a94403f6e0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 2 15:24:23 2009 +0000

    Fixed APR_ARRAY_IDX related issue in apt_pair (Thanks, Anthony)

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

commit a7cc93a58d189ec805f55360c5cc7d6578566050
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Oct 2 07:45:19 2009 +0000

    Implicitly modify initial offer (RTSP/MRCPv1), if it contains disabled media stream.

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

commit cc135ce9547c5caf09238b552d53085b4443b8bc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Oct 1 04:06:18 2009 +0000

    Added a user level function to associate (de-associate) external object with the session

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

commit 5364deb02ce21e10f3a8a0f13ab78473022c5248
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 30 18:24:33 2009 +0000

    Fixed crash of client stack caused by race condition on session termination.

    Most probably this fixes the issue reported on the discussion group recently and Issue-33.

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

commit 8c6b3def701b3e4b04b7cec344d6c83e6b147733
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Sep 29 15:54:02 2009 +0000

    Enhanced "prepare" utility project to install the whole apr-iconv stuff including iconv/*.so, if apr-iconv library exists. (Issue-45)

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

commit 1a26706b602aa5aef4eb77e60656600e0efab22c
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 28 18:38:47 2009 +0000

    Fixed C++ compile error in codec_descriptor.h (Issue-44, Thanks Vali)

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

commit 980551739dae22c9219d2987958d44ba65072cf1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 28 18:32:22 2009 +0000

    Added media path traces for mixer and multiplier. Fixed initialization of source and sink streams in them.

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

commit 4d0d245f3ad93e62b64d549df4a3edfa00607eba
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 28 10:01:23 2009 +0000

    Added an example on how to specify 16Kz codecs in config

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

commit edd7d550cd0c69b7e71863fe82f825a80d75348a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 28 04:51:02 2009 +0000

    Added to project file

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

commit 56866f06009823a8a682535d12a516295e627be9
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Sep 27 18:41:54 2009 +0000

    Using MRCP_PLUGIN_VERSION_DECLARE macro for existing plugins.

    Version info is a property of the plugin but not the engine as it was before.

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

commit 0f33b7d3a61ee9bb2815b54e0a6f7473acd42f2d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Sep 27 18:37:08 2009 +0000

    Separated user interface (what MRCP server uses) and implementation (what plugins implement) of MRCP engines.

    There are a few changes plugin implementors must be aware of
    - Plugin version number must be declared in each plugin, preferably using MRCP_PLUGIN_VERSION_DECLARE macro
    - MRCP engine is renamed from mrcp_resource_engine_t to mrcp_engine_t (legacy typedef remains)
    - Instead of mrcp_resource_engine.h consider using mrcp_engine_impl.h (legacy header remains)

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

commit b10833cf2bc46e7c306fdbf27493d95b86136258
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Sep 27 09:55:54 2009 +0000

    Added missing #include stdlib.h (GNU compilation)

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

commit 1601da5d00e1d04ae284578937a6d7f07df75829
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Sep 27 09:53:04 2009 +0000

    Moved, separated functionality related to loading of plugins into corresponding header and source files

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

commit 860768fabdd91b8c50ccdbbe882455bf120d59bf
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Sep 27 09:01:27 2009 +0000

    Moved, separated functionality related to factory of MRCP engines into corresponding header and source files

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

commit 065cb1e9a449a6692f3cc023dee14f60c8612800
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 26 07:28:47 2009 +0000

    Finally applied changes to the Cepstral plugin either.

    Scan available voices and indicate stream capabilities upon channel creation and use decided codec descriptor on channel open

    Better comply with engine create/destroy open/close routine

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

commit 7d61bdeba92adcfed677619b7c92a203a8c4d94a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Sep 25 16:10:18 2009 +0000

    Finally applied changes to the plugins.

    Indicate stream capabilities upon channel creation and use decided codec descriptor on channel open

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

commit 64aaee0d070a5589aa3ec162586acd78d023b343
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Sep 25 15:24:01 2009 +0000

    Modified processing of offer.

    1. Receive offer
    2. Create control channels and media terminations indicating their capabilities
    3. Build media topology and media path (all the descriptors are initialized at this stage)
    4. Only then open control channels
    5. Send answer

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

commit 5a35d4c20ce3f67c8cd2a6ed1440817c6d5a1f1f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Sep 25 14:31:39 2009 +0000

    Added is_open member to mrcp_engine_channel_t

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

commit ff764c523b9a60bb6de243e928d1a399f2ed7e6a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Sep 25 14:10:01 2009 +0000

    Building RTP termination capabilities according to associated media termination(s)

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

commit 6b85a37e65c2600e317440d539968a794b2212f5
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 24 21:06:54 2009 +0000

    Updated demo speech file naming convention (demo-8kHz and demo-16kHz)

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

commit da1d688fac7022152ea5962fa36420a9f6e049a6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 24 20:50:27 2009 +0000

    Added/renamed 8 kHz and 16 kHz speech to be used from demos

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

commit c54d354c1de2a273b2e5c4eeb83c75d893a4cbe5
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 24 19:55:12 2009 +0000

    Added new function to the client API to create media termination (audio stream) based on specified capabilities.
    mrcp_application_audio_termination_create()

    Marked the following functions as deprecated (they still remain functional though)
    mrcp_application_source_termination_create()
    mrcp_application_sink_termination_create()

    Upgraded demo synth and recog applications according

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

commit a8de40f600fe129b6367af435c47e80a3f1d52d6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 24 19:10:02 2009 +0000

    Added new function for the plugins to create media termination (audio stream) based on specified capabilities.
    mrcp_engine_audio_termination_create()

    Marked the following functions as deprecated (they still remain functional though)
    mrcp_engine_source_channel_create()
    mrcp_engine_sink_channel_create()

    Upgraded Flite plugin according

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

commit a2f6fbc628717b4f927eed5fbda64dd47027bc9b
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 23 16:59:32 2009 +0000

    Dropped any further requests from application if session is being terminated.

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

commit d27e77a39c48baa110bb96524e170ff2a6419bbc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 23 15:15:50 2009 +0000

    Modified includes to #include what is actually needed

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

commit ede4c291d16d5fe8783e3300b2eda71137fb095a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 23 14:51:44 2009 +0000

    Reviewed mpf_codec_t and mpf_stream_t entities and relationship between them.

    Codec as a manipulator (encode,decode,dissect) is not a property of stream. Stream holds capabilities and active codec descriptor(s). Actual codecs (PCMU, PCMA, L16) are registered at startup and passed to encoder and decoder objects when/where needed.
    Linear PCM (LPCM, but not L16) is just an internal descriptor, it's not a codec.

    Everything should work as is basis. The only user level interface change is in stream_open() method, which is optional and probably is not actually used. See demos for more info.

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

commit 502ed670a75f8a94c017fbd3525bbeb928d72ac9
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Sep 22 16:55:40 2009 +0000

    Considered own capabilities while building local descriptor (codec list), added more utility functions

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

commit 9cc077274f2333a8c1c2ed01d28d396c0ba95992
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 21 15:38:56 2009 +0000

    Further enhanced stream, codec capabilities and descriptors.
    Finally those capabilities will participate in offer/answer, a few steps remain.

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

commit 9ddb49bd1a1dc51c4510abee8f1a092a6bce5dab
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 19 11:53:16 2009 +0000

    Using APR_ARRAY_IDX and APR_ARRAY_PUSH convenient macros to operate on APR arrays.

    These macros are more safe and intuitive. Unfortunately they have been added only in APR-1.3. If you still use earlier APR-1.2.x versions, consider to backport those macros, please.

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

commit c38a54eb3b65b45e8d5265144864b6419dc4824d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 17 16:57:49 2009 +0000

    Renamed mpf_stream_mode_e to mpf_stream_direction_e (send,receive or duplex), moved mpf_stream_capabilities_t to mpf_stream_descriptor.h

    Nothing has to be done, unless you explicitly construct and use mpf_stream_mode_e in your apps.

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

commit 28ca2617a6f85face3e7eb7a2fbe3d300b9199c6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 17 16:44:53 2009 +0000

    Fixed last commit

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

commit 450154c862b567f8b24b30e0662ad16eda6f9855
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 17 16:25:25 2009 +0000

    Minor fix in format of vcproj version 8,00 -> 8.00

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

commit 1cf803d3696d62523f6084c4ac88a528c0bd9eaa
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 16 20:59:41 2009 +0000

    Destroy resource engines on server destroy

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

commit b08782eb2d6a4a87a0a70dc7d276957dab906223
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 16 20:40:17 2009 +0000

    Added is_open state to resource engines (Issue-42)

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

commit df037667c94449091144f36347bbb4c6dbdc1168
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 16 16:15:36 2009 +0000

    Unregister plugins at later stage from mrcp_server_destroy().
    It makes no difference for now, but from conceptual view point, it should be possible to create server once, start/stop it multiple times if needed and finally destroy it once.

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

commit 1336d1b985329b32fca0c8127f3c3bd4785f9412
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 16 13:10:50 2009 +0000

    Reset existing associations and topology (if any), while processing answer from server (re-Invites).

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

commit d83f12e3262f156bb10bb55ab5bf9407afb110b2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 14 19:12:42 2009 +0000

    Fixed spelling: transmit -> transmitter, receive -> receiver

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

commit 67894e96a9c8b5db7652c8a2a34b5eecd88aa1d7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Sep 14 17:11:03 2009 +0000

    Added media path traces
    Examples:
    Source->[PCMU/8000/1]->Decoder->[LPCM/8000/1]->Bridge->[LPCM/8000/1]->Sink
    Source->[LPCM/8000/1]->Bridge->[LPCM/8000/1]->Encoder->[PCMU/8000/1]->Sink

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

commit 35cd98bce0d462c10dfbc8beb5369e12f3de55a3
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 12 17:58:23 2009 +0000

    Merged mpf_media_descriptor with mpf_rtp_media_descriptor (no need in separate base descriptor)

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

commit 689df477413bef09cda1fc2f0ba6c14f6378e088
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 12 17:05:31 2009 +0000

    Using apr types (short -> apr_int16_t)

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

commit c578f6ea274229afee64a4aa6faf0b0610049153
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 12 16:50:10 2009 +0000

    Fixed compilation warnings under gcc

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

commit 8499d8cbc4cdadd07b60d72a5811e21b48da6f0f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Sep 12 16:16:08 2009 +0000

    Added MPF object derived new entities such as mixer (n-sources, 1-sink) and multiplier (1-source, n-sinks)

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

commit a957416aa7e536c5616d9c58725b82689bce58a0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 10 18:47:32 2009 +0000

    Added new line at the end of the file to fix compilation warning

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

commit 3fd96c529abd99b1a4b398481e72541448c48783
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 10 16:27:14 2009 +0000

    Encapsulated creation of encoder, decoder and resampler in mpf_bridge.

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

commit 4b169b670e95adec16741c2876d18f90a72fd95d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 10 16:05:25 2009 +0000

    Added skeleton for MPF resampler. Eventually external resampler should be integrated there.

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

commit aa8507f6c0982ae45cdba3f44fd52fcf7ad9e372
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 9 20:39:25 2009 +0000

    Removed unused function

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

commit 2e533dbc7a24c24e03a0e2810d78b3eaad13efb6
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 9 20:32:46 2009 +0000

    Supported multiple "cmid" attributes per each control m-line. (Section 4.3)
    Client API still allows to define only one to one association between control channels and their corresponding media terminations. Meantime server should be flexible enough even now and support any offered association among control channels and media terminations.

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

commit e8c77db43f8c6a39f912e2b60e594c753b2b3182
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 9 18:45:41 2009 +0000

    Fixed issue-41.
    Port number must be matched too, while trying to find an existing MRCPv2 connection (Thanks asackheim)

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

commit 3594fd3d2f5a3ba5ae91a885fb09b3d9322bbffd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 9 16:57:49 2009 +0000

    Fixed race condition issue in pocketsphinx plugin (Thanks Alban)

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

commit 202b654d75f5625bfdfd00adc61bb0fab000ab42
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Sep 8 15:51:58 2009 +0000

    Added define for TCP discard port used in offer/answer

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

commit a0d61fd4ea2b0e8c1899b1420fc24c1f2515afa7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Sep 8 13:56:51 2009 +0000

    Reworked MPF context, which allows to provide custom associations among the terminations involved in the context and build topology based on association matrix.
    Client and server stacks have been modified according. Everything should work as is basis

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

commit 54470cc5cdb35169409fe145c69046b3ad5a0c27
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Sep 8 13:50:01 2009 +0000

    Check if session->connection is a valid pointer first and only then use it

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

commit d33217a9227ea3ecb1b3e2e360b148ece5b6be0d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 3 19:23:10 2009 +0000

    Added more MPF commands to operate (add/modify/subtract) on terminations, add/remove associations between terminations and apply/destroy topology. More to come...

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

commit 19984cd1e5229910d9392588cba587895b05b50f
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Sep 3 17:01:10 2009 +0000

    Using apr_ring to store factory of media contexts.

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

commit 93c65ccde10d8eaa2eeec1b453c820af93b28ff2
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 2 18:43:31 2009 +0000

    Moved MPF context related public interface from mpf_user.h to mpf_engine.h

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

commit 99d7100026ba6867daf5486c29c514b0deaa2c75
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 2 14:59:15 2009 +0000

    Removed unused function

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

commit 6f21c53584b73e79ced6dbc695178a02611cce9d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Sep 2 13:20:14 2009 +0000

    Added ability to send more than one MPF messages at once.
    Grouping of MPF messages allows to reduce thread context switches, as a result, improves the performance.

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

commit b2a72d24996acf67b29b8aabfed3850da2b27ef7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 31 17:14:05 2009 +0000

    Updated Makefile

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

commit 18647d833d4df8991bee0b1a8255c7359502e8c7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 31 17:04:09 2009 +0000

    Added stream capabilities in order to set not only single codec descriptor, but capabilities of the stream (no API changes ... yet)

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

commit ac6fe620c6d0f45ad5f7f43e04db124f2e0db69b
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Aug 28 13:10:39 2009 +0000

    Added/moved negotiated rx/tx event descriptor to mpf_stream base next to rx/tx codecs

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

commit 481f01cefa540b3903aa6635b833bb6e894a300d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Aug 28 13:08:46 2009 +0000

    Name of the attribute should be bits_per_sample

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

commit e22100eeb324677d214c07a3ef91504fc6c106de
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 24 18:00:43 2009 +0000

    Added Makefile targets for pocketsphinx plugin to install dictionary and model. Do nothing if installed, but not source directory of pocketsphinx is used at ./configure time. In this case, dictionary and model have to be copied manually.

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

commit 3c680289d19481ae8e62009057ef7d639fd14a00
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 24 17:41:29 2009 +0000

    Fixed compilation warnings in pocketsphinx plugin, while compiling with enabled mainatainer mode

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

commit 5d6c7e26cc6a98f59da72676aae9fd1d0d17bb9b
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 24 15:15:44 2009 +0000

    Fixed prototype of on_start and on_terminate handlers in Flite plugin

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

commit 1d3044c8137ec39b3b7dcf65f8ec5e10718c7dd3
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Aug 18 16:41:06 2009 +0000

    Fixed trailing space in MRCPv2 response-line  (interoperability with Optimsys, Thanks Roger)

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

commit e835d5e8e51d19932a2e3e3f808ec987e2901de4
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Aug 18 13:26:50 2009 +0000

    Fixed possible access violation in APT logger (Issue-40, Thanks Vali)

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

commit 2e35e28c31d4a79025d105b00c73a9d66019d144
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 17 18:31:48 2009 +0000

    Added L16 and telephone-event to yet hard coded capabilities of the server included into the response to resource discovery request

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

commit 1fa878e171b528293528566f244c5142c051ac3a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 17 18:17:07 2009 +0000

    Fixed the response message sent to RTSP DESCRIBE request. It shouldn't contain RTSP Transport header, while RTSP Transport can be present only in RTSP SETUP request/response messages. This hopefully fixes interoperability with GVP (Issue-39, Thanks Vali).

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

commit 4e3d64c778fb3cc6a0a072d898f43b3c37e80eba
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Aug 16 06:49:54 2009 +0000

    Applied patch, which implements utility functions to transform DTMF characters and event identifiers (Thanks Vali)

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

commit 041580394f2ecdfe920cdb1e3d3d16ebceaecdbd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Aug 16 06:39:45 2009 +0000

    Applied patch, which basically implements RFC4733/RFC2833 sender procedure,
    yet to be enhanced, see Issue-31 (Thanks Chaitanya)

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

commit 947b49f9ff8e353d6bb5985f00db14942db971db
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sun Aug 16 06:28:22 2009 +0000

    Set negotiated payload type of named event for RTP transmit and receive

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

commit dc2687129335089a513127405e968b749197e002
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 15 17:47:13 2009 +0000

    Added "telephone-event/101/8000" to default client and server config

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

commit 178ba987d2f89ae5b9d6684be46814014fb3df2e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 15 17:36:24 2009 +0000

    Added generation of a=fmtp SDP media level attribute, which is optional for generic codecs, but is required for telephone-event (a=fmtp:100 0-15)

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

commit bfcc86e8e93fca16543e723a54132b74f3082216
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 15 16:38:46 2009 +0000

    Set SOATAG_AUDIO_AUX("telephone-event") in nua_respond to enable auxiliary codecs in response.

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

commit 1287b89a349dce746b9f11f927e31b3e52b4bd9a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 15 16:33:37 2009 +0000

    Integrated named events into offer/answer, made codec descriptors related minor enhancements

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

commit 98e9b1971e3b28fa3865ff77c3865c3e6d76d305
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 15 12:26:23 2009 +0000

    Moved matching of codec capabilities into separate function

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

commit e6f975d55fdd89d415548bcd63ba7756dcc93b8a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Aug 13 18:32:21 2009 +0000

    Added codec descriptor of named event into codec manager to load from config (done) and further to participate in offer/answer (yet to be done)

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

commit 6418912f7b96acce0e14feb474d106b8ac834cb8
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Aug 13 16:37:04 2009 +0000

    Moved named event definition into mpf_named_event.h, more stuff should be added there.

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

commit 9cc4da5d75f1fca118a5b962ee9e8c5d20c7a616
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Aug 11 18:21:02 2009 +0000

    Switched libasrclient into dll in order not to expose internal stuff to application context

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

commit 85480c95b03f727dbd11618fb42ae3ac907eddc0
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 10 07:59:54 2009 +0000

    Added plugin/engine config. The structure consists of
    - parameters which are common for all engines such as engine name and max channel count
    - table of transparent name/value string parameters, which are engine dependent

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

commit 5dfe8442ded69b773e83cb9c43b9197213ee5654
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 10 05:40:10 2009 +0000

    Initialized codec manager with 4 instead of 3 codecs to avoid later reallocations, as we actually have 4 codecs now

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

commit cb9d6d1406d4e5eb418c8a6de04eae004998a2f9
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 10 05:36:41 2009 +0000

    Fixed typo in comments (defualt -> default)

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

commit 00971c82e72adde2221fdbc204571a7c7a781e5a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Aug 5 07:57:20 2009 +0000

    Added ability to get MRCP version of the channel from plugin context in order to be able to construct MRCP version dependent responses and events when/if needed.

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

commit 328ebb30c8eb5124326bf5a43f4fa588877bea9d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Aug 5 05:45:31 2009 +0000

    Set RTSP transport "mode" attribute in the outgoing RTSP response if it's specified in the received RTSP request

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

commit c538367f46ef48cf157af53431ace47c6ac2be88
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Aug 5 05:42:32 2009 +0000

    Added another RTSP transport attribute (mode=)

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

commit a8a7ac5d7dc2845e1294d726fc8d651b9b749472
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Mon Aug 3 19:05:17 2009 +0000

    Added ability to limit max number of engine channels in use.

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

commit 43bdbd881e763c33e1cb6fff9ac88c91fe038d07
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 1 14:44:31 2009 +0000

    Added helper function to get session MRCP version

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

commit 7d53c0d31b12122a2ea4a200f3390ef0c78b392e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Sat Aug 1 12:54:34 2009 +0000

    Added enumeration of RTP payload types (RFC3551) project uses

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

commit 666f5657bf8bcd2f149119d07c725ff9599b2759
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Jul 30 13:39:11 2009 +0000

    Added svn props

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

commit 996b0d2489b377818290f7527080cbbfb8229bdc
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Jul 30 13:36:44 2009 +0000

    Updated GNU build

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

commit 53d8fe5f0fd4379c2ea626c861f9a031c9d88349
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Thu Jul 30 13:21:52 2009 +0000

    Separated libasrclient library from asrclient application to server as a reusable basic ASR block on top of UniMRCP client stack.

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

commit 8e6b678bd662127240546f95e8bf8c3a68033090
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Tue Jul 28 10:36:40 2009 +0000

    Added Michael Jerris (OS X build, FreeSWITCH build integration) and Carlos Pina Soares (RTP port management and several essential issue reports) to the project contributors

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

commit 25f0b60b56d7ed3ab11d1779615f2c2ba90dd686
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Jul 24 16:33:17 2009 +0000

    Included asrclient into GNU build

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

commit 316c3331b67a3504461bbf597ed3ff95c44bd053
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Jul 24 16:23:34 2009 +0000

    Introduced an alternate demo ASR client application
    usage:
      run [grammar_file] [audio_input_file] [profile_name]

    examples:
      run
      run grammar.xml one.pcm
      run grammar.xml one.pcm MRCPv1-Default

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

commit 04a3b14edb3e68743df4a4b22ca5445a54c79f9a
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 19:18:21 2009 +0000

    Increased unimrcp version number

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

commit d4b7ddc381ff0d2fb6831be473c84cd6c1da78ef
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 18:39:58 2009 +0000

    Fixed doxygen warnings

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

commit da304aa5485b2252a2826355c870108c52eac4bd
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 18:30:08 2009 +0000

    Fixed doxygen warnings

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

commit e6db110edb0a199298db5a0bdd08134543df40d7
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 18:23:34 2009 +0000

    Fixed doxygen warnings

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

commit 5b29de76a653423a02ec9329aec56429959d40c1
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 17:52:11 2009 +0000

    Updated INSTALL instructions

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

commit 8882ecf7b8dea6959d096edecb371c213294f25d
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 17:13:29 2009 +0000

    APR-Iconv is not included in dependency pack. Thus, first check if apr-iconv.dll exists and only then try to copy it.

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

commit 1997ed691507b5e0fdf58c3b22ce04c7a9c4fead
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Wed Jul 22 16:17:57 2009 +0000

    From now on use thread safe APR pools.

    Consider using the dependency package from http://code.google.com/p/unimrcp/downloads/list
    or manually apply patches over the libraries you use from
    http://www.unimrcp.org/dependencies

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

commit 5cbdaa7304b6146ff002191b7142885a18c8cf0e
Author: achaloyan <achaloyan@f001bc3a-424a-0410-80a0-a715b8f413a8>
Date:   Fri Jul 17 13:48:27 2009 +0000

    Raised unexpected MRCPv2 disconnect event from transport layer to client and server stacks (Issue-36)

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

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

245 files changed:
libs/unimrcp/AUTHORS
libs/unimrcp/INSTALL
libs/unimrcp/Makefile.am
libs/unimrcp/build/tools/prepare.vcproj
libs/unimrcp/build/uni_version.h
libs/unimrcp/build/vsprops/unimrcpserver.vsprops
libs/unimrcp/conf/umcscenarios.xml [new file with mode: 0644]
libs/unimrcp/conf/unimrcpclient.xml
libs/unimrcp/conf/unimrcpserver.xml
libs/unimrcp/configure.ac
libs/unimrcp/data/demo-16kHz.pcm [new file with mode: 0644]
libs/unimrcp/data/demo-8kHz.pcm [moved from libs/unimrcp/data/demo.pcm with 100% similarity]
libs/unimrcp/data/grammar.jsgf [new file with mode: 0644]
libs/unimrcp/data/one-16kHz.pcm [new file with mode: 0644]
libs/unimrcp/data/one-8kHz.pcm [moved from libs/unimrcp/data/one.pcm with 100% similarity]
libs/unimrcp/data/speak.txt [new file with mode: 0644]
libs/unimrcp/libs/apr-toolkit/include/apt_cyclic_queue.h
libs/unimrcp/libs/apr-toolkit/include/apt_log.h
libs/unimrcp/libs/apr-toolkit/include/apt_net.h
libs/unimrcp/libs/apr-toolkit/include/apt_nlsml_doc.h
libs/unimrcp/libs/apr-toolkit/include/apt_pool.h
libs/unimrcp/libs/apr-toolkit/include/apt_task.h
libs/unimrcp/libs/apr-toolkit/include/apt_test_suite.h
libs/unimrcp/libs/apr-toolkit/src/apt_consumer_task.c
libs/unimrcp/libs/apr-toolkit/src/apt_log.c
libs/unimrcp/libs/apr-toolkit/src/apt_net.c
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_pair.c
libs/unimrcp/libs/apr-toolkit/src/apt_pool.c
libs/unimrcp/libs/apr-toolkit/src/apt_task.c
libs/unimrcp/libs/mpf/Makefile.am
libs/unimrcp/libs/mpf/include/mpf_activity_detector.h
libs/unimrcp/libs/mpf/include/mpf_audio_file_descriptor.h
libs/unimrcp/libs/mpf/include/mpf_bridge.h
libs/unimrcp/libs/mpf/include/mpf_codec.h
libs/unimrcp/libs/mpf/include/mpf_codec_descriptor.h
libs/unimrcp/libs/mpf/include/mpf_codec_manager.h
libs/unimrcp/libs/mpf/include/mpf_context.h
libs/unimrcp/libs/mpf/include/mpf_decoder.h
libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_encoder.h
libs/unimrcp/libs/mpf/include/mpf_engine.h
libs/unimrcp/libs/mpf/include/mpf_file_termination_factory.h
libs/unimrcp/libs/mpf/include/mpf_frame.h
libs/unimrcp/libs/mpf/include/mpf_jitter_buffer.h
libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h [deleted file]
libs/unimrcp/libs/mpf/include/mpf_message.h
libs/unimrcp/libs/mpf/include/mpf_mixer.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_multiplier.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_named_event.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_object.h
libs/unimrcp/libs/mpf/include/mpf_resampler.h [moved from libs/unimrcp/libs/mpf/include/mpf_timer.h with 54% similarity]
libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_attribs.h
libs/unimrcp/libs/mpf/include/mpf_rtp_defs.h
libs/unimrcp/libs/mpf/include/mpf_rtp_descriptor.h
libs/unimrcp/libs/mpf/include/mpf_rtp_header.h
libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_rtp_stat.h
libs/unimrcp/libs/mpf/include/mpf_rtp_stream.h
libs/unimrcp/libs/mpf/include/mpf_rtp_termination_factory.h
libs/unimrcp/libs/mpf/include/mpf_scheduler.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_stream.h
libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_stream_mode.h [deleted file]
libs/unimrcp/libs/mpf/include/mpf_termination.h
libs/unimrcp/libs/mpf/include/mpf_termination_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_timer_manager.h [new file with mode: 0644]
libs/unimrcp/libs/mpf/include/mpf_types.h
libs/unimrcp/libs/mpf/include/mpf_user.h [deleted file]
libs/unimrcp/libs/mpf/mpf.vcproj
libs/unimrcp/libs/mpf/src/mpf_activity_detector.c
libs/unimrcp/libs/mpf/src/mpf_audio_file_stream.c
libs/unimrcp/libs/mpf/src/mpf_bridge.c
libs/unimrcp/libs/mpf/src/mpf_codec_descriptor.c
libs/unimrcp/libs/mpf/src/mpf_codec_g711.c
libs/unimrcp/libs/mpf/src/mpf_codec_linear.c
libs/unimrcp/libs/mpf/src/mpf_codec_manager.c
libs/unimrcp/libs/mpf/src/mpf_context.c
libs/unimrcp/libs/mpf/src/mpf_decoder.c
libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_encoder.c
libs/unimrcp/libs/mpf/src/mpf_engine.c
libs/unimrcp/libs/mpf/src/mpf_file_termination_factory.c
libs/unimrcp/libs/mpf/src/mpf_frame_buffer.c
libs/unimrcp/libs/mpf/src/mpf_jitter_buffer.c
libs/unimrcp/libs/mpf/src/mpf_mixer.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_multiplier.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_named_event.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_resampler.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_rtp_attribs.c
libs/unimrcp/libs/mpf/src/mpf_rtp_stream.c
libs/unimrcp/libs/mpf/src/mpf_rtp_termination_factory.c
libs/unimrcp/libs/mpf/src/mpf_scheduler.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_stream.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_termination.c
libs/unimrcp/libs/mpf/src/mpf_termination_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mpf/src/mpf_timer.c [deleted file]
libs/unimrcp/libs/mpf/src/mpf_timer_manager.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-client/include/mrcp_application.h
libs/unimrcp/libs/mrcp-client/include/mrcp_client_session.h
libs/unimrcp/libs/mrcp-client/src/mrcp_client.c
libs/unimrcp/libs/mrcp-client/src/mrcp_client_session.c
libs/unimrcp/libs/mrcp-engine/Makefile.am
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h [moved from libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_plugin.h with 76% similarity]
libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h [moved from libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_state_machine.h with 72% similarity]
libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h [moved from libs/unimrcp/libs/mrcp/resources/include/mrcp_default_factory.h with 62% similarity]
libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_engine.h
libs/unimrcp/libs/mrcp-engine/include/mrcp_state_machine.h [moved from libs/unimrcp/libs/mrcp/control/include/mrcp_state_machine.h with 100% similarity]
libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h [moved from libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_state_machine.h with 72% similarity]
libs/unimrcp/libs/mrcp-engine/mrcpengine.vcproj
libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c [moved from libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_server_state_machine.c with 92% similarity]
libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c [deleted file]
libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c [moved from libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_server_state_machine.c with 91% similarity]
libs/unimrcp/libs/mrcp-server/include/mrcp_server.h
libs/unimrcp/libs/mrcp-server/include/mrcp_server_session.h
libs/unimrcp/libs/mrcp-server/src/mrcp_server.c
libs/unimrcp/libs/mrcp-server/src/mrcp_server_session.c
libs/unimrcp/libs/mrcp-signaling/include/mrcp_session.h
libs/unimrcp/libs/mrcp-signaling/include/mrcp_session_descriptor.h
libs/unimrcp/libs/mrcp/Makefile.am
libs/unimrcp/libs/mrcp/control/include/mrcp_resource.h
libs/unimrcp/libs/mrcp/control/include/mrcp_resource_factory.h
libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/src/mrcp_resource_factory.c
libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/control/src/mrcp_stream.c
libs/unimrcp/libs/mrcp/include/mrcp_types.h
libs/unimrcp/libs/mrcp/message/include/mrcp_message.h
libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/message/src/mrcp_generic_header.c
libs/unimrcp/libs/mrcp/message/src/mrcp_header_accessor.c
libs/unimrcp/libs/mrcp/message/src/mrcp_message.c
libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/mrcp.vcproj
libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_header.h
libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_header.h
libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c [deleted file]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c [deleted file]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_header.c
libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_resource.c
libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c [new file with mode: 0644]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c [deleted file]
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_header.c
libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_resource.c
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection.h
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_connection_types.h
libs/unimrcp/libs/mrcpv2-transport/include/mrcp_control_descriptor.h
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_client_connection.c
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_connection.c
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_control_descriptor.c
libs/unimrcp/libs/mrcpv2-transport/src/mrcp_server_connection.c
libs/unimrcp/libs/uni-rtsp/include/rtsp_header.h
libs/unimrcp/libs/uni-rtsp/src/rtsp_client.c
libs/unimrcp/libs/uni-rtsp/src/rtsp_header.c
libs/unimrcp/libs/uni-rtsp/src/rtsp_message.c
libs/unimrcp/libs/uni-rtsp/src/rtsp_server.c
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sdp.c
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_client_agent.c
libs/unimrcp/modules/mrcp-sofiasip/src/mrcp_sofiasip_server_agent.c
libs/unimrcp/modules/mrcp-unirtsp/include/mrcp_unirtsp_sdp.h
libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_sdp.c
libs/unimrcp/modules/mrcp-unirtsp/src/mrcp_unirtsp_server_agent.c
libs/unimrcp/packages/inno-setup/setup.iss
libs/unimrcp/platforms/Makefile.am
libs/unimrcp/platforms/asr-client/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/asr-client/asrclient.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/asr-client/src/main.c [new file with mode: 0644]
libs/unimrcp/platforms/libasr-client/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/libasr-client/include/asr_engine.h [new file with mode: 0644]
libs/unimrcp/platforms/libasr-client/libasrclient.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/libasr-client/src/asr_engine.c [new file with mode: 0644]
libs/unimrcp/platforms/libunimrcp-client/Makefile.am
libs/unimrcp/platforms/libunimrcp-client/src/unimrcp_client.c
libs/unimrcp/platforms/libunimrcp-server/Makefile.am
libs/unimrcp/platforms/libunimrcp-server/src/unimrcp_server.c
libs/unimrcp/platforms/umc/Makefile.am [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/dtmfscenario.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/dtmfsession.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/recogscenario.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/recogsession.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/recorderscenario.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/recordersession.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/synthscenario.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/synthsession.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/umcconsole.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/umcframework.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/umcscenario.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/include/umcsession.h [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/dtmfscenario.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/dtmfsession.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/main.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/recogscenario.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/recogsession.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/recorderscenario.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/recordersession.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/synthscenario.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/synthsession.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/umcconsole.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/umcframework.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/umcscenario.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/src/umcsession.cpp [new file with mode: 0644]
libs/unimrcp/platforms/umc/umc.vcproj [new file with mode: 0644]
libs/unimrcp/platforms/unimrcp-client/src/demo_bypass_application.c
libs/unimrcp/platforms/unimrcp-client/src/demo_recog_application.c
libs/unimrcp/platforms/unimrcp-client/src/demo_synth_application.c
libs/unimrcp/platforms/unimrcp-client/src/demo_util.c
libs/unimrcp/plugins/Makefile.am
libs/unimrcp/plugins/demo-recog/src/demo_recog_engine.c
libs/unimrcp/plugins/demo-synth/src/demo_synth_engine.c
libs/unimrcp/plugins/mrcp-cepstral/src/mrcp_swift.c
libs/unimrcp/plugins/mrcp-flite/include/flite_voices.h
libs/unimrcp/plugins/mrcp-flite/src/mrcp_flite.c
libs/unimrcp/plugins/mrcp-pocketsphinx/Makefile.am
libs/unimrcp/plugins/mrcp-pocketsphinx/include/pocketsphinx_properties.h
libs/unimrcp/plugins/mrcp-pocketsphinx/src/mrcp_pocketsphinx.c
libs/unimrcp/plugins/mrcp-pocketsphinx/src/pocketsphinx_properties.c
libs/unimrcp/plugins/mrcp-recorder/Makefile.am [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-recorder/mrcprecorder.vcproj [new file with mode: 0644]
libs/unimrcp/plugins/mrcp-recorder/src/mrcp_recorder_engine.c [new file with mode: 0644]
libs/unimrcp/tests/mpftest/src/mpf_suite.c
libs/unimrcp/tests/mrcptest/mrcptest.vcproj
libs/unimrcp/tests/mrcptest/src/parse_gen_suite.c
libs/unimrcp/tests/mrcptest/src/set_get_suite.c
libs/unimrcp/tests/strtablegen/src/main.c
libs/unimrcp/unimrcp.sln

index 365eaf00269e389d0806b687e15e91fda9f8dba5..d032c9e71aa58ae707d0fac3014be58d70d16957 100644 (file)
@@ -4,9 +4,13 @@ Author(s):
 
 Contributor(s):
    Kamil Shakirov <kamils80@gmail.com>
-   Anthony Masse <amasse.telisma@gmail.com>
+   Anthony Masse <amasse.atwork@gmail.com>
    Vlad Socaciu <Curatica@gmail.com>
    Garmt <garmt.noname@gmail.com>
-   Patrick <pnunes29@gmail.com>
-   Bayram <bayramboyraz@gmail.com>
-   Mahmoud Hassan <firstmahmoud2002@gmail.com>
\ No newline at end of file
+   Patrick Nunes <pnunes29@gmail.com>
+   Bayram Boyraz <bayramboyraz@gmail.com>
+   Mahmoud Hassan <firstmahmoud2002@gmail.com>
+   Michael Jerris <mike@jerris.com>
+   Carlos Pina Soares
+   Chaitanya Chokkareddy <chaitanya.chokkareddy@gmail.com>
+   Tomas Valenta <tomas.valenta@speechtech.cz>
index 50826f313a07bc84d902b8c68976e5683b33d949..b29a738be6c1f9a4c46f789cffb2980e75467a3b 100644 (file)
@@ -1,22 +1,31 @@
 BUILD REQUIREMENTS
 ==================
-UniMRCP depends on a number of third party tools and libraries,
-which must be installed prior to UniMRCP build.
+UniMRCP depends on a number of third party tools and libraries, 
+which are required and must be installed first.
 
-1. Apache Portable Runtime [>=1.2.x] (http://apr.apache.org/)
-Whenever you want to build any part of UniMRCP, you need the
-Apache Portable Runtime (APR) and the APR Utility (APR-util)
+The easiest and recommended way is to install an appropriate 
+dependency package from the download area, which contains APR, 
+APR-Util and Sofia-SIP libraries prepackaged for UniMRCP use.
+
+http://code.google.com/p/unimrcp/downloads/
+
+Alternatively, the original packages of APR, APR-Util and
+Sofia-SIP libraries and patches for them can be downloaded from
+
+http://www.unimrcp.org/dependencies/
+
+References:
+  
+1. Apache Portable Runtime [>=1.2.x] (http://apr.apache.org/). 
+Whenever you want to build any part of UniMRCP, you need the 
+Apache Portable Runtime (APR) and the APR Utility (APR-util) 
 libraries.
 
-2. Sofia-SIP [>=1.12.6] (http://sofia-sip.sourceforge.net/)
-Sofia-SIP library is used to implement MRCPv2 specification
+2. Sofia-SIP [>=1.12.6] (http://sofia-sip.sourceforge.net/)
+Sofia-SIP library is used to implement MRCPv2 specification 
 compliant SIP signaling. Sofia-SIP is an open-source SIP User-Agent
 library, compliant with the IETF RFC3261 specification.
 
-Use the link below to download one of known to work and 
-ready to use packages of APR and Sofia-SIP libraries.
-    http://www.unimrcp.org/dependencies/
-
 
 GNU BUILD
 ===================
@@ -36,9 +45,11 @@ $ make install
 Installed directory layout
 bin      - binaries (unimrcpserver, unimrcpclient)
 conf     - configuration files
+data     - data files
 include  - header files
-libs     - shared (convenient) libraries
-plugins  - run-time loadable modules
+lib      - shared (convenient) libraries
+log      - log files
+plugin   - run-time loadable modules
 
 There are a couple of options to "./configure".
 To specify where to look for the APR and APR-util libraries
@@ -100,4 +111,6 @@ libraries and the default configuration to the output directory.
 Output directory layout
 bin      - binaries (unimrcpserver, unimrcpclient) and all the required dlls
 conf     - configuration files
-plugins  - run-time loadable modules
\ No newline at end of file
+data     - data files
+log      - log files
+plugin   - run-time loadable modules
index a720714d6d5b2b62c631b3c6b5d683c84ea5996b..d2609d008f59d73f3878378020d17face09a1aa5 100644 (file)
@@ -31,7 +31,7 @@ def-conf:
 
 def-data:
        test -d $(datadir) || $(mkinstalldirs) $(datadir)
-       for datafile in `find data -name *.pcm -o -name *.xml` ; do \
+       for datafile in `find data -name *.pcm -o -name *.xml -o -name *.jsgf -o -name *.txt` ; do \
            filename=`echo $$datafile | sed -e 's|^.*/||'`; \
            $(INSTALL) -m 644 data/$$filename $(datadir); \
        done
index d2a792cfaded825faa2d84bb37174d48583d2c31..2708a8648a71bfea423d9f0d47db815e7bca4d30 100644 (file)
@@ -25,7 +25,7 @@
                        >
                        <Tool
                                Name="VCPreBuildEventTool"
-                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
+                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; (&#x0D;&#x0A; xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A; if exist &quot;$(AprIconvDir)\$(ConfigurationName)\iconv&quot; (&#x0D;&#x0A;  if not exist &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv&quot;&#x0D;&#x0A;  xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\iconv\*.so&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv\&quot; /Y&#x0D;&#x0A;  )&#x0D;&#x0A;)&#x0D;&#x0A;&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
                                ExcludedFromBuild="false"
                        />
                        <Tool
@@ -47,7 +47,7 @@
                        >
                        <Tool
                                Name="VCPreBuildEventTool"
-                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
+                               CommandLine="xcopy &quot;$(AprDir)\$(ConfigurationName)\libapr-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; (&#x0D;&#x0A; xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A; if exist &quot;$(AprIconvDir)\$(ConfigurationName)\iconv&quot; (&#x0D;&#x0A;  if not exist &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv&quot;&#x0D;&#x0A;  xcopy &quot;$(AprIconvDir)\$(ConfigurationName)\iconv\*.so&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\iconv\&quot; /Y&#x0D;&#x0A;  )&#x0D;&#x0A;)&#x0D;&#x0A;&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;xcopy &quot;$(SofiaDir)\win32\pthread\pthreadVC2.dll&quot; &quot;$(SolutionDir)$(ConfigurationName)\bin\&quot; /Y&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\conf&quot; xcopy &quot;$(SolutionDir)conf\*.xml&quot; &quot;$(SolutionDir)$(ConfigurationName)\conf\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\data&quot; xcopy &quot;$(SolutionDir)data\*&quot; &quot;$(SolutionDir)$(ConfigurationName)\data\&quot; /Y&#x0D;&#x0A;if not exist &quot;$(SolutionDir)$(ConfigurationName)\log&quot; mkdir &quot;$(SolutionDir)$(ConfigurationName)\log\&quot;&#x0D;&#x0A;"
                        />
                        <Tool
                                Name="VCCustomBuildTool"
index b453927d09b99c57e422b74e2602bed3da39fa93..07b10a7d7c635378a0a366d02b97a2ea07abd6a9 100644 (file)
@@ -39,7 +39,7 @@
  * Minor API changes that do not cause binary compatibility problems.
  * Reset to 0 when upgrading UNI_MAJOR_VERSION
  */
-#define UNI_MINOR_VERSION   6
+#define UNI_MINOR_VERSION   8
 
 /** patch level 
  * The Patch Level never includes API changes, simply bug fixes.
index 966d2b794e60cf3a40aec3db52e9a6f4ee29e2c6..a65c5a08c8cfd06b64d8aa18f23748d44b8ab38b 100644 (file)
@@ -15,6 +15,6 @@
        />
        <UserMacro
                Name="UniMRCPServerLibs"
-               Value="libunimrcpserver.lib mrcpserver.lib mrcpsignaling.lib mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
+               Value="libunimrcpserver.lib mrcpserver.lib mrcpsignaling.lib mrcpengine.lib mrcp.lib aprtoolkit.lib libaprutil-1.lib libapr-1.lib libsofia_sip_ua.lib ws2_32.lib winmm.lib"
        />
 </VisualStudioPropertySheet>
diff --git a/libs/unimrcp/conf/umcscenarios.xml b/libs/unimrcp/conf/umcscenarios.xml
new file mode 100644 (file)
index 0000000..ab02487
--- /dev/null
@@ -0,0 +1,96 @@
+<!-- 
+UniMRCP Client Scenarios.
+There are predefined, named scenarios, which you can customize and use.
+Currently available scenarios are
+1. class="Synthesizer"
+2. class="Recognizer"
+3. class="Recorder"
+4. class="DtmfRecofnizer"
+
+More than one scenario of the same type (class) can be defined.
+The name (not class) of the scenario is used to run it from console.
+For instance,
+> run synth
+-->
+
+<umcscenarios>
+  <scenario name="synth" class="Synthesizer" profile="MRCPv2-Default">
+    <resource-discovery enable="0"/>
+    <speak enable="1" content-type="application/synthesis+ssml" content-location="speak.xml"/>
+    <!-- <speak enable="1" content-type="text/plain" content-location="speak.txt"/> -->
+
+    <termination enable="1">
+      <capabilities>
+        <codec name="LPCM" rates="8000 16000"/>
+        <!-- <codec name="PCMU" rates="8000 16000"/> -->
+      </capabilities>
+    </termination>
+    <!-- 
+    <rtp-termination enable="1" ip="127.0.0.1" port="5678">
+      <codecs="PCMU PCMA L16/96/8000 PCMU/97/16000 telephone-event/101/8000"/>
+    </rtp-termination>
+    -->
+  </scenario>
+
+  <scenario name="recog" class="Recognizer" profile="MRCPv2-Default">
+    <resource-discovery enable="0"/>
+    <define-grammar enable="1" content-type="application/srgs+xml" content-location="grammar.xml"/>
+    <!-- <define-grammar enable="1" content-type="application/grammar+xml" content-location="grammar.xml"/> -->
+    <!-- <define-grammar enable="1" content-type="application/x-jsgf" content-location="grammar.jsgf"/> -->
+    <recognize enable="1"/>
+    <!-- <recognize enable="1" audio-source="one-8kHz.pcm"/> -->
+    <!-- <recognize enable="1" content-type="application/srgs+xml" content-location="grammar.xml"/> -->
+
+    <termination enable="1">
+      <capabilities>
+        <codec name="LPCM" rates="8000 16000"/>
+        <!-- <codec name="PCMU" rates="8000 16000"/> -->
+      </capabilities>
+    </termination>
+    <!-- 
+    <rtp-termination enable="1" ip="127.0.0.1" port="5678">
+      <codecs="PCMU PCMA L16/96/8000 PCMU/97/16000 telephone-event/101/8000"/>
+    </rtp-termination>
+    -->
+  </scenario>
+
+  <scenario name="rec" class="Recorder" profile="MRCPv2-Default">
+    <resource-discovery enable="0"/>
+    <record enable="1"/>
+
+    <termination enable="1">
+      <capabilities>
+        <codec name="LPCM" rates="8000 16000"/>
+        <!-- <codec name="PCMU" rates="8000 16000"/> -->
+      </capabilities>
+    </termination>
+    <!-- 
+    <rtp-termination enable="1" ip="127.0.0.1" port="5678">
+      <codecs="PCMU PCMA L16/96/8000 PCMU/97/16000 telephone-event/101/8000"/>
+    </rtp-termination>
+    -->
+  </scenario>
+
+  <scenario name="dtmf" class="DtmfRecognizer" profile="MRCPv2-Default">
+    <resource-discovery enable="0"/>
+    <recognize enable="1" content-type="text/uri-list" grammar="builtin:dtmf/digits" digits="1234"/> -->
+
+    <termination enable="1">
+      <capabilities>
+        <codec name="LPCM" rates="8000 16000"/>
+        <!-- <codec name="PCMU" rates="8000 16000"/> -->
+      </capabilities>
+    </termination>
+    <!-- 
+    <rtp-termination enable="1" ip="127.0.0.1" port="5678">
+      <codecs="PCMU PCMA L16/96/8000 PCMU/97/16000 telephone-event/101/8000"/>
+    </rtp-termination>
+    -->
+  </scenario>
+
+  <!-- It'd be great to have scriptable custom scenarios as well.
+  <scenario name="custom" class="UmcXml">
+  </scenario>
+  -->
+
+</umcscenarios>
index fc903ffbd8af7aab23e5f326912718cd9bc5d177..42a18d3552d41ed114e5b90edb5cf95411d4d1dc 100644 (file)
@@ -1,5 +1,12 @@
 <!-- UniMRCP client document -->
 <unimrcpclient>
+  <!-- MRCP resources -->
+  <resources>
+    <resource class="speechsynth" enable="1"/>
+    <resource class="speechrecog" enable="1"/>
+    <resource class="recorder" enable="1"/>
+  </resources>
+
   <!-- Client settings (signaling, media, ...) -->
   <settings>
     <!-- SIP, RTSP signaling agents -->
         <!-- <param name="playout-delay" value="50"/> -->
         <!-- <param name="max-playout-delay" value="200"/> -->
         <!-- <param name="ptime" value="20"/> -->
-        <param name="codecs" value="PCMU PCMA L16/96/8000"/>
+        <param name="codecs" value="PCMU PCMA L16/96/8000 PCMU/97/16000 telephone-event/101/8000"/>
+        <!-- <param name="codecs" value="PCMU PCMA L16/96/8000 PCMU/97/16000 PCMA/98/16000 L16/99/16000"/> -->
+
+        <!-- enable/disable rtcp support -->
+        <param name="rtcp" value="0"/>
+        <!-- rtcp bye policies (rtcp must be enabled first)
+             0 - disable rtcp bye
+             1 - send rtcp bye at the end of session
+             2 - send rtcp bye also at the end of each talkspurt (input)
+        -->
+        <param name="rtcp-bye" value="1"/>
+        <!-- rtcp transmission interval in msec (set 0 to disable) -->
+        <param name="rtcp-tx-interval" value="5000"/>
+        <!-- period (timeout) to check for new rtcp messages in msec (set 0 to disable) -->
+        <param name="rtcp-rx-resolution" value="1000"/>
       </rtp>
     </media>
   </settings>
index eac086bd4fc02e2ac911028efe3aded479d34d01..7e7c094e27973365dbc4a81e862c9896ef21ae46 100644 (file)
@@ -1,5 +1,12 @@
 <!-- unimrcpserver document -->
 <unimrcpserver>
+  <!-- MRCP resources -->
+  <resources>
+    <resource class="speechsynth" enable="1"/>
+    <resource class="speechrecog" enable="1"/>
+    <resource class="recorder" enable="1"/>
+  </resources>
+
   <!-- Server settings (signaling, media, ...) -->
   <settings>
     <!-- SIP, RTSP signaling agents -->
         <!-- <param name="playout-delay" value="50"/> -->
         <!-- <param name="max-playout-delay" value="200"/> -->
         <!-- <param name="ptime" value="20"/> -->
-        <param name="codecs" value="PCMU PCMA L16/96/8000"/>
+        <param name="codecs" value="PCMU PCMA L16/96/8000 telephone-event/101/8000"/>
+        <!-- <param name="codecs" value="PCMU PCMA L16/96/8000 PCMU/97/16000 PCMA/98/16000 L16/99/16000"/> -->
         <!-- <param name="own-preference" value="1"/> -->
+
+        <!-- enable/disable rtcp support -->
+        <param name="rtcp" value="0"/>
+        <!-- rtcp bye policies (rtcp must be enabled first)
+             0 - disable rtcp bye
+             1 - send rtcp bye at the end of session
+             2 - send rtcp bye also at the end of each talkspurt (input)
+        -->
+        <param name="rtcp-bye" value="1"/>
+        <!-- rtcp transmission interval in msec -->
+        <param name="rtcp-tx-interval" value="5000"/>
+        <!-- period (timeout) to check for new rtcp messages in msec (set 0 to disable) -->
+        <param name="rtcp-rx-resolution" value="1000"/>
       </rtp>
     </media>
 
@@ -58,6 +79,7 @@
       <engine name="Flite-1" class="mrcpflite" enable="0"/>
       <engine name="Demo-Synth-1" class="demosynth" enable="1"/>
       <engine name="Demo-Recog-1" class="demorecog" enable="1"/>
+      <engine name="Recorder-1" class="mrcprecorder" enable="1"/>
     </plugin>
   </settings>
 
index dd7fe6ac1d0d3c8cfe4e89e10a9d6a8591635fdc..ac8174e7521b11fc93bb06343cd206d35bbe0cca 100644 (file)
@@ -3,7 +3,7 @@
 
 AC_PREREQ(2.57)
 
-AC_INIT([unimrcp],[0.6.0])
+AC_INIT([unimrcp],[0.8.0])
 
 AC_CONFIG_AUX_DIR([build])
 AC_CONFIG_MACRO_DIR([build/acmacros])
@@ -31,7 +31,7 @@ AC_PROG_LIBTOOL
 # Get version information
 get_version="build/get-version.sh"
 version_hdr="build/uni_version.h"
-plugin_version_hdr="libs/mrcp-engine/include/mrcp_resource_plugin.h"
+plugin_version_hdr="libs/mrcp-engine/include/mrcp_engine_plugin.h"
 UNI_DOTTED_VERSION="`$get_version all $version_hdr UNI`"
 UNI_LT_VERSION="-version-info `$get_version libtool $version_hdr UNI`"
 PLUGIN_LT_VERSION="-version-info `$get_version libtool $plugin_version_hdr PLUGIN`"
@@ -117,6 +117,15 @@ AC_ARG_ENABLE(demorecog-plugin,
 AM_CONDITIONAL([DEMORECOG_PLUGIN],[test "${enable_demorecog_plugin}" = "yes"])
 
 
+#Enable recorder plugin
+AC_ARG_ENABLE(recorder-plugin,
+    [AC_HELP_STRING([--disable-recorder-plugin  ],[exclude recorder plugin from build])],
+    [enable_recorder_plugin="$enableval"],
+    [enable_recorder_plugin="yes"])
+
+AM_CONDITIONAL([RECORDER_PLUGIN],[test "${enable_recorder_plugin}" = "yes"])
+
+
 #Enable Cepstral Swift plugin
 AC_ARG_ENABLE(cepstral-plugin,
     [AC_HELP_STRING([--disable-cepstral-plugin  ],[exclude cepstral plugin from build])],
@@ -182,6 +191,7 @@ AC_CONFIG_FILES([
   plugins/mrcp-cepstral/Makefile
   plugins/mrcp-pocketsphinx/Makefile
   plugins/mrcp-flite/Makefile
+  plugins/mrcp-recorder/Makefile
   plugins/demo-synth/Makefile
   plugins/demo-recog/Makefile
   platforms/Makefile
@@ -189,6 +199,9 @@ AC_CONFIG_FILES([
   platforms/libunimrcp-client/Makefile
   platforms/unimrcp-server/Makefile
   platforms/unimrcp-client/Makefile
+  platforms/libasr-client/Makefile
+  platforms/asr-client/Makefile
+  platforms/umc/Makefile
   tests/Makefile
   tests/apttest/Makefile
   tests/mpftest/Makefile
diff --git a/libs/unimrcp/data/demo-16kHz.pcm b/libs/unimrcp/data/demo-16kHz.pcm
new file mode 100644 (file)
index 0000000..01ace40
Binary files /dev/null and b/libs/unimrcp/data/demo-16kHz.pcm differ
diff --git a/libs/unimrcp/data/grammar.jsgf b/libs/unimrcp/data/grammar.jsgf
new file mode 100644 (file)
index 0000000..df19bb9
--- /dev/null
@@ -0,0 +1,3 @@
+#JSGF V1.0;\r
+grammar digits;\r
+public <numbers> = (one | two | three);\r
diff --git a/libs/unimrcp/data/one-16kHz.pcm b/libs/unimrcp/data/one-16kHz.pcm
new file mode 100644 (file)
index 0000000..44e0b34
Binary files /dev/null and b/libs/unimrcp/data/one-16kHz.pcm differ
diff --git a/libs/unimrcp/data/speak.txt b/libs/unimrcp/data/speak.txt
new file mode 100644 (file)
index 0000000..3245b20
--- /dev/null
@@ -0,0 +1 @@
+Hello World.
\ No newline at end of file
index c36fcd21c8b253388941682df9a399676b7f76dd..7c6ea3ab08c31d69801ba76e2bfa91fb0a33ecff 100644 (file)
@@ -26,6 +26,7 @@
 
 APT_BEGIN_EXTERN_C
 
+/** Default size (number of elements) of cyclic queue */
 #define CYCLIC_QUEUE_DEFAULT_SIZE      100
 
 /** Opaque cyclic queue declaration */
index d3b38abf8306199c36c3de1b503085e35d1a4ab2..aee0adb2195f4c1e51f72d1e03f56da6e5ec7e93 100644 (file)
@@ -98,12 +98,12 @@ APT_DECLARE(apt_bool_t) apt_log_instance_create(apt_log_output_e mode, apt_log_p
 /**
  * Destroy the singleton instance of the logger.
  */
-APT_DECLARE(apt_bool_t) apt_log_instance_destroy();
+APT_DECLARE(apt_bool_t) apt_log_instance_destroy(void);
 
 /**
  * Get the singleton instance of the logger.
  */
-APT_DECLARE(apt_logger_t*) apt_log_instance_get();
+APT_DECLARE(apt_logger_t*) apt_log_instance_get(void);
 
 /**
  * Set the singleton instance of the logger.
@@ -128,7 +128,7 @@ APT_DECLARE(apt_bool_t) apt_log_file_open(
 /**
  * Close the log file.
  */
-APT_DECLARE(apt_bool_t) apt_log_file_close();
+APT_DECLARE(apt_bool_t) apt_log_file_close(void);
 
 /**
  * Set the logging output.
index d3792f2dd178d73436ea299f1f580d942fa1e19f..7c9d1098512b1c31f28a6ca501b9f45eb054f91c 100644 (file)
@@ -33,6 +33,14 @@ APT_BEGIN_EXTERN_C
  */
 apt_bool_t apt_ip_get(char **addr, apr_pool_t *pool);
 
+
+/**
+ * Get current NTP time
+ * @param sec the seconds of the NTP time to return
+ * @param frac the fractions of the NTP time to return
+ */
+void apt_ntp_time_get(apr_uint32_t *sec, apr_uint32_t *frac);
+
 APT_END_EXTERN_C
 
 #endif /*__APT_NET_H__*/
index 85f8476db4ba46b47ea81bf76f46fd8ded14fcf5..ab8724598fa47a7ffc15ae235f2ea39c86d27a9f 100644 (file)
@@ -30,16 +30,16 @@ APT_BEGIN_EXTERN_C
 /** Load NLSML document */
 APT_DECLARE(apr_xml_doc*) nlsml_doc_load(const apt_str_t *data, apr_pool_t *pool);
 
-/** Get the first <interpretation> element */
+/** Get the first interpretation element */
 APT_DECLARE(apr_xml_elem*) nlsml_first_interpret_get(const apr_xml_doc *doc);
 
-/** Get the next <interpretation> element */
+/** Get the next interpretation element */
 APT_DECLARE(apr_xml_elem*) nlsml_next_interpret_get(const apr_xml_elem *interpret);
 
-/** Get <instance> and <input> elements of <interpretation> element */
+/** Get instance and input elements of interpretation element */
 APT_DECLARE(apt_bool_t) nlsml_interpret_results_get(const apr_xml_elem *interpret, apr_xml_elem **instance, apr_xml_elem **input);
 
-/** Get specified atrribute of <input> */
+/** Get specified atrribute of input element */
 APT_DECLARE(const char *) nlsml_input_attrib_get(const apr_xml_elem *input, const char *attrib, apt_bool_t recursive);
 
 
index 085195bee41f6d69751f0ea6110657cc352f8295..b2bff52688b06f66718465402c953cc20bff638e 100644 (file)
@@ -34,7 +34,7 @@ APT_BEGIN_EXTERN_C
 /**
  * Create APR pool
  */
-APT_DECLARE(apr_pool_t*) apt_pool_create();
+APT_DECLARE(apr_pool_t*) apt_pool_create(void);
 
 /**
  * Create APR subpool pool
index a2117d72d32d2739a32f30802acf4df90972e841..29c2dea399a9ebddc1bc8218bcf2da9b19311551 100644 (file)
@@ -55,8 +55,8 @@ APT_DECLARE(apt_task_t*) apt_task_create(
 APT_DECLARE(apt_bool_t) apt_task_destroy(apt_task_t *task);
 
 /**
- * Add slave task.
- * @param task the task to add slave task to
+ * Add child task.
+ * @param task the task to add child task to
  * @param child_task the child task to add
  */
 APT_DECLARE(apt_bool_t) apt_task_add(apt_task_t *task, apt_task_t *child_task);
@@ -157,6 +157,19 @@ APT_DECLARE(void) apt_task_name_set(apt_task_t *task, const char *name);
  */
 APT_DECLARE(const char*) apt_task_name_get(apt_task_t *task);
 
+/**
+ * Enable/disable auto ready mode.
+ * @param task the task to set mode for
+ * @param auto_ready the enabled/disabled auto ready mode
+ */
+APT_DECLARE(void) apt_task_auto_ready_set(apt_task_t *task, apt_bool_t auto_ready);
+
+/**
+ * Explicitly indicate task is ready to process messages.
+ * @param task the task
+ */
+APT_DECLARE(apt_bool_t) apt_task_ready(apt_task_t *task);
+
 /**
  * Hold task execution.
  * @param msec the time to hold
index a703de7c032872abf26912497415e6b1b8b45a3a..3e1b2cbeca06acc6dc2a5a229ceee33fbb6b57ae 100644 (file)
@@ -65,7 +65,7 @@ typedef struct apt_test_framework_t apt_test_framework_t;
 /**
  * Create test framework.
  */
-APT_DECLARE(apt_test_framework_t*) apt_test_framework_create();
+APT_DECLARE(apt_test_framework_t*) apt_test_framework_create(void);
 
 /**
  * Destroy test framework.
index 42a87543474e010204c982d2e34054388be0bedc..3b96373a74945d2d141cb98e8e633faf70ff6172 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <apr_queue.h>
 #include "apt_consumer_task.h"
+#include "apt_log.h"
 
 struct apt_consumer_task_t {
        void        *obj;
@@ -85,6 +86,7 @@ static apt_bool_t apt_consumer_task_run(apt_task_t *task)
        }
 
        while(running) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for Task Messages [%s]",apt_task_name_get(task));
                rv = apr_queue_pop(consumer_task->msg_queue,&msg);
                if(rv == APR_SUCCESS) {
                        if(msg) {
index 25a5abf5d583a2b0365cb19a64a087a2ee805d2c..a78e61c54ca73e36a11eebb8a7da0005123e6478 100644 (file)
@@ -257,7 +257,7 @@ static apt_bool_t apt_do_log(const char *file, int line, apt_log_priority_e prio
        log_entry[offset++] = '\n';
        log_entry[offset] = '\0';
        if((apt_logger->mode & APT_LOG_OUTPUT_CONSOLE) == APT_LOG_OUTPUT_CONSOLE) {
-               printf(log_entry);
+               fwrite(log_entry,offset,1,stdout);
        }
        
        if((apt_logger->mode & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE && apt_logger->file_data) {
index bf5b8a9f92c70b7a8488ffa2d6ea1a09552c407c..733f0e20bc8e03ee1e78a94965d499ce62d6bb83 100644 (file)
@@ -33,3 +33,20 @@ apt_bool_t apt_ip_get(char **addr, apr_pool_t *pool)
        }
        return TRUE;
 }
+
+/** Seconds from  Jan 1 1900 to Jan 1 1970 */
+#define NTP_TIME_OFFSET 2208988800UL
+
+/** Get current NTP time */
+void apt_ntp_time_get(apr_uint32_t *sec, apr_uint32_t *frac)
+{
+       apr_uint32_t t;
+       apr_uint32_t usec;
+       
+       apr_time_t now = apr_time_now();
+       *sec = (apr_uint32_t)apr_time_sec(now) + NTP_TIME_OFFSET;
+
+       usec = (apr_uint32_t) apr_time_usec(now);
+       t = (usec * 1825) >> 5;
+       *frac = ((usec << 12) + (usec << 8) - t);
+}
index 6e59440cbdc89df9ee1952ccb5f694c27294876e..6effe42f3c6c4d81f235d2896d2041ef9b4d8e31 100644 (file)
@@ -74,6 +74,7 @@ APT_DECLARE(apt_net_client_task_t*) apt_net_client_task_create(
                vtable->destroy = apt_net_client_task_on_destroy;
                vtable->signal_msg = apt_net_client_task_msg_signal;
        }
+       apt_task_auto_ready_set(task->base,FALSE);
 
        task->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
        apr_thread_mutex_create(&task->guard,APR_THREAD_MUTEX_UNNESTED,pool);
@@ -279,6 +280,9 @@ static apt_bool_t apt_net_client_task_run(apt_task_t *base)
                return FALSE;
        }
 
+       /* explicitly indicate task is ready to process messages */
+       apt_task_ready(task->base);
+
        while(running) {
                status = apt_pollset_poll(task->pollset, -1, &num, &ret_pfd);
                if(status != APR_SUCCESS) {
index 4d994f4bedbec363befd8f271382ac0f4cb1c78d..93cc9f5d69b9fc3817acec7b1d692906313e2333 100644 (file)
@@ -89,6 +89,7 @@ APT_DECLARE(apt_net_server_task_t*) apt_net_server_task_create(
                vtable->destroy = apt_net_server_task_on_destroy;
                vtable->signal_msg = apt_net_server_task_msg_signal;
        }
+       apt_task_auto_ready_set(task->base,FALSE);
 
        task->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
        apr_thread_mutex_create(&task->guard,APR_THREAD_MUTEX_UNNESTED,pool);
@@ -324,6 +325,9 @@ static apt_bool_t apt_net_server_task_run(apt_task_t *base)
                return FALSE;
        }
 
+       /* explicitly indicate task is ready to process messages */
+       apt_task_ready(task->base);
+
        while(running) {
                status = apt_pollset_poll(task->pollset, -1, &num, &ret_pfd);
                if(status != APR_SUCCESS) {
index 816eea264e70ceb867bfb4d8c60104c32e14aa3e..982ab1093a5786b25778be16f1306ab16ed959b6 100644 (file)
@@ -34,8 +34,8 @@ APT_DECLARE(apt_pair_arr_t*) apt_pair_array_copy(const apt_pair_arr_t *src_arr,
        }
        arr = apr_array_copy(pool,src_arr);
        for(i=0; i<arr->nelts; i++) {
-               pair = (apt_pair_t*)arr->elts + i;
-               src_pair = (const apt_pair_t*)src_arr->elts + i;
+               pair = &APR_ARRAY_IDX(arr,i,apt_pair_t);
+               src_pair = &APR_ARRAY_IDX(src_arr,i,const apt_pair_t);
                apt_pair_copy(pair,src_pair,pool);
        }
        return arr;
@@ -62,7 +62,7 @@ APT_DECLARE(const apt_pair_t*) apt_pair_array_find(const apt_pair_arr_t *arr, co
        int i;
        apt_pair_t *pair;
        for(i=0; i<arr->nelts; i++) {
-               pair = (apt_pair_t*)arr->elts + i;
+               pair = &APR_ARRAY_IDX(arr,i,apt_pair_t);
                if(apt_string_compare(&pair->name,name) == TRUE) {
                        return pair;
                }
index 9de0e3fa93314eb30387b63a1f35ecb09f0f5a80..8f7540083631fb8f128d842fb822bf37e60210de 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "apt_pool.h"
 
-//#define OWN_ALLOCATOR_PER_POOL
+#define OWN_ALLOCATOR_PER_POOL
 
 APT_DECLARE(apr_pool_t*) apt_pool_create()
 {
@@ -31,6 +31,7 @@ APT_DECLARE(apr_pool_t*) apt_pool_create()
                        apr_allocator_owner_set(allocator,pool);
                        apr_thread_mutex_create(&mutex,APR_THREAD_MUTEX_NESTED,pool);
                        apr_allocator_mutex_set(allocator,mutex);
+                       apr_pool_mutex_set(pool,mutex); 
                }
        }
 #else
index 0c8f3d04652e5a7a9cd22298b11e9fddc695e51b..355a7a62c9e010e7499ea04a07ac38f29a3ea968 100644 (file)
@@ -40,6 +40,7 @@ struct apt_task_t {
        apt_obj_list_t      *child_tasks;   /* list of the child (slave) tasks */
        apr_size_t           pending_start; /* number of pending start requests */
        apr_size_t           pending_term;  /* number of pending terminate requests */
+       apt_bool_t           auto_ready;    /* if TRUE, task is implicitly ready to process messages */
        const char          *name;          /* name of the task */
 };
 
@@ -75,6 +76,7 @@ APT_DECLARE(apt_task_t*) apt_task_create(
        task->child_tasks = apt_list_create(pool);
        task->pending_start = 0;
        task->pending_term = 0;
+       task->auto_ready = TRUE;
        task->name = "Task";
        return task;
 }
@@ -386,6 +388,23 @@ APT_DECLARE(apt_bool_t) apt_task_child_terminate(apt_task_t *task)
        return TRUE;
 }
 
+APT_DECLARE(void) apt_task_auto_ready_set(apt_task_t *task, apt_bool_t auto_ready)
+{
+       task->auto_ready = auto_ready;
+}
+
+APT_DECLARE(apt_bool_t) apt_task_ready(apt_task_t *task)
+{
+       if(task->auto_ready == TRUE) {
+               return FALSE;
+       }
+
+       /* start child tasks (if any) */
+       apt_task_child_start(task);
+       return TRUE;
+}
+
+
 static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *data)
 {
        apt_task_t *task = data;
@@ -398,8 +417,10 @@ static void* APR_THREAD_FUNC apt_task_run(apr_thread_t *thread_handle, void *dat
        task->state = TASK_STATE_RUNNING;
        apr_thread_mutex_unlock(task->data_guard);
 
-       /* start child tasks (if any) */
-       apt_task_child_start(task);
+       if(task->auto_ready == TRUE) {
+               /* start child tasks (if any) */
+               apt_task_child_start(task);
+       }
 
        /* run task */
        if(task->vtable.run) {
index 4a73d9132535abaff53d4f62aadfeecd43565548..d1539052781c91500a08869add021b919a40c8ac 100644 (file)
@@ -18,17 +18,24 @@ include_HEADERS          = codecs/g711/g711.h \
                            include/mpf_codec_descriptor.h \
                            include/mpf_codec_manager.h \
                            include/mpf_context.h \
+                           include/mpf_dtmf_detector.h \
+                           include/mpf_dtmf_generator.h \
                            include/mpf_engine.h \
                            include/mpf_frame.h \
                            include/mpf_frame_buffer.h \
                            include/mpf_message.h \
+                           include/mpf_mixer.h \
+                           include/mpf_multiplier.h \
+                           include/mpf_named_event.h \
                            include/mpf_object.h \
                            include/mpf_stream.h \
-                           include/mpf_stream_mode.h \
+                           include/mpf_stream_descriptor.h \
                            include/mpf_termination.h \
+                           include/mpf_termination_factory.h \
                            include/mpf_rtp_termination_factory.h \
                            include/mpf_file_termination_factory.h \
-                           include/mpf_timer.h \
+                           include/mpf_scheduler.h \
+                           include/mpf_timer_manager.h \
                            include/mpf_types.h \
                            include/mpf_encoder.h \
                            include/mpf_decoder.h \
@@ -39,8 +46,9 @@ include_HEADERS          = codecs/g711/g711.h \
                            include/mpf_rtp_stat.h \
                            include/mpf_rtp_defs.h \
                            include/mpf_rtp_attribs.h \
-                           include/mpf_media_descriptor.h \
-                           include/mpf_user.h
+                           include/mpf_rtp_pt.h \
+                           include/mpf_rtcp_packet.h \
+                           include/mpf_resampler.h
 
 libmpf_la_SOURCES        = codecs/g711/g711.c \
                            src/mpf_activity_detector.c \
@@ -52,14 +60,23 @@ libmpf_la_SOURCES        = codecs/g711/g711.c \
                            src/mpf_codec_linear.c \
                            src/mpf_codec_manager.c \
                            src/mpf_context.c \
+                           src/mpf_dtmf_detector.c \
+                           src/mpf_dtmf_generator.c \
                            src/mpf_engine.c \
+                           src/mpf_mixer.c \
+                           src/mpf_multiplier.c \
+                           src/mpf_named_event.c \
                            src/mpf_termination.c \
+                           src/mpf_termination_factory.c \
                            src/mpf_rtp_termination_factory.c \
                            src/mpf_file_termination_factory.c \
                            src/mpf_frame_buffer.c \
-                           src/mpf_timer.c \
+                           src/mpf_scheduler.c \
+                           src/mpf_timer_manager.c \
                            src/mpf_encoder.c \
                            src/mpf_decoder.c \
                            src/mpf_jitter_buffer.c \
                            src/mpf_rtp_stream.c \
-                           src/mpf_rtp_attribs.c
+                           src/mpf_rtp_attribs.c \
+                           src/mpf_resampler.c \
+                           src/mpf_stream.c
index 57729877c4c791fc5bf51a86a6a97ac18fab55c8..1b90b558d58543192ab8008280149464dd91b86d 100644 (file)
@@ -23,7 +23,7 @@
  */ 
 
 #include "mpf_frame.h"
-#include "mpf_codec.h"
+#include "mpf_codec_descriptor.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -51,8 +51,11 @@ MPF_DECLARE(void) mpf_activity_detector_level_set(mpf_activity_detector_t *detec
 /** Set noinput timeout */
 MPF_DECLARE(void) mpf_activity_detector_noinput_timeout_set(mpf_activity_detector_t *detector, apr_size_t noinput_timeout);
 
-/** Set transition complete timeout */
-MPF_DECLARE(void) mpf_activity_detector_complete_timeout_set(mpf_activity_detector_t *detector, apr_size_t complete_timeout);
+/** Set timeout required to trigger speech (transition from inactive to active state) */
+MPF_DECLARE(void) mpf_activity_detector_speech_timeout_set(mpf_activity_detector_t *detector, apr_size_t speech_timeout);
+
+/** Set timeout required to trigger silence (transition from active to inactive state) */
+MPF_DECLARE(void) mpf_activity_detector_silence_timeout_set(mpf_activity_detector_t *detector, apr_size_t silence_timeout);
 
 /** Process current frame, return detected event if any */
 MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_detector_t *detector, const mpf_frame_t *frame);
index 4dfb6d3ebba12130a1f184c75cc8d16105096b75..0d9c439c4c38c937ed00b4bffaeb9ef2c684b43f 100644 (file)
  */ 
 
 #include <stdio.h>
-#include "mpf_stream_mode.h"
-#include "mpf_codec_descriptor.h"
+#include "mpf_stream_descriptor.h"
 
 APT_BEGIN_EXTERN_C
 
-/** FILE_READER is defined as STREAM_MODE_RECEIVE */
-#define FILE_READER STREAM_MODE_RECEIVE
-/** FILE_WRITER is defined as STREAM_MODE_SEND */
-#define FILE_WRITER STREAM_MODE_SEND
+/** FILE_READER defined as a stream source */
+#define FILE_READER STREAM_DIRECTION_RECEIVE
+/** FILE_WRITER defined as a stream sink */
+#define FILE_WRITER STREAM_DIRECTION_SEND
 
 /** Audio file descriptor declaration */
 typedef struct mpf_audio_file_descriptor_t mpf_audio_file_descriptor_t;
 
 /** Audio file descriptor */
 struct mpf_audio_file_descriptor_t {
-       /** Indicate what descriptor for (reader and/or write) */
-       mpf_stream_mode_e      mask;
+       /** Indicate descriptor type (reader and/or writer) */
+       mpf_stream_direction_e  mask;
        /** Codec descriptor to use for audio file read/write */
-       mpf_codec_descriptor_t codec_descriptor;
+       mpf_codec_descriptor_t *codec_descriptor;
        /** File handle to read audio stream */
-       FILE                  *read_handle;
+       FILE                   *read_handle;
        /** File handle to write audio stream */
-       FILE                  *write_handle;
+       FILE                   *write_handle;
        /** Max size of file  */
-       apr_size_t             max_write_size;
+       apr_size_t              max_write_size;
 };
 
 APT_END_EXTERN_C
index ceb00713b9bbdca8866b07bb7f18efe66994ca0d..395aaa966acb2732c1c4546cf4af16f5d51032a7 100644 (file)
@@ -30,17 +30,14 @@ APT_BEGIN_EXTERN_C
  * Create bridge of audio streams.
  * @param source the source audio stream
  * @param sink the sink audio stream
+ * @param codec_manager the codec manager
  * @param pool the pool to allocate memory from
  */
-MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool);
-
-/**
- * Create bridge of audio streams with the same codec descriptor.
- * @param source the source audio stream
- * @param sink the sink audio stream
- * @param pool the pool to allocate memory from
- */
-MPF_DECLARE(mpf_object_t*) mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool);
+MPF_DECLARE(mpf_object_t*) mpf_bridge_create(
+                                                               mpf_audio_stream_t *source, 
+                                                               mpf_audio_stream_t *sink, 
+                                                               const mpf_codec_manager_t *codec_manager,
+                                                               apr_pool_t *pool);
 
 
 APT_END_EXTERN_C
index 282ab693d8c6edc1de5c019c0d11972429aa7755..04d9b27079d395e69313e6af63d90b73c8acd2f4 100644 (file)
@@ -39,9 +39,6 @@ struct mpf_codec_t {
        const mpf_codec_attribs_t    *attribs;
        /** Optional static codec descriptor (pt < 96) */
        const mpf_codec_descriptor_t *static_descriptor;
-       
-       /** Negotiated codec descriptor */
-       mpf_codec_descriptor_t       *descriptor;
 };
 
 /** Table of codec virtual methods */
@@ -77,7 +74,6 @@ static APR_INLINE mpf_codec_t* mpf_codec_create(
        codec->vtable = vtable;
        codec->attribs = attribs;
        codec->static_descriptor = descriptor;
-       codec->descriptor = NULL;
        return codec;
 }
 
@@ -92,7 +88,6 @@ static APR_INLINE mpf_codec_t* mpf_codec_clone(mpf_codec_t *src_codec, apr_pool_
        codec->vtable = src_codec->vtable;
        codec->attribs = src_codec->attribs;
        codec->static_descriptor = src_codec->static_descriptor;
-       codec->descriptor = src_codec->descriptor;
        return codec;
 }
 
@@ -100,13 +95,8 @@ static APR_INLINE mpf_codec_t* mpf_codec_clone(mpf_codec_t *src_codec, apr_pool_
 static APR_INLINE apt_bool_t mpf_codec_open(mpf_codec_t *codec)
 {
        apt_bool_t rv = TRUE;
-       if(codec->descriptor) {
-               if(codec->vtable->open) {
-                       rv = codec->vtable->open(codec);
-               }
-       }
-       else {
-               rv = FALSE;
+       if(codec->vtable->open) {
+               rv = codec->vtable->open(codec);
        }
        return rv;
 }
index 09fd3254048b1c9b97acf421b90814a3658ac3a9..9f3a6ea1d7f16ff4203e980c03a907a836e5bb06 100644 (file)
@@ -41,17 +41,22 @@ typedef enum {
        MPF_SAMPLE_RATE_8000  = 0x01,
        MPF_SAMPLE_RATE_16000 = 0x02,
        MPF_SAMPLE_RATE_32000 = 0x04,
-       MPF_SAMPLE_RATE_48000 = 0x08
+       MPF_SAMPLE_RATE_48000 = 0x08,
+
+       MPF_SAMPLE_RATE_SUPPORTED =     MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 | 
+                                                               MPF_SAMPLE_RATE_32000 | MPF_SAMPLE_RATE_48000
 } mpf_sample_rates_e;
 
 /** Codec descriptor declaration */
 typedef struct mpf_codec_descriptor_t mpf_codec_descriptor_t;
+/** Codec attributes declaration */
+typedef struct mpf_codec_attribs_t mpf_codec_attribs_t;
 /** Codec list declaration */
 typedef struct mpf_codec_list_t mpf_codec_list_t;
+/** Codec capabilities declaration */
+typedef struct mpf_codec_capabilities_t mpf_codec_capabilities_t;
 /** Codec frame declaration */
 typedef struct mpf_codec_frame_t mpf_codec_frame_t;
-/** Codec attributes declaration */
-typedef struct mpf_codec_attribs_t mpf_codec_attribs_t;
 
 
 /** Codec descriptor */
@@ -65,25 +70,19 @@ struct mpf_codec_descriptor_t {
        /** Channel count */
        apr_byte_t   channel_count;
        /** Codec dependent additional format */
-       const char  *format;
+       apt_str_t    format;
        /**  Enabled/disabled state */
        apt_bool_t   enabled;
 };
 
 /** List of codec descriptors */
 struct mpf_codec_list_t {
-       /** Dynamic array of mpf_codec_descriptor_t */
+       /** Dynamic array of codec descriptors (mpf_codec_descriptor_t) */
        apr_array_header_t     *descriptor_arr;
-       /** Preffered codec descriptor */
-       mpf_codec_descriptor_t *preffered;
-};
-
-/** Codec frame */
-struct mpf_codec_frame_t {
-       /** Raw buffer, which may contain encoded or decoded data */
-       void      *buffer;
-       /** Buffer size */
-       apr_size_t size;
+       /** Preffered primary (audio/video codec) descriptor from descriptor_arr */
+       mpf_codec_descriptor_t *primary_descriptor;
+       /** Preffered named event (telephone-event) descriptor from descriptor_arr */
+       mpf_codec_descriptor_t *event_descriptor;
 };
 
 /** Codec attributes */
@@ -91,11 +90,27 @@ struct mpf_codec_attribs_t {
        /** Codec name */
        apt_str_t  name;
        /** Bits per sample */
-       apr_byte_t bits_per_samples;
+       apr_byte_t bits_per_sample;
        /** Supported sampling rates (mpf_sample_rates_e) */
        int        sample_rates;
 };
 
+/** List of codec attributes (capabilities) */
+struct mpf_codec_capabilities_t {
+       /** Dynamic array of codec attributes (mpf_codec_attrribs_t) */
+       apr_array_header_t *attrib_arr;
+       /** Allow/support named events */
+       apt_bool_t          allow_named_events;
+};
+
+/** Codec frame */
+struct mpf_codec_frame_t {
+       /** Raw buffer, which may contain encoded or decoded data */
+       void      *buffer;
+       /** Buffer size */
+       apr_size_t size;
+};
+
 
 /** Initialize codec descriptor */
 static APR_INLINE void mpf_codec_descriptor_init(mpf_codec_descriptor_t *descriptor)
@@ -104,14 +119,22 @@ static APR_INLINE void mpf_codec_descriptor_init(mpf_codec_descriptor_t *descrip
        apt_string_reset(&descriptor->name);
        descriptor->sampling_rate = 0;
        descriptor->channel_count = 0;
-       descriptor->format = NULL;
+       apt_string_reset(&descriptor->format);
        descriptor->enabled = TRUE;
 }
 
+/** Initialize codec descriptor */
+static APR_INLINE  mpf_codec_descriptor_t* mpf_codec_descriptor_create(apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *descriptor = (mpf_codec_descriptor_t*) apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(descriptor);
+       return descriptor;
+}
+
 /** Calculate encoded frame size in bytes */
 static APR_INLINE apr_size_t mpf_codec_frame_size_calculate(const mpf_codec_descriptor_t *descriptor, const mpf_codec_attribs_t *attribs)
 {
-       return descriptor->channel_count * attribs->bits_per_samples * CODEC_FRAME_TIME_BASE * 
+       return descriptor->channel_count * attribs->bits_per_sample * CODEC_FRAME_TIME_BASE * 
                        descriptor->sampling_rate / 1000 / 8; /* 1000 - msec per sec, 8 - bits per byte */
 }
 
@@ -127,17 +150,22 @@ static APR_INLINE apr_size_t mpf_codec_linear_frame_size_calculate(apr_uint16_t
        return channel_count * BYTES_PER_SAMPLE * CODEC_FRAME_TIME_BASE * sampling_rate / 1000;
 }
 
+
+
 /** Reset list of codec descriptors */
 static APR_INLINE void mpf_codec_list_reset(mpf_codec_list_t *codec_list)
 {
        codec_list->descriptor_arr = NULL;
-       codec_list->preffered = NULL;
+       codec_list->primary_descriptor = NULL;
+       codec_list->event_descriptor = NULL;
 }
 
 /** Initialize list of codec descriptors */
 static APR_INLINE void mpf_codec_list_init(mpf_codec_list_t *codec_list, apr_size_t initial_count, apr_pool_t *pool)
 {
        codec_list->descriptor_arr = apr_array_make(pool,(int)initial_count, sizeof(mpf_codec_descriptor_t));
+       codec_list->primary_descriptor = NULL;
+       codec_list->event_descriptor = NULL;
 }
 
 /** Copy list of codec descriptors */
@@ -149,7 +177,7 @@ static APR_INLINE void mpf_codec_list_copy(mpf_codec_list_t *codec_list, const m
 /** Increment number of codec descriptors in the list and return the descriptor to fill */
 static APR_INLINE mpf_codec_descriptor_t* mpf_codec_list_add(mpf_codec_list_t *codec_list)
 {
-       mpf_codec_descriptor_tdescriptor = (mpf_codec_descriptor_t*)apr_array_push(codec_list->descriptor_arr);
+       mpf_codec_descriptor_t *descriptor = (mpf_codec_descriptor_t*)apr_array_push(codec_list->descriptor_arr);
        mpf_codec_descriptor_init(descriptor);
        return descriptor;
 }
@@ -161,20 +189,91 @@ static APR_INLINE apt_bool_t mpf_codec_list_is_empty(const mpf_codec_list_t *cod
 }
 
 /** Get codec descriptor by index */
-static APR_INLINE mpf_codec_descriptor_t* mpf_codec_get(const mpf_codec_list_t *codec_list, apr_size_t id)
+static APR_INLINE mpf_codec_descriptor_t* mpf_codec_list_descriptor_get(const mpf_codec_list_t *codec_list, apr_size_t id)
 {
-       mpf_codec_descriptor_t *descriptor;
        if(id >= (apr_size_t)codec_list->descriptor_arr->nelts) {
                return NULL;
        }
-       descriptor = (mpf_codec_descriptor_t*)codec_list->descriptor_arr->elts;
-       return descriptor + id;
+       return &APR_ARRAY_IDX(codec_list->descriptor_arr,id,mpf_codec_descriptor_t);
 }
 
+/** Create linear PCM descriptor */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_lpcm_descriptor_create(apr_uint16_t sampling_rate, apr_byte_t channel_count, apr_pool_t *pool);
+
+/** Create codec descriptor by capabilities */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_descriptor_create_by_capabilities(const mpf_codec_capabilities_t *capabilities, const mpf_codec_descriptor_t *peer, apr_pool_t *pool);
+
 /** Match two codec descriptors */
-MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2);
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptors_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2);
+
+/** Match specified codec descriptor and the default lpcm one */
+MPF_DECLARE(apt_bool_t) mpf_codec_lpcm_descriptor_match(const mpf_codec_descriptor_t *descriptor);
+
+/** Match codec descriptor by attribs specified */
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match_by_attribs(mpf_codec_descriptor_t *descriptor, const mpf_codec_descriptor_t *static_descriptor, const mpf_codec_attribs_t *attribs);
+
+
+
+/** Initialize codec capabilities */
+static APR_INLINE void mpf_codec_capabilities_init(mpf_codec_capabilities_t *capabilities, apr_size_t initial_count, apr_pool_t *pool)
+{
+       capabilities->attrib_arr = apr_array_make(pool,(int)initial_count, sizeof(mpf_codec_attribs_t));
+       capabilities->allow_named_events = TRUE;
+}
+
+/** Clone codec capabilities */
+static APR_INLINE void mpf_codec_capabilities_clone(mpf_codec_capabilities_t *capabilities, const mpf_codec_capabilities_t *src_capabilities, apr_pool_t *pool)
+{
+       capabilities->attrib_arr = apr_array_copy(pool,src_capabilities->attrib_arr);
+       capabilities->allow_named_events = src_capabilities->allow_named_events;
+}
+
+/** Merge codec capabilities */
+static APR_INLINE apt_bool_t mpf_codec_capabilities_merge(mpf_codec_capabilities_t *capabilities, const mpf_codec_capabilities_t *src_capabilities, apr_pool_t *pool)
+{
+       if(capabilities->allow_named_events == FALSE && src_capabilities->allow_named_events == TRUE) {
+               capabilities->allow_named_events = src_capabilities->allow_named_events;
+       }
+       capabilities->attrib_arr = apr_array_append(pool,capabilities->attrib_arr,src_capabilities->attrib_arr);
+       return TRUE;
+}
+
+/** Add codec capabilities */
+static APR_INLINE apt_bool_t mpf_codec_capabilities_add(mpf_codec_capabilities_t *capabilities, int sample_rates, const char *codec_name)
+{
+       mpf_codec_attribs_t *attribs = (mpf_codec_attribs_t*)apr_array_push(capabilities->attrib_arr);
+       apt_string_set(&attribs->name,codec_name);
+       attribs->sample_rates = sample_rates;
+       attribs->bits_per_sample = 0;
+       return TRUE;
+}
+
+/** Add default (liear PCM) capabilities */
+MPF_DECLARE(apt_bool_t) mpf_codec_default_capabilities_add(mpf_codec_capabilities_t *capabilities);
+
+/** Validate codec capabilities */
+static APR_INLINE apt_bool_t mpf_codec_capabilities_validate(mpf_codec_capabilities_t *capabilities)
+{
+       if(apr_is_empty_array(capabilities->attrib_arr) == TRUE) {
+               mpf_codec_default_capabilities_add(capabilities);
+       }
+       return TRUE;
+}
+
+
+
+/** Find matched descriptor in codec list */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_list_descriptor_find(const mpf_codec_list_t *codec_list, const mpf_codec_descriptor_t *descriptor);
+
+/** Modify codec list according to capabilities specified */
+MPF_DECLARE(apt_bool_t) mpf_codec_list_modify(mpf_codec_list_t *codec_list, const mpf_codec_capabilities_t *capabilities);
+
 /** Intersect two codec lists */
-MPF_DECLARE(apt_bool_t) mpf_codec_list_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2);
+MPF_DECLARE(apt_bool_t) mpf_codec_lists_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2);
+
+
+/** Get sampling rate mask (mpf_sample_rate_e) by integer value  */
+MPF_DECLARE(int) mpf_sample_rate_mask_get(apr_uint16_t sampling_rate);
 
 
 APT_END_EXTERN_C
index ec2fdd8d19bd0bc445656bf31d260a3f4266e5dd..2b14070b529f51b75e0c0dbc39a936acd8617e18 100644 (file)
@@ -39,9 +39,6 @@ MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_register(mpf_codec_manager_t *co
 /** Get (allocate) codec by codec descriptor */
 MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_codec_get(const mpf_codec_manager_t *codec_manager, mpf_codec_descriptor_t *descriptor, apr_pool_t *pool);
 
-/** Get (allocate) default codec */
-MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_default_codec_get(const mpf_codec_manager_t *codec_manager, apr_pool_t *pool);
-
 /** Get (allocate) list of available codecs */
 MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, apr_pool_t *pool);
 
index 49f99e27b13031e9a6ddfe9e5208fb45fbe2c495..d9a20bf9ad2ae4c2e1ad8ee3c4b7d4eb994cc30e 100644 (file)
  * @brief MPF Context
  */ 
 
-#include "mpf_object.h"
-#include "apt_obj_list.h"
+#include "mpf_types.h"
 
 APT_BEGIN_EXTERN_C
 
-/** Definition of table item used in context */
-typedef void* table_item_t;
+/** Opaque factory of media contexts */
+typedef struct mpf_context_factory_t mpf_context_factory_t;
+/**
+ * Create factory of media contexts.
+ */
+MPF_DECLARE(mpf_context_factory_t*) mpf_context_factory_create(apr_pool_t *pool); 
+
+/**
+ * Destroy factory of media contexts.
+ */
+MPF_DECLARE(void) mpf_context_factory_destroy(mpf_context_factory_t *factory); 
 
-/** Media processing context */
-struct mpf_context_t {
-    /** Pool to allocate memory from */
-       apr_pool_t        *pool;
-    /** External object */
-       void              *obj;
-    /** Set when context is addded to the list to ensure quick find on delete */
-       apt_list_elem_t   *elem;
+/**
+ * Process factory of media contexts.
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_factory_process(mpf_context_factory_t *factory);
 
-       /** Max number of terminations */
-       apr_size_t          max_termination_count;
-       /** Current number of terminations */
-       apr_size_t          termination_count;
-       /** Table, which holds terminations and topology */
-       table_item_t      **table;
-};
+/**
+ * Create MPF context.
+ * @param factory the factory context belongs to
+ * @param obj the external object associated with context
+ * @param max_termination_count the max number of terminations in context
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_context_t*) mpf_context_create(
+                                                               mpf_context_factory_t *factory, 
+                                                               void *obj, 
+                                                               apr_size_t max_termination_count, 
+                                                               apr_pool_t *pool);
 
+/**
+ * Destroy MPF context.
+ * @param context the context to destroy
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context);
+
+/**
+ * Get external object associated with MPF context.
+ * @param context the context to get object from
+ */
+MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context);
 
 /**
  * Add termination to context.
@@ -62,23 +83,43 @@ MPF_DECLARE(apt_bool_t) mpf_context_termination_add(mpf_context_t *context, mpf_
  */
 MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, mpf_termination_t *termination);
 
+/**
+ * Add association between specified terminations.
+ * @param context the context to add association in the scope of
+ * @param termination1 the first termination to associate
+ * @param termination2 the second termination to associate
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_association_add(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2);
+
+/**
+ * Remove association between specified terminations.
+ * @param context the context to remove association in the scope of
+ * @param termination1 the first termination
+ * @param termination2 the second termination
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_association_remove(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2);
+
+/**
+ * Reset assigned associations and destroy applied topology.
+ * @param context the context to reset associations for
+ */
+MPF_DECLARE(apt_bool_t) mpf_context_associations_reset(mpf_context_t *context);
+
 /**
  * Apply topology.
- * @param context the context which holds the termination
- * @param termination the termination to apply toplogy for
+ * @param context the context to apply topology for
  */
-MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context, mpf_termination_t *termination);
+MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context);
 
 /**
  * Destroy topology.
- * @param context the context which holds the termination
- * @param termination the termination to destroy toplogy for
+ * @param context the context to destroy topology for
  */
-MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context, mpf_termination_t *termination);
+MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context);
 
 /**
  * Process context.
- * @param context the context
+ * @param context the context to process
  */
 MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context);
 
index 0d40bd346c0349cddb1714ff35c144ca6938e32b..ea99db8ad1d3416ef1455791dac0315b89b6b4d2 100644 (file)
@@ -29,9 +29,10 @@ APT_BEGIN_EXTERN_C
 /**
  * Create audio stream decoder.
  * @param source the source to get encoded stream from
+ * @param codec the codec to use for decode
  * @param pool the pool to allocate memory from
  */
-MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, apr_pool_t *pool);
+MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, mpf_codec_t *codec, apr_pool_t *pool);
 
 
 APT_END_EXTERN_C
diff --git a/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h b/libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h
new file mode 100644 (file)
index 0000000..6c6d957
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2009 Tomas Valenta, 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_DTMF_DETECTOR_H__
+#define __MPF_DTMF_DETECTOR_H__
+
+/*
+ * @file mpf_dtmf_detector.h
+ * @brief DTMF detector
+ *
+ * Detector of DTMF tones sent both out-of-band (RFC4733) and in-band (audio).
+ */
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "apt.h"
+#include "mpf_frame.h"
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** DTMF detector band */
+typedef enum mpf_dtmf_detector_band_e {
+       /** Detect tones in-band */
+       MPF_DTMF_DETECTOR_INBAND  = 0x1,
+       /** Detect named events out-of-band */
+       MPF_DTMF_DETECTOR_OUTBAND = 0x2,
+       /** Detect both in-band and out-of-band digits */
+       MPF_DTMF_DETECTOR_BOTH = MPF_DTMF_DETECTOR_INBAND | MPF_DTMF_DETECTOR_OUTBAND
+} mpf_dtmf_detector_band_e;
+
+/** Opaque MPF DTMF detector structure definition */
+typedef struct mpf_dtmf_detector_t mpf_dtmf_detector_t;
+
+
+/**
+ * Create MPF DTMF detector (advanced).
+ * @param stream      A stream to get digits from.
+ * @param band        One of:
+ *   - MPF_DTMF_DETECTOR_INBAND: detect audible tones only
+ *   - MPF_DTMF_DETECTOR_OUTBAND: detect out-of-band named-events only
+ *   - MPF_DTMF_DETECTOR_BOTH: detect digits in both bands if supported by
+ *     stream. When out-of-band digit arrives, in-band detection is turned off.
+ * @param pool        Memory pool to allocate DTMF detector from.
+ * @return The object or NULL on error.
+ * @see mpf_dtmf_detector_create
+ */
+MPF_DECLARE(struct mpf_dtmf_detector_t *) mpf_dtmf_detector_create_ex(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               enum mpf_dtmf_detector_band_e band,
+                                                               struct apr_pool_t *pool);
+
+/**
+ * Create MPF DTMF detector (simple). Calls mpf_dtmf_detector_create_ex
+ * with band = MPF_DTMF_DETECTOR_BOTH if out-of-band supported by the stream,
+ * MPF_DTMF_DETECTOR_INBAND otherwise.
+ * @param stream      A stream to get digits from.
+ * @param pool        Memory pool to allocate DTMF detector from.
+ * @return The object or NULL on error.
+ * @see mpf_dtmf_detector_create_ex
+ */
+static APR_INLINE struct mpf_dtmf_detector_t *mpf_dtmf_detector_create(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               struct apr_pool_t *pool)
+{
+       return mpf_dtmf_detector_create_ex(stream,
+               stream->tx_event_descriptor ? MPF_DTMF_DETECTOR_BOTH : MPF_DTMF_DETECTOR_INBAND,
+               pool);
+}
+
+/**
+ * Get DTMF digit from buffer of digits detected so far and remove it.
+ * @param detector  The detector.
+ * @return DTMF character [0-9*#A-D] or NUL if the buffer is empty.
+ */
+MPF_DECLARE(char) mpf_dtmf_detector_digit_get(struct mpf_dtmf_detector_t *detector);
+
+/**
+ * Retrieve how many digits was lost due to full buffer.
+ * @param detector  The detector.
+ * @return Number of lost digits.
+ */
+MPF_DECLARE(apr_size_t) mpf_dtmf_detector_digits_lost(const struct mpf_dtmf_detector_t *detector);
+
+/**
+ * Empty the buffer and reset detection states.
+ * @param detector  The detector.
+ */
+MPF_DECLARE(void) mpf_dtmf_detector_reset(struct mpf_dtmf_detector_t *detector);
+
+/**
+ * Detect DTMF digits in the frame.
+ * @param detector  The detector.
+ * @param frame     Frame object passed in stream_write().
+ */
+MPF_DECLARE(void) mpf_dtmf_detector_get_frame(
+                                                               struct mpf_dtmf_detector_t *detector,
+                                                               const struct mpf_frame_t *frame);
+
+/**
+ * Free all resources associated with the detector.
+ * @param detector  The detector.
+ */
+MPF_DECLARE(void) mpf_dtmf_detector_destroy(struct mpf_dtmf_detector_t *detector);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_DTMF_DETECTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h b/libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h
new file mode 100644 (file)
index 0000000..e5c8548
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2009 Tomas Valenta, 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_DTMF_GENERATOR_H__
+#define __MPF_DTMF_GENERATOR_H__
+
+/*
+ * @file mpf_named_event.h
+ * @brief DTMF generator
+ *
+ * Generator used to send DTMF tones. Capable to send digits
+ * either in-band as audible tones or out-of-band according
+ * to RFC4733.
+ */
+
+#include "apr_pools.h"
+#include "apt.h"
+#include "mpf_frame.h"
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** DTMF generator band */
+typedef enum mpf_dtmf_generator_band_e {
+       /** Generate tones in-band */
+       MPF_DTMF_GENERATOR_INBAND  = 0x1,
+       /** Generate named events out-of-band */
+       MPF_DTMF_GENERATOR_OUTBAND = 0x2,
+       /** Generate both tones and named events */
+       MPF_DTMF_GENERATOR_BOTH = MPF_DTMF_GENERATOR_INBAND | MPF_DTMF_GENERATOR_OUTBAND
+} mpf_dtmf_generator_band_e;
+
+/** Opaque MPF DTMF generator structure definition */
+typedef struct mpf_dtmf_generator_t mpf_dtmf_generator_t;
+
+
+/**
+ * Create MPF DTMF generator (advanced).
+ * @param stream      A stream to transport digits via.
+ * @param band        MPF_DTMF_GENERATOR_INBAND or MPF_DTMF_GENERATOR_OUTBAND
+ * @param tone_ms     Tone duration in milliseconds.
+ * @param silence_ms  Inter-digit silence in milliseconds.
+ * @param pool        Memory pool to allocate DTMF generator from.
+ * @return The object or NULL on error.
+ * @see mpf_dtmf_generator_create
+ */
+MPF_DECLARE(struct mpf_dtmf_generator_t *) mpf_dtmf_generator_create_ex(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               enum mpf_dtmf_generator_band_e band,
+                                                               apr_size_t tone_ms,
+                                                               apr_size_t silence_ms,
+                                                               struct apr_pool_t *pool);
+
+/**
+ * Create MPF DTMF generator (simple). Calls mpf_dtmf_generator_create_ex
+ * with band = MPF_DTMF_GENERATOR_OUTBAND if supported by the stream or
+ * MPF_DTMF_GENERATOR_INBAND otherwise, tone_ms = 70, silence_ms = 50.
+ * @param stream      A stream to transport digits via.
+ * @param pool        Memory pool to allocate DTMF generator from.
+ * @return The object or NULL on error.
+ * @see mpf_dtmf_generator_create_ex
+ */
+static APR_INLINE struct mpf_dtmf_generator_t *mpf_dtmf_generator_create(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               struct apr_pool_t *pool)
+{
+       return mpf_dtmf_generator_create_ex(stream,
+               stream->rx_event_descriptor ? MPF_DTMF_GENERATOR_OUTBAND : MPF_DTMF_GENERATOR_INBAND,
+               70, 50, pool);
+}
+
+/**
+ * Add DTMF digits to the queue.
+ * @param generator The generator.
+ * @param digits    DTMF character sequence [0-9*#A-D].
+ * @return TRUE if ok, FALSE if there are too many digits.
+ */
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_enqueue(
+                                                               struct mpf_dtmf_generator_t *generator,
+                                                               const char *digits);
+
+/**
+ * Empty the queue and immediately stop generating.
+ * @param generator The generator.
+ */
+MPF_DECLARE(void) mpf_dtmf_generator_reset(struct mpf_dtmf_generator_t *generator);
+
+/**
+ * Check state of the generator.
+ * @param generator The generator.
+ * @return TRUE if generating a digit or there are digits waiting in queue.
+ * FALSE if the queue is empty or generating silence after the last digit.
+ */
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_sending(const struct mpf_dtmf_generator_t *generator);
+
+/**
+ * Put frame into the stream.
+ * @param generator The generator.
+ * @param frame     Frame object passed in stream_read().
+ * @return TRUE if frame with tone (both in-band and out-of-band) was generated,
+ * FALSE otherwise. In contrast to mpf_dtmf_generator_sending, returns FALSE even
+ * if generating inter-digit silence. In other words returns TRUE iff the frame
+ * object was filled with data. This method MUST be called for each frame for
+ * proper timing.
+ */
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_put_frame(
+                                                               struct mpf_dtmf_generator_t *generator,
+                                                               struct mpf_frame_t *frame);
+
+/**
+ * Free all resources associated with the generator.
+ * @param generator The generator.
+ */
+MPF_DECLARE(void) mpf_dtmf_generator_destroy(struct mpf_dtmf_generator_t *generator);
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_DTMF_GENERATOR_H__*/
index 36a819da6ab15360e171fd38c8c98e359cbefef0..529f9a0b7e01901a8fbde8d74c0546327252ccf1 100644 (file)
@@ -29,9 +29,10 @@ APT_BEGIN_EXTERN_C
 /**
  * Create audio stream encoder.
  * @param sink the sink to write encoded stream to
+ * @param codec the codec to use for encode
  * @param pool the pool to allocate memory from
  */
-MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, apr_pool_t *pool);
+MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, mpf_codec_t *codec, apr_pool_t *pool);
 
 
 APT_END_EXTERN_C
index d1d38a61ea564a550cb821d0fb2a51edc7feb0e4..e784d07d6c3a53808740dc46e220fcdd41bd3f41 100644 (file)
 
 APT_BEGIN_EXTERN_C
 
+/** MPF task message definition */
+typedef apt_task_msg_t mpf_task_msg_t;
+
 /**
  * Create MPF engine.
+ * @param rate the rate (n times faster than real-time)
  * @param pool the pool to allocate memory from
  */
-MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool);
+MPF_DECLARE(mpf_engine_t*) mpf_engine_create(unsigned long rate, apr_pool_t *pool);
 
 /**
  * Create MPF codec manager.
@@ -46,6 +50,31 @@ MPF_DECLARE(mpf_codec_manager_t*) mpf_engine_codec_manager_create(apr_pool_t *po
  */
 MPF_DECLARE(apt_bool_t) mpf_engine_codec_manager_register(mpf_engine_t *engine, const mpf_codec_manager_t *codec_manager);
 
+/**
+ * Create MPF context.
+ * @param engine the engine to create context for
+ * @param obj the external object associated with context
+ * @param max_termination_count the max number of terminations in context
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_context_t*) mpf_engine_context_create(
+                                                               mpf_engine_t *engine, 
+                                                               void *obj, 
+                                                               apr_size_t max_termination_count, 
+                                                               apr_pool_t *pool);
+
+/**
+ * Destroy MPF context.
+ * @param context the context to destroy
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_context_destroy(mpf_context_t *context);
+
+/**
+ * Get external object associated with MPF context.
+ * @param context the context to get object from
+ */
+MPF_DECLARE(void*) mpf_engine_context_object_get(mpf_context_t *context);
+
 /**
  * Get task.
  * @param engine the engine to get task from
@@ -59,6 +88,60 @@ MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine);
  */
 MPF_DECLARE(void) mpf_engine_task_msg_type_set(mpf_engine_t *engine, apt_task_msg_type_e type);
 
+/**
+ * Create task message(if not created) and add MPF termination message to it.
+ * @param engine the engine task message belongs to
+ * @param command_id the MPF command identifier
+ * @param context the context to add termination to
+ * @param termination the termination to add
+ * @param descriptor the termination dependent descriptor
+ * @param task_msg the task message to create and add constructed MPF message to
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_termination_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_termination_t *termination,
+                                                       void *descriptor,
+                                                       mpf_task_msg_t **task_msg);
+
+/**
+ * Create task message(if not created) and add MPF association message to it.
+ * @param engine the engine task message belongs to
+ * @param command_id the MPF command identifier
+ * @param context the context to add association of terminations for
+ * @param termination the termination to associate
+ * @param assoc_termination the termination to associate
+ * @param task_msg the task message to create and add constructed MPF message to
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_assoc_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_termination_t *termination,
+                                                       mpf_termination_t *assoc_termination,
+                                                       mpf_task_msg_t **task_msg);
+
+/**
+ * Create task message(if not created) and add MPF topology message to it.
+ * @param engine the engine task message belongs to
+ * @param command_id the MPF command identifier
+ * @param context the context to modify topology for
+ * @param task_msg the task message to create and add constructed MPF message to
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_topology_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_task_msg_t **task_msg);
+
+/**
+ * Send MPF task message.
+ * @param engine the engine to send task message to
+ * @param task_msg the task message to send
+ */
+MPF_DECLARE(apt_bool_t) mpf_engine_message_send(mpf_engine_t *engine, mpf_task_msg_t **task_msg);
+
 
 APT_END_EXTERN_C
 
index f8243280392458f3adcc8b8d189670b4608c143b..df8a05abd7de758c5329ee7bf5c1eaffb6d821c1 100644 (file)
@@ -22,7 +22,7 @@
  * @brief MPF File Termination Factory
  */ 
 
-#include "mpf_types.h"
+#include "mpf_termination_factory.h"
 
 APT_BEGIN_EXTERN_C
 
index b1c8c438ac6e02c3ef23cbeced137fb7cf03eaff..3abba6e28290044adf7c7126e83457889c678399 100644 (file)
@@ -23,6 +23,7 @@
  */ 
 
 #include "mpf_codec_descriptor.h"
+#include "mpf_named_event.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -31,42 +32,26 @@ typedef enum {
        MEDIA_FRAME_TYPE_NONE  = 0x0, /**< none */
        MEDIA_FRAME_TYPE_AUDIO = 0x1, /**< audio frame */
        MEDIA_FRAME_TYPE_VIDEO = 0x2, /**< video frame */
-       MEDIA_FRAME_TYPE_EVENT = 0x4  /**< named event frame (RFC2833) */
+       MEDIA_FRAME_TYPE_EVENT = 0x4  /**< named event frame (RFC4733/RFC2833) */
 } mpf_frame_type_e;
 
-/** Named event declaration */
-typedef struct mpf_named_event_frame_t mpf_named_event_frame_t;
+/** Media frame marker */
+typedef enum {
+       MPF_MARKER_NONE,           /**< none */
+       MPF_MARKER_START_OF_EVENT, /**< start of event */
+       MPF_MARKER_END_OF_EVENT,   /**< end of event */
+       MPF_MARKER_NEW_SEGMENT,    /**< start of new segment (long-lasting events) */
+} mpf_frame_marker_e;
+
 /** Media frame declaration */
 typedef struct mpf_frame_t mpf_frame_t;
 
-
-/** Named event (RFC2833, out-of-band DTMF) */
-struct mpf_named_event_frame_t {
-       /** event (DTMF, tone) identifier */
-       apr_uint32_t event_id: 8;
-#if (APR_IS_BIGENDIAN == 1)
-       /** end of event */
-       apr_uint32_t edge:     1;
-       /** reserved */
-       apr_uint32_t reserved: 1;
-       /** tone volume */
-       apr_uint32_t volume:   6;
-#else
-       /** tone volume */
-       apr_uint32_t volume:   6;
-       /** reserved */
-       apr_uint32_t reserved: 1;
-       /** end of event */
-       apr_uint32_t edge:     1;
-#endif
-       /** event duration */
-       apr_uint32_t duration: 16;
-};
-
 /** Media frame */
 struct mpf_frame_t {
        /** frame type (audio/video/named-event) mpf_frame_type_e */
        int                     type;
+       /** frame marker (start-of-event,end-of-event) mpf_frame_marker_e */
+       int                     marker;
        /** codec frame */
        mpf_codec_frame_t       codec_frame;
        /** named-event frame */
index d6384398242d43590d3a884a3395e4410a103336..a4cb4c8ba26099f53b46662783adb92e7abc6063 100644 (file)
@@ -41,7 +41,7 @@ typedef struct mpf_jitter_buffer_t mpf_jitter_buffer_t;
 
 
 /** Create jitter buffer */
-mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_t *codec, apr_pool_t *pool);
+mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_descriptor_t *descriptor, mpf_codec_t *codec, apr_pool_t *pool);
 
 /** Destroy jitter buffer */
 void mpf_jitter_buffer_destroy(mpf_jitter_buffer_t *jb);
@@ -50,10 +50,10 @@ void mpf_jitter_buffer_destroy(mpf_jitter_buffer_t *jb);
 apt_bool_t mpf_jitter_buffer_restart(mpf_jitter_buffer_t *jb);
 
 /** Write audio data to jitter buffer */
-jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, mpf_codec_t *codec, void *buffer, apr_size_t size, apr_uint32_t ts);
+jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, void *buffer, apr_size_t size, apr_uint32_t ts);
 
 /** Write named event to jitter buffer */
-jb_result_t mpf_jitter_buffer_write_named_event(mpf_jitter_buffer_t *jb, mpf_named_event_frame_t *named_event, apr_uint32_t ts);
+jb_result_t mpf_jitter_buffer_event_write(mpf_jitter_buffer_t *jb, const mpf_named_event_frame_t *named_event, apr_uint32_t ts, apr_byte_t marker);
 
 /** Read media frame from jitter buffer */
 apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_frame);
diff --git a/libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_media_descriptor.h
deleted file mode 100644 (file)
index af54224..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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_MEDIA_DESCRIPTOR_H__
-#define __MPF_MEDIA_DESCRIPTOR_H__
-
-/**
- * @file mpf_media_descriptor.h
- * @brief Media Descriptor Base
- */ 
-
-#include <apr_network_io.h>
-#include "apt_string.h"
-
-APT_BEGIN_EXTERN_C
-
-/** MPF media state */
-typedef enum {
-       MPF_MEDIA_DISABLED, /**< disabled media */
-       MPF_MEDIA_ENABLED   /**< enabled media */
-} mpf_media_state_e;
-
-/** MPF media descriptor declaration */
-typedef struct mpf_media_descriptor_t mpf_media_descriptor_t;
-
-/** MPF media descriptor */
-struct mpf_media_descriptor_t {
-       /** Media state (disabled/enabled)*/
-       mpf_media_state_e state;
-
-       /** Ip address */
-       apt_str_t          ip;
-       /** External (NAT) Ip address */
-       apt_str_t          ext_ip;
-       /** Port */
-       apr_port_t         port;
-       /** Identifier (0,1,...) */
-       apr_size_t         id;
-};
-
-/** Initialize MPF media descriptor */
-static APR_INLINE void mpf_media_descriptor_init(mpf_media_descriptor_t *descriptor)
-{
-       descriptor->state = MPF_MEDIA_DISABLED;
-       apt_string_reset(&descriptor->ip);
-       apt_string_reset(&descriptor->ext_ip);
-       descriptor->port = 0;
-       descriptor->id = 0;
-}
-
-APT_END_EXTERN_C
-
-#endif /*__MPF_MEDIA_DESCRIPTOR_H__*/
index ae69638519eae6d211ce05f2f552c5b1fb6c40d6..601b306a9e703fe34c4a675d8d2277daef405b9d 100644 (file)
@@ -26,6 +26,9 @@
 
 APT_BEGIN_EXTERN_C
 
+/** Max number of messages grouped in a container */
+#define MAX_MPF_MESSAGE_COUNT 5
+
 /** Enumeration of MPF message types */
 typedef enum {
        MPF_MESSAGE_TYPE_REQUEST,  /**< request message */
@@ -40,16 +43,22 @@ typedef enum {
 } mpf_status_code_e;
 
 
-/** Enumeration of commands */
+/** Enumeration of MPF commands */
 typedef enum {
-       MPF_COMMAND_ADD,     /**< add termination to context */
-       MPF_COMMAND_MODIFY,  /**< modify termination properties */
-       MPF_COMMAND_SUBTRACT,/**< subtract termination from context */ 
-       MPF_COMMAND_MOVE     /**< move termination to another context */
+       MPF_ADD_TERMINATION,     /**< add termination to context */
+       MPF_MODIFY_TERMINATION,  /**< modify termination properties */
+       MPF_SUBTRACT_TERMINATION,/**< subtract termination from context */
+       MPF_ADD_ASSOCIATION,     /**< add association between terminations */
+       MPF_REMOVE_ASSOCIATION,  /**< remove association between terminations */
+       MPF_RESET_ASSOCIATIONS,  /**< reset associations among terminations (also destroy topology) */
+       MPF_APPLY_TOPOLOGY,      /**< apply topology based on assigned associations */
+       MPF_DESTROY_TOPOLOGY     /**< destroy applied topology */
 } mpf_command_type_e;
 
 /** MPF message declaration */
 typedef struct mpf_message_t mpf_message_t;
+/** MPF message container declaration */
+typedef struct mpf_message_container_t mpf_message_container_t;
 
 /** MPF message definition */
 struct mpf_message_t {
@@ -64,10 +73,20 @@ struct mpf_message_t {
        mpf_context_t     *context;
        /** Termination */
        mpf_termination_t *termination;
+       /** Associated termination */
+       mpf_termination_t *assoc_termination;
        /** Termination type dependent descriptor */
        void              *descriptor;
 };
 
+/** MPF message container definition */
+struct mpf_message_container_t {
+       /** Number of actual messages */
+       apr_size_t    count;
+       /** Array of messages */
+       mpf_message_t messages[MAX_MPF_MESSAGE_COUNT];
+};
+
 APT_END_EXTERN_C
 
 #endif /*__MPF_MESSAGE_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_mixer.h b/libs/unimrcp/libs/mpf/include/mpf_mixer.h
new file mode 100644 (file)
index 0000000..fa48f5b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_MIXER_H__
+#define __MPF_MIXER_H__
+
+/**
+ * @file mpf_mixer.h
+ * @brief MPF Stream Mixer (n-sources, 1-sink)
+ */ 
+
+#include "mpf_object.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create audio stream mixer.
+ * @param source_arr the array of audio sources
+ * @param source_count the number of audio sources
+ * @param sink the audio sink
+ * @param codec_manager the codec manager
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_object_t*) mpf_mixer_create(
+                                                               mpf_audio_stream_t **source_arr, 
+                                                               apr_size_t source_count, 
+                                                               mpf_audio_stream_t *sink, 
+                                                               const mpf_codec_manager_t *codec_manager,
+                                                               apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_MIXER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_multiplier.h b/libs/unimrcp/libs/mpf/include/mpf_multiplier.h
new file mode 100644 (file)
index 0000000..380d5b5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_MULTIPLIER_H__
+#define __MPF_MULTIPLIER_H__
+
+/**
+ * @file mpf_multiplier.h
+ * @brief MPF Stream Multiplier (1-source, n-sinks)
+ */ 
+
+#include "mpf_object.h"
+
+APT_BEGIN_EXTERN_C
+
+/**
+ * Create audio stream multiplier.
+ * @param source the audio source
+ * @param sink_arr the array of audio sinks
+ * @param sink_count the number of audio sinks
+ * @param codec_manager the codec manager
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_object_t*) mpf_multiplier_create(
+                                                               mpf_audio_stream_t *source,
+                                                               mpf_audio_stream_t **sink_arr,
+                                                               apr_size_t sink_count,
+                                                               const mpf_codec_manager_t *codec_manager,
+                                                               apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_MULTIPLIER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_named_event.h b/libs/unimrcp/libs/mpf/include/mpf_named_event.h
new file mode 100644 (file)
index 0000000..d8d4dc6
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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_NAMED_EVENT_H__
+#define __MPF_NAMED_EVENT_H__
+
+/**
+ * @file mpf_named_event.h
+ * @brief MPF Named Events (RFC4733/RFC2833)
+ */ 
+
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Named event declaration */
+typedef struct mpf_named_event_frame_t mpf_named_event_frame_t;
+
+
+/** Named event (RFC4733/RFC2833, out-of-band DTMF) */
+struct mpf_named_event_frame_t {
+       /** event (DTMF, tone) identifier */
+       apr_uint32_t event_id: 8;
+#if (APR_IS_BIGENDIAN == 1)
+       /** end of event */
+       apr_uint32_t edge:     1;
+       /** reserved */
+       apr_uint32_t reserved: 1;
+       /** tone volume */
+       apr_uint32_t volume:   6;
+#else
+       /** tone volume */
+       apr_uint32_t volume:   6;
+       /** reserved */
+       apr_uint32_t reserved: 1;
+       /** end of event */
+       apr_uint32_t edge:     1;
+#endif
+       /** event duration */
+       apr_uint32_t duration: 16;
+};
+
+/** Create named event descriptor */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_event_descriptor_create(apr_uint16_t sampling_rate, apr_pool_t *pool);
+
+/** Check whether the specified descriptor is named event one */
+MPF_DECLARE(apt_bool_t) mpf_event_descriptor_check(const mpf_codec_descriptor_t *descriptor);
+
+/** Convert DTMF character to event identifier */
+MPF_DECLARE(apr_uint32_t) mpf_dtmf_char_to_event_id(const char dtmf_char);
+
+/** Convert event identifier to DTMF character */
+MPF_DECLARE(char) mpf_event_id_to_dtmf_char(const apr_uint32_t event_id);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_NAMED_EVENT_H__*/
index f4136b0ed23d454266b399cd0e12b4552c0d53d4..8e3e4eee95350d471e418f044a9e0944f0c6ab33 100644 (file)
  */ 
 
 #include "mpf_types.h"
-#include "mpf_frame.h"
 
 APT_BEGIN_EXTERN_C
 
 /** MPF object declaration */
 typedef struct mpf_object_t mpf_object_t;
 
-/** Base for media processing objects */
+/** Media processing objects base */
 struct mpf_object_t {
-       /** Audio stream source */
-       mpf_audio_stream_t *source;
-       /** Audio stream sink */
-       mpf_audio_stream_t *sink;
-
-       /** Media frame used to read data from source and write it to sink */
-       mpf_frame_t         frame;
-
-       /** Virtual process */
-       apt_bool_t (*process)(mpf_object_t *object);
        /** Virtual destroy */
        apt_bool_t (*destroy)(mpf_object_t *object);
+       /** Virtual process */
+       apt_bool_t (*process)(mpf_object_t *object);
+       /** Virtual trace of media path */
+       void (*trace)(mpf_object_t *object);
 };
 
+/** Initialize object */
+static APR_INLINE void mpf_object_init(mpf_object_t *object)
+{
+       object->destroy = NULL;
+       object->process = NULL;
+       object->trace = NULL;
+}
+
+/** Destroy object */
+static APR_INLINE void mpf_object_destroy(mpf_object_t *object)
+{
+       if(object->destroy)
+               object->destroy(object);
+}
+
+/** Process object */
+static APR_INLINE void mpf_object_process(mpf_object_t *object)
+{
+       if(object->process)
+               object->process(object);
+}
+
+/** Trace media path */
+static APR_INLINE void mpf_object_trace(mpf_object_t *object)
+{
+       if(object->trace)
+               object->trace(object);
+}
+
 
 APT_END_EXTERN_C
 
similarity index 54%
rename from libs/unimrcp/libs/mpf/include/mpf_timer.h
rename to libs/unimrcp/libs/mpf/include/mpf_resampler.h
index a58af07f50af0034c864daa33c70b21db0ce9f10..d674336139f338de79ea74787b5ea8a36324ea4f 100644 (file)
  * limitations under the License.
  */
 
-#ifndef __MPF_TIMER_H__
-#define __MPF_TIMER_H__
+#ifndef __MPF_RESAMPLER_H__
+#define __MPF_RESAMPLER_H__
 
 /**
- * @file mpf_timer.h
- * @brief MPF High Resolution Timer
+ * @file mpf_resampler.h
+ * @brief MPF Stream Resampler
  */ 
 
-#include "mpf.h"
+#include "mpf_stream.h"
 
 APT_BEGIN_EXTERN_C
 
-/** Opaque MPF timer declaration */
-typedef struct mpf_timer_t mpf_timer_t;
-
-/** Prototype of timer callback */
-typedef void (*mpf_timer_proc_f)(mpf_timer_t *timer, void *obj);
-
-/** Start periodic timer */
-MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool);
-
-/** Stop timer */
-MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer);
+/**
+ * Create audio stream resampler.
+ * @param source the source stream to resample
+ * @param sink the sink stream to resample to
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_resampler_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool);
 
 
 APT_END_EXTERN_C
 
-#endif /*__MPF_TIMER_H__*/
+#endif /*__MPF_RESAMPLER_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h b/libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h
new file mode 100644 (file)
index 0000000..b43e4a1
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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_RTCP_PACKET_H__
+#define __MPF_RTCP_PACKET_H__
+
+/**
+ * @file mpf_rtcp_packet.h
+ * @brief RTCP Packet Definition
+ */ 
+
+#include "mpf_rtp_stat.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** RTCP payload (packet) types */
+typedef enum {
+       RTCP_SR   = 200,
+       RTCP_RR   = 201,
+       RTCP_SDES = 202,
+       RTCP_BYE  = 203,
+       RTCP_APP  = 204
+} rtcp_type_e;
+
+/** RTCP SDES types */
+typedef enum {
+       RTCP_SDES_END   = 0,
+       RTCP_SDES_CNAME = 1,
+       RTCP_SDES_NAME  = 2,
+       RTCP_SDES_EMAIL = 3,
+       RTCP_SDES_PHONE = 4,
+       RTCP_SDES_LOC   = 5,
+       RTCP_SDES_TOOL  = 6,
+       RTCP_SDES_NOTE  = 7,
+       RTCP_SDES_PRIV  = 8
+} rtcp_sdes_type_e;
+
+/** RTCP header declaration */
+typedef struct rtcp_header_t rtcp_header_t;
+/** RTCP packet declaration */
+typedef struct rtcp_packet_t rtcp_packet_t;
+/** SDES item declaration*/
+typedef struct rtcp_sdes_item_t rtcp_sdes_item_t;
+
+
+/** RTCP header */
+struct rtcp_header_t {
+#if (APR_IS_BIGENDIAN == 1)
+       /** protocol version */
+       unsigned int version: 2;
+       /** padding flag */
+       unsigned int padding: 1;
+       /** varies by packet type */
+       unsigned int count:   5;
+       /** packet type */
+       unsigned int pt:      8;
+#else
+       /** varies by packet type */
+       unsigned int count:   5;
+       /** padding flag */
+       unsigned int padding: 1;
+       /** protocol version */
+       unsigned int version: 2;
+       /** packet type */
+       unsigned int pt:      8;
+#endif 
+       
+       /** packet length in words, w/o this word */
+       unsigned int length:  16;
+};
+
+/** SDES item */
+struct rtcp_sdes_item_t {
+       /** type of item (rtcp_sdes_type_t) */
+       apr_byte_t type;
+       /* length of item (in octets) */
+       apr_byte_t length;
+       /* text, not null-terminated */
+       char       data[1];
+};
+
+/** RTCP packet */
+struct rtcp_packet_t {
+       /** common header */
+       rtcp_header_t header;
+       union {
+               /** sender report (SR) */
+               struct {
+                       /** sr stat */
+                       rtcp_sr_stat_t sr_stat;
+                       /** variable-length list rr stats */
+                       rtcp_rr_stat_t rr_stat[1];
+               } sr;
+
+               /** reception report (RR) */
+               struct {
+                       /** receiver generating this report */
+                       apr_uint32_t   ssrc;
+                       /** variable-length list rr stats */
+                       rtcp_rr_stat_t rr_stat[1];
+               } rr;
+
+               /** source description (SDES) */
+               struct {
+                       /** first SSRC/CSRC */
+                       apr_uint32_t     ssrc;
+                       /** list of SDES items */
+                       rtcp_sdes_item_t item[1];
+               } sdes;
+
+               /** BYE */
+               struct {
+                       /** list of sources */
+                       apr_uint32_t ssrc[1];
+                       /* optional length of reason string (in octets) */
+                       apr_byte_t   length;
+                       /* optional reason string, not null-terminated */
+                       char         data[1];
+               } bye;
+       } r;
+};
+
+/** Initialize RTCP header */
+static APR_INLINE void rtcp_header_init(rtcp_header_t *header, rtcp_type_e pt)
+{
+       header->version = RTP_VERSION;
+       header->padding = 0;
+       header->count = 0;
+       header->pt = pt;
+       header->length = 0;
+}
+
+static APR_INLINE void rtcp_header_length_set(rtcp_header_t *header, apr_size_t length)
+{
+       header->length = htons((apr_uint16_t)length / 4 - 1);
+}
+
+static APR_INLINE void rtcp_sr_hton(rtcp_sr_stat_t *sr_stat)
+{
+       sr_stat->ssrc = htonl(sr_stat->ssrc);
+       sr_stat->ntp_sec = htonl(sr_stat->ntp_sec);
+       sr_stat->ntp_frac = htonl(sr_stat->ntp_frac);
+       sr_stat->rtp_ts = htonl(sr_stat->rtp_ts);
+       sr_stat->sent_packets = htonl(sr_stat->sent_packets);
+       sr_stat->sent_octets = htonl(sr_stat->sent_octets);
+}
+
+static APR_INLINE void rtcp_sr_ntoh(rtcp_sr_stat_t *sr_stat)
+{
+       sr_stat->ssrc = ntohl(sr_stat->ssrc);
+       sr_stat->ntp_sec = ntohl(sr_stat->ntp_sec);
+       sr_stat->ntp_frac = ntohl(sr_stat->ntp_frac);
+       sr_stat->rtp_ts = ntohl(sr_stat->rtp_ts);
+       sr_stat->sent_packets = ntohl(sr_stat->sent_packets);
+       sr_stat->sent_octets = ntohl(sr_stat->sent_octets);
+}
+
+static APR_INLINE void rtcp_rr_hton(rtcp_rr_stat_t *rr_stat)
+{
+       rr_stat->ssrc = htonl(rr_stat->ssrc);
+       rr_stat->last_seq =     htonl(rr_stat->last_seq);
+       rr_stat->jitter = htonl(rr_stat->jitter);
+
+#if (APR_IS_BIGENDIAN == 0)
+       rr_stat->lost = ((rr_stat->lost >> 16) & 0x000000ff) |
+                                               (rr_stat->lost & 0x0000ff00) |
+                                                       ((rr_stat->lost << 16) & 0x00ff0000);
+#endif
+}
+
+static APR_INLINE void rtcp_rr_ntoh(rtcp_rr_stat_t *rr_stat)
+{
+       rr_stat->ssrc = ntohl(rr_stat->ssrc);
+       rr_stat->last_seq =     ntohl(rr_stat->last_seq);
+       rr_stat->jitter = ntohl(rr_stat->jitter);
+
+#if (APR_IS_BIGENDIAN == 0)
+       rr_stat->lost = ((rr_stat->lost >> 16) & 0x000000ff) |
+                                               (rr_stat->lost & 0x0000ff00) |
+                                                       ((rr_stat->lost << 16) & 0x00ff0000);
+#endif
+}
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTCP_PACKET_H__*/
index 5fe3d9606738e25edd2cfb42bd50eeebd364b34e..dbce6b706fd6850d33a93b8f385d8912885a2fdd 100644 (file)
@@ -22,8 +22,7 @@
  * @brief RTP Attributes (SDP)
  */ 
 
-#include "mpf_media_descriptor.h"
-#include "mpf_stream_mode.h"
+#include "mpf_rtp_descriptor.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -47,8 +46,8 @@ MPF_DECLARE(const apt_str_t*) mpf_rtp_attrib_str_get(mpf_rtp_attrib_e attrib_id)
 /** Find audio media attribute identifier by attribute name */
 MPF_DECLARE(mpf_rtp_attrib_e) mpf_rtp_attrib_id_find(const apt_str_t *attrib);
 
-/** Get string by stream mode (send/receive) */
-MPF_DECLARE(const apt_str_t*) mpf_stream_mode_str_get(mpf_stream_mode_e direction);
+/** Get string by RTP direction (send/receive) */
+MPF_DECLARE(const apt_str_t*) mpf_rtp_direction_str_get(mpf_stream_direction_e direction);
 
 APT_END_EXTERN_C
 
index 9fc7925fc7d0e16eeab64fa9d2e2a66f89f63e17..883a1f589632f16485c914f0f58763db348eaa60 100644 (file)
@@ -41,56 +41,58 @@ APT_BEGIN_EXTERN_C
 /** Deviation threshold is used to trigger drift in timestamps */
 #define DEVIATION_THRESHOLD 4000
 
-/** RTP receive history declaration */
+/** RTP receiver history declaration */
 typedef struct rtp_rx_history_t rtp_rx_history_t;
-/** RTP receive periodic history declaration */
+/** RTP receiver periodic history declaration */
 typedef struct rtp_rx_periodic_history_t rtp_rx_periodic_history_t;
 /** RTP receiver declaration */
 typedef struct rtp_receiver_t rtp_receiver_t;
 /** RTP transmitter declaration */
 typedef struct rtp_transmitter_t rtp_transmitter_t;
 
-/** History of RTP receive */
+/** History of RTP receiver */
 struct rtp_rx_history_t {
-       /** Updated on every seq num wrap around*/
-       apr_uint32_t           seq_cycles;
+       /** Updated on every seq num wrap around */
+       apr_uint32_t seq_cycles;
 
        /** First seq num received */
-       apr_uint16_t           seq_num_base;
+       apr_uint16_t seq_num_base;
        /** Max seq num received */
-       apr_uint16_t           seq_num_max;
+       apr_uint16_t seq_num_max;
 
        /** Last timestamp received */
-       apr_uint32_t           ts_last;
+       apr_uint32_t ts_last;
        /** Local time measured on last packet received */
-       apr_time_t             time_last;
+       apr_time_t   time_last;
 
        /** New ssrc, which is in probation */
-       apr_uint32_t           ssrc_new;
+       apr_uint32_t ssrc_new;
        /** Period of ssrc probation */
-       apr_byte_t             ssrc_probation;
+       apr_byte_t   ssrc_probation;
 };
 
-/** Periodic history of RTP receive (initialized after every N packets) */
+/** Periodic history of RTP receiver (initialized after every N packets) */
 struct rtp_rx_periodic_history_t {
        /** Number of packets received */
-       apr_uint32_t           received_prior;
+       apr_uint32_t received_prior;
+       /** Number of packets expected */
+       apr_uint32_t expected_prior;
        /** Number of packets discarded */
-       apr_uint32_t           discarded_prior;
+       apr_uint32_t discarded_prior;
 
        /** Min jitter */
-       apr_uint32_t           jitter_min;
+       apr_uint32_t jitter_min;
        /** Max jitter */
-       apr_uint32_t           jitter_max;
+       apr_uint32_t jitter_max;
 };
 
-/** Reset RTP receive history */
+/** Reset RTP receiver history */
 static APR_INLINE void mpf_rtp_rx_history_reset(rtp_rx_history_t *rx_history)
 {
        memset(rx_history,0,sizeof(rtp_rx_history_t));
 }
 
-/** Reset RTP receive periodic history */
+/** Reset RTP receiver periodic history */
 static APR_INLINE void mpf_rtp_rx_periodic_history_reset(rtp_rx_periodic_history_t *rx_periodic_history)
 {
        memset(rx_periodic_history,0,sizeof(rtp_rx_periodic_history_t));
@@ -98,13 +100,12 @@ static APR_INLINE void mpf_rtp_rx_periodic_history_reset(rtp_rx_periodic_history
 
 /** RTP receiver */
 struct rtp_receiver_t {
-       /** Payload type of named-event packets (RFC2833) */
-       apr_byte_t                event_pt;
-
        /** Jitter buffer */
        mpf_jitter_buffer_t      *jb;
 
-       /** RTP receive statistics to report */
+       /** RTCP statistics used in RR */
+       rtcp_rr_stat_t            rr_stat;
+       /** RTP receiver statistics */
        rtp_rx_stat_t             stat;
        /** RTP history */
        rtp_rx_history_t          history;
@@ -115,10 +116,6 @@ struct rtp_receiver_t {
 
 /** RTP transmitter */
 struct rtp_transmitter_t {
-       /** RTP stream ssrc */
-       apr_uint32_t    ssrc;
-       /** Payload type of named-event packets (RFC2833) */
-       apr_byte_t      event_pt;
        /** Packetization time in msec */
        apr_uint16_t    ptime;
 
@@ -135,24 +132,25 @@ struct rtp_transmitter_t {
        apr_uint16_t    last_seq_num;
        /** Current timestamp (samples processed) */
        apr_uint32_t    timestamp;
+       /** Event timestamp base */
+       apr_uint32_t    timestamp_base;
 
        /** RTP packet payload */
        char           *packet_data;
        /** RTP packet payload size */
        apr_size_t      packet_size;
 
-       /** RTP transmit statistics to report */
-       rtp_tx_stat_t   stat;
+       /** RTCP statistics used in SR */
+       rtcp_sr_stat_t  sr_stat;
 };
 
 
 /** Initialize RTP receiver */
 static APR_INLINE void rtp_receiver_init(rtp_receiver_t *receiver)
 {
-       receiver->event_pt = 0;
-
        receiver->jb = NULL;
 
+       mpf_rtcp_rr_stat_reset(&receiver->rr_stat);
        mpf_rtp_rx_stat_reset(&receiver->stat);
        mpf_rtp_rx_history_reset(&receiver->history);
        mpf_rtp_rx_periodic_history_reset(&receiver->periodic_history);
@@ -161,8 +159,6 @@ static APR_INLINE void rtp_receiver_init(rtp_receiver_t *receiver)
 /** Initialize RTP transmitter */
 static APR_INLINE void rtp_transmitter_init(rtp_transmitter_t *transmitter)
 {
-       transmitter->ssrc = 0;
-       transmitter->event_pt = 0;
        transmitter->ptime = 0;
 
        transmitter->packet_frames = 0;
@@ -172,11 +168,12 @@ static APR_INLINE void rtp_transmitter_init(rtp_transmitter_t *transmitter)
        transmitter->inactivity = 0;
        transmitter->last_seq_num = 0;
        transmitter->timestamp = 0;
+       transmitter->timestamp_base = 0;
 
        transmitter->packet_data = NULL;
        transmitter->packet_size = 0;
 
-       mpf_rtp_tx_stat_reset(&transmitter->stat);
+       mpf_rtcp_sr_stat_reset(&transmitter->sr_stat);
 }
 
 APT_END_EXTERN_C
index 46655e4c276a00eb5abf78222e4917479f1749bc..d7fe3afedc502275d0300d0302e29c53ecea1f9c 100644 (file)
@@ -22,9 +22,9 @@
  * @brief MPF RTP Stream Descriptor
  */ 
 
-#include "mpf_stream_mode.h"
-#include "mpf_media_descriptor.h"
-#include "mpf_codec_descriptor.h"
+#include <apr_network_io.h>
+#include "apt_string.h"
+#include "mpf_stream_descriptor.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -39,23 +39,38 @@ typedef struct mpf_rtp_config_t mpf_rtp_config_t;
 /** Jitter buffer configuration declaration */
 typedef struct mpf_jb_config_t mpf_jb_config_t;
 
+/** MPF media state */
+typedef enum {
+       MPF_MEDIA_DISABLED, /**< disabled media */
+       MPF_MEDIA_ENABLED   /**< enabled media */
+} mpf_media_state_e;
 
 /** RTP media (local/remote) descriptor */
 struct mpf_rtp_media_descriptor_t {
-       /** Media descriptor base */
-       mpf_media_descriptor_t base;
+       /** Media state (disabled/enabled)*/
+       mpf_media_state_e      state;
+       /** Ip address */
+       apt_str_t              ip;
+       /** External (NAT) Ip address */
+       apt_str_t              ext_ip;
+       /** Port */
+       apr_port_t             port;
        /** Stream mode (send/receive) */
-       mpf_stream_mode_e      mode;
+       mpf_stream_direction_e direction;
        /** Packetization time */
        apr_uint16_t           ptime;
        /** Codec list */
        mpf_codec_list_t       codec_list;
        /** Media identifier */
        apr_size_t             mid;
+       /** Position, order in SDP message (0,1,...) */
+       apr_size_t             id;
 };
 
 /** RTP stream descriptor */
 struct mpf_rtp_stream_descriptor_t {
+       /** Stream capabilities */
+       mpf_stream_capabilities_t  *capabilities;
        /** Local media descriptor */
        mpf_rtp_media_descriptor_t *local;
        /** Remote media descriptor */
@@ -82,43 +97,62 @@ struct mpf_jb_config_t {
        apr_byte_t adaptive;
 };
 
+typedef enum {
+       RTCP_BYE_DISABLE,       /**< disable RTCP BYE transmission */
+       RTCP_BYE_PER_SESSION,   /**< transmit RTCP BYE at the end of session */
+       RTCP_BYE_PER_TALKSPURT, /**< transmit RTCP BYE at the end of each talkspurt (input) */
+} rtcp_bye_policy_e;
+
 /** RTP config */
 struct mpf_rtp_config_t {
        /** Local IP address to bind to */
-       apt_str_t ip;
+       apt_str_t         ip;
        /** External (NAT) IP address */
-       apt_str_t ext_ip;
+       apt_str_t         ext_ip;
        /** Min RTP port */
-       apr_port_t rtp_port_min;
+       apr_port_t        rtp_port_min;
        /** Max RTP port */
-       apr_port_t rtp_port_max;
+       apr_port_t        rtp_port_max;
        /** Current RTP port */
-       apr_port_t rtp_port_cur;
+       apr_port_t        rtp_port_cur;
        /** Packetization time */
-       apr_uint16_t ptime;
+       apr_uint16_t      ptime;
        /** Codec list */
-       mpf_codec_list_t codec_list;
-       /** Preference in offer/anser: 1 - own(local) preference, 0 - remote preference */
-       apt_bool_t own_preferrence;
+       mpf_codec_list_t  codec_list;
+       /** Preference in offer/anwser: 1 - own(local) preference, 0 - remote preference */
+       apt_bool_t        own_preferrence;
+       /** Enable/disable RTCP support */
+       apt_bool_t        rtcp;
+       /** RTCP BYE policy */
+       rtcp_bye_policy_e rtcp_bye_policy;
+       /** RTCP report transmission interval */
+       apr_uint16_t      rtcp_tx_interval;
+       /** RTCP rx resolution (timeout to check for a new RTCP message) */
+       apr_uint16_t      rtcp_rx_resolution;
        /** Jitter buffer config */
-       mpf_jb_config_t jb_config;
+       mpf_jb_config_t   jb_config;
 };
 
 /** Initialize media descriptor */
 static APR_INLINE void mpf_rtp_media_descriptor_init(mpf_rtp_media_descriptor_t *media)
 {
-       mpf_media_descriptor_init(&media->base);
-       media->mode = STREAM_MODE_NONE;
+       media->state = MPF_MEDIA_DISABLED;
+       apt_string_reset(&media->ip);
+       apt_string_reset(&media->ext_ip);
+       media->port = 0;
+       media->direction = STREAM_DIRECTION_NONE;
        media->ptime = 0;
        mpf_codec_list_reset(&media->codec_list);
        media->mid = 0;
+       media->id = 0;
 }
 
 /** Initialize stream descriptor */
-static APR_INLINE void mpf_rtp_stream_descriptor_init(mpf_rtp_stream_descriptor_t *stream)
+static APR_INLINE void mpf_rtp_stream_descriptor_init(mpf_rtp_stream_descriptor_t *descriptor)
 {
-       stream->local = NULL;
-       stream->remote = NULL;
+       descriptor->capabilities = NULL;
+       descriptor->local = NULL;
+       descriptor->remote = NULL;
 }
 
 /** Initialize RTP termination descriptor */
@@ -149,7 +183,12 @@ static APR_INLINE mpf_rtp_config_t* mpf_rtp_config_create(apr_pool_t *pool)
        rtp_config->ptime = 0;
        mpf_codec_list_init(&rtp_config->codec_list,0,pool);
        rtp_config->own_preferrence = FALSE;
+       rtp_config->rtcp = FALSE;
+       rtp_config->rtcp_bye_policy = RTCP_BYE_DISABLE;
+       rtp_config->rtcp_tx_interval = 0;
+       rtp_config->rtcp_rx_resolution = 0;
        mpf_jb_config_init(&rtp_config->jb_config);
+
        return rtp_config;
 }
 
index 070bf8c99cefde469615bc08de55e428fe049d94..398d844dced360d84b1ad131d77c77a4fcee99a6 100644 (file)
@@ -26,7 +26,7 @@
 
 APT_BEGIN_EXTERN_C
 
-/** Protocol version. */
+/** Protocol version */
 #define RTP_VERSION 2
 
 /** RTP header declaration */
@@ -74,8 +74,7 @@ struct rtp_header_t {
 };
 
 /** RTP extension header */
-struct rtp_extension_header_t
-{
+struct rtp_extension_header_t {
        /** profile */
        apr_uint16_t profile;
        /** length */
diff --git a/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h b/libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h
new file mode 100644 (file)
index 0000000..27114c5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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_RTP_PT_H__
+#define __MPF_RTP_PT_H__
+
+/**
+ * @file mpf_rtp_pt.h
+ * @brief RTP Payload Types (RFC3551)
+ */ 
+
+#include "mpf.h"
+
+APT_BEGIN_EXTERN_C
+
+/** RTP payload types */
+typedef enum {
+       RTP_PT_PCMU        =  0, /**< PCMU          Audio 8kHz 1  */
+       RTP_PT_PCMA        =  8, /**< PCMA          Audio 8kHz 1  */
+
+       RTP_PT_CN          =  13, /**< Comfort Noise Audio 8kHz 1  */
+
+       RTP_PT_DYNAMIC     =  96, /**< Start of dynamic payload types */
+       RTP_PT_DYNAMIC_MAX = 127, /**< End of dynamic payload types  */
+
+       RTP_PT_UNKNOWN     = 128  /**< Unknown (invalid) payload type */
+} mpf_rtp_pt_e;
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_RTP_PT_H__*/
index 248a4b5c66c300c2d151bafad01696c2d67199cb..eef43adcd497bf902ea72dbfdcf9d261318d2d6a 100644 (file)
 
 /**
  * @file mpf_rtp_stat.h
- * @brief RTP Statistics
+ * @brief RTP/RTCP Statistics
  */ 
 
 #include "mpf.h"
 
 APT_BEGIN_EXTERN_C
 
-/** RTP transmit statistics declaration */
-typedef struct rtp_tx_stat_t rtp_tx_stat_t;
-/** RTP receive statistics declaration */
+/** RTP receiver statistics */
 typedef struct rtp_rx_stat_t rtp_rx_stat_t;
 
+/** RTCP statistics used in Sender Report (SR) */
+typedef struct rtcp_sr_stat_t rtcp_sr_stat_t;
+/** RTCP statistics used in Receiver Report (RR) */
+typedef struct rtcp_rr_stat_t rtcp_rr_stat_t;
 
-/** RTP transmit statistics */
-struct rtp_tx_stat_t {
-       /** number of RTP packets received */
-       apr_uint32_t    sent_packets;
 
-       /* more to come */
-};
-
-/** RTP receive statistics */
+/** RTP receiver statistics */
 struct rtp_rx_stat_t {
        /** number of valid RTP packets received */
-       apr_uint32_t           received_packets;
+       apr_uint32_t received_packets;
        /** number of invalid RTP packets received */
-       apr_uint32_t           invalid_packets;
+       apr_uint32_t invalid_packets;
 
        /** number of discarded in jitter buffer packets */
-       apr_uint32_t           discarded_packets;
+       apr_uint32_t discarded_packets;
        /** number of ignored packets */
-       apr_uint32_t           ignored_packets;
+       apr_uint32_t ignored_packets;
 
        /** number of lost in network packets */
-       apr_uint32_t           lost_packets;
+       apr_uint32_t lost_packets;
 
        /** number of restarts */
-       apr_byte_t             restarts;
+       apr_byte_t   restarts;
+};
 
-       /** network jitter (rfc3550) */
-       apr_uint32_t           jitter;
+/** RTCP statistics used in Sender Report (SR)  */
+struct rtcp_sr_stat_t {
+       /** sender source identifier */
+       apr_uint32_t ssrc;
+       /** NTP timestamp (seconds) */
+       apr_uint32_t ntp_sec;
+       /** NTP timestamp (fractions) */
+       apr_uint32_t ntp_frac;
+       /** RTP timestamp */
+       apr_uint32_t rtp_ts;
+       /* packets sent */
+       apr_uint32_t sent_packets;
+       /* octets (bytes) sent */
+       apr_uint32_t sent_octets;
+};
 
-       /** source id of received RTP stream */
-       apr_uint32_t           ssrc;
+/** RTCP statistics used in Receiver Report (RR) */
+struct rtcp_rr_stat_t {
+       /** source identifier of RTP stream being received */
+       apr_uint32_t ssrc;
+       /** fraction lost since last SR/RR */
+       apr_uint32_t fraction:8;
+       /** cumulative number of packets lost (signed!) */
+       apr_int32_t  lost:24;
+       /** extended last sequence number received */
+       apr_uint32_t last_seq;
+       /** interarrival jitter (RFC3550) */
+       apr_uint32_t jitter;
+       /** last SR packet from this source */
+       apr_uint32_t lsr;
+       /** delay since last SR packet */
+       apr_uint32_t dlsr;
 };
 
 
-/** Reset RTP transmit statistics */
-static APR_INLINE void mpf_rtp_tx_stat_reset(rtp_tx_stat_t *tx_stat)
+
+/** Reset RTCP SR statistics */
+static APR_INLINE void mpf_rtcp_sr_stat_reset(rtcp_sr_stat_t *sr_stat)
+{
+       memset(sr_stat,0,sizeof(rtcp_sr_stat_t));
+}
+
+/** Reset RTCP RR statistics */
+static APR_INLINE void mpf_rtcp_rr_stat_reset(rtcp_rr_stat_t *rr_stat)
 {
-       memset(tx_stat,0,sizeof(rtp_tx_stat_t));
+       memset(rr_stat,0,sizeof(rtcp_rr_stat_t));
 }
 
-/** Reset RTP receive statistics */
+/** Reset RTP receiver statistics */
 static APR_INLINE void mpf_rtp_rx_stat_reset(rtp_rx_stat_t *rx_stat)
 {
        memset(rx_stat,0,sizeof(rtp_rx_stat_t));
index 848cb54c843d3e27bad5ac4e7f238ca2240d4ab0..803ab34577c15e2d15e16f334f41de2c39254106 100644 (file)
@@ -35,6 +35,18 @@ APT_BEGIN_EXTERN_C
  */
 MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, apr_pool_t *pool);
 
+/**
+ * Add/enable RTP stream.
+ * @param stream RTP stream to add
+ */
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_add(mpf_audio_stream_t *stream);
+
+/**
+ * Subtract/disable RTP stream.
+ * @param stream RTP stream to subtract
+ */
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_remove(mpf_audio_stream_t *stream);
+
 /**
  * Modify RTP stream.
  * @param stream RTP stream to modify
index 2f9f171e3c24f9afe6d06ad100904ae0cde87d67..f881c445aff22cd7b955fc0e632d0e5327f05b40 100644 (file)
@@ -22,8 +22,7 @@
  * @brief MPF RTP Termination Factory
  */ 
 
-#include <apr_network_io.h>
-#include "mpf_types.h"
+#include "mpf_termination_factory.h"
 #include "mpf_rtp_descriptor.h"
 
 APT_BEGIN_EXTERN_C
diff --git a/libs/unimrcp/libs/mpf/include/mpf_scheduler.h b/libs/unimrcp/libs/mpf/include/mpf_scheduler.h
new file mode 100644 (file)
index 0000000..8712266
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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_SCHEDULER_H__
+#define __MPF_SCHEDULER_H__
+
+/**
+ * @file mpf_scheduler.h
+ * @brief MPF Scheduler (High Resolution Clock for Media Processing and Timer)
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Prototype of scheduler callback */
+typedef void (*mpf_scheduler_proc_f)(mpf_scheduler_t *scheduler, void *obj);
+
+/** Create scheduler */
+MPF_DECLARE(mpf_scheduler_t*) mpf_scheduler_create(unsigned long rate, apr_pool_t *pool);
+
+/** Destroy scheduler */
+MPF_DECLARE(void) mpf_scheduler_destroy(mpf_scheduler_t *scheduler);
+
+/** Set media processing clock */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_media_clock_set(
+                                                               mpf_scheduler_t *scheduler,
+                                                               unsigned long resolution,
+                                                               mpf_scheduler_proc_f proc,
+                                                               void *obj);
+
+/** Set timer clock */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_timer_clock_set(
+                                                               mpf_scheduler_t *scheduler,
+                                                               unsigned long resolution,
+                                                               mpf_scheduler_proc_f proc,
+                                                               void *obj);
+
+/** Start scheduler */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_start(mpf_scheduler_t *scheduler);
+
+/** Stop scheduler */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_stop(mpf_scheduler_t *scheduler);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_SCHEDULER_H__*/
index 9df864ecfcd03192fd115aca0346d1f480fa81cd..4decae523535dec0ff6c3f659077eeae7873e6a8 100644 (file)
  */ 
 
 #include "mpf_types.h"
-#include "mpf_stream_mode.h"
 #include "mpf_frame.h"
+#include "mpf_stream_descriptor.h"
 #include "mpf_codec.h"
+#include "apt_text_stream.h"
 
 APT_BEGIN_EXTERN_C
 
-/** Opaque audio stream virtual table declaration */
+/** Declaration of virtual table of audio stream */
 typedef struct mpf_audio_stream_vtable_t mpf_audio_stream_vtable_t;
 
 /** Audio stream */
@@ -40,20 +41,28 @@ struct mpf_audio_stream_t {
        const mpf_audio_stream_vtable_t *vtable;
        /** Back pointer */
        mpf_termination_t               *termination;
-       /** Stream mode (send/receive) */
-       mpf_stream_mode_e                mode;
-       /** Receive codec */
-       mpf_codec_t                     *rx_codec;
-       /** Transmit codec */
-       mpf_codec_t                     *tx_codec;
+
+       /** Stream capabilities */
+       const mpf_stream_capabilities_t *capabilities;
+
+       /** Stream direction send/receive (bitmask of mpf_stream_direction_e) */
+       mpf_stream_direction_e           direction;
+       /** Rx codec descriptor */
+       mpf_codec_descriptor_t          *rx_descriptor;
+       /** Rx event descriptor */
+       mpf_codec_descriptor_t          *rx_event_descriptor;
+       /** Tx codec descriptor */
+       mpf_codec_descriptor_t          *tx_descriptor;
+       /** Tx event descriptor */
+       mpf_codec_descriptor_t          *tx_event_descriptor;
 };
 
 /** Video stream */
 struct mpf_video_stream_t {
        /** Back pointer */
        mpf_termination_t               *termination;
-       /** Stream mode (send/receive) */
-       mpf_stream_mode_e                mode;
+       /** Stream direction send/receive (bitmask of mpf_stream_direction_e) */
+       mpf_stream_direction_e           direction;
 };
 
 /** Table of audio stream virtual methods */
@@ -62,33 +71,39 @@ struct mpf_audio_stream_vtable_t {
        apt_bool_t (*destroy)(mpf_audio_stream_t *stream);
 
        /** Virtual open receiver method */
-       apt_bool_t (*open_rx)(mpf_audio_stream_t *stream);
+       apt_bool_t (*open_rx)(mpf_audio_stream_t *stream, mpf_codec_t *codec);
        /** Virtual close receiver method */
        apt_bool_t (*close_rx)(mpf_audio_stream_t *stream);
        /** Virtual read frame method */
        apt_bool_t (*read_frame)(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
        /** Virtual open transmitter method */
-       apt_bool_t (*open_tx)(mpf_audio_stream_t *stream);
+       apt_bool_t (*open_tx)(mpf_audio_stream_t *stream, mpf_codec_t *codec);
        /** Virtual close transmitter method */
        apt_bool_t (*close_tx)(mpf_audio_stream_t *stream);
        /** Virtual write frame method */
        apt_bool_t (*write_frame)(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
-};
 
+       /** Virtual trace method */
+       void (*trace)(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output);
+};
 
 /** Create audio stream */
-static APR_INLINE mpf_audio_stream_t* mpf_audio_stream_create(void *obj, const mpf_audio_stream_vtable_t *vtable, mpf_stream_mode_e mode, apr_pool_t *pool)
-{
-       mpf_audio_stream_t *stream = (mpf_audio_stream_t*)apr_palloc(pool,sizeof(mpf_audio_stream_t));
-       stream->obj = obj;
-       stream->vtable = vtable;
-       stream->termination = NULL;
-       stream->mode = mode;
-       stream->rx_codec = NULL;
-       stream->tx_codec = NULL;
-       return stream;
-}
+MPF_DECLARE(mpf_audio_stream_t*) mpf_audio_stream_create(void *obj, const mpf_audio_stream_vtable_t *vtable, const mpf_stream_capabilities_t *capabilities, apr_pool_t *pool);
+
+/** Validate audio stream receiver */
+MPF_DECLARE(apt_bool_t) mpf_audio_stream_rx_validate(
+                                                       mpf_audio_stream_t *stream,
+                                                       const mpf_codec_descriptor_t *descriptor,
+                                                       const mpf_codec_descriptor_t *event_descriptor,
+                                                       apr_pool_t *pool);
+
+/** Validate audio stream transmitter */
+MPF_DECLARE(apt_bool_t) mpf_audio_stream_tx_validate(
+                                                       mpf_audio_stream_t *stream, 
+                                                       const mpf_codec_descriptor_t *descriptor, 
+                                                       const mpf_codec_descriptor_t *event_descriptor, 
+                                                       apr_pool_t *pool);
 
 /** Destroy audio stream */
 static APR_INLINE apt_bool_t mpf_audio_stream_destroy(mpf_audio_stream_t *stream)
@@ -98,15 +113,15 @@ static APR_INLINE apt_bool_t mpf_audio_stream_destroy(mpf_audio_stream_t *stream
        return TRUE;
 }
 
-/** Open audio stream receive */
-static APR_INLINE apt_bool_t mpf_audio_stream_rx_open(mpf_audio_stream_t *stream)
+/** Open audio stream receiver */
+static APR_INLINE apt_bool_t mpf_audio_stream_rx_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        if(stream->vtable->open_rx)
-               return stream->vtable->open_rx(stream);
+               return stream->vtable->open_rx(stream,codec);
        return TRUE;
 }
 
-/** Close audio stream receive */
+/** Close audio stream receiver */
 static APR_INLINE apt_bool_t mpf_audio_stream_rx_close(mpf_audio_stream_t *stream)
 {
        if(stream->vtable->close_rx)
@@ -122,15 +137,15 @@ static APR_INLINE apt_bool_t mpf_audio_stream_frame_read(mpf_audio_stream_t *str
        return TRUE;
 }
 
-/** Open audio stream transmit */
-static APR_INLINE apt_bool_t mpf_audio_stream_tx_open(mpf_audio_stream_t *stream)
+/** Open audio stream transmitter */
+static APR_INLINE apt_bool_t mpf_audio_stream_tx_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        if(stream->vtable->open_tx)
-               return stream->vtable->open_tx(stream);
+               return stream->vtable->open_tx(stream,codec);
        return TRUE;
 }
 
-/** Close audio stream transmit */
+/** Close audio stream transmitter */
 static APR_INLINE apt_bool_t mpf_audio_stream_tx_close(mpf_audio_stream_t *stream)
 {
        if(stream->vtable->close_tx)
@@ -146,6 +161,9 @@ static APR_INLINE apt_bool_t mpf_audio_stream_frame_write(mpf_audio_stream_t *st
        return TRUE;
 }
 
+/** Trace media path */
+MPF_DECLARE(void) mpf_audio_stream_trace(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output);
+
 APT_END_EXTERN_C
 
 #endif /*__MPF_STREAM_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h b/libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h
new file mode 100644 (file)
index 0000000..86b56b1
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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_STREAM_DESCRIPTOR_H__
+#define __MPF_STREAM_DESCRIPTOR_H__
+
+/**
+ * @file mpf_stream_descriptor.h
+ * @brief MPF Stream Descriptor
+ */ 
+
+#include "mpf_codec_descriptor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Stream capabilities declaration */
+typedef struct mpf_stream_capabilities_t mpf_stream_capabilities_t;
+
+/** Stream directions (none, send, receive, duplex) */
+typedef enum {
+       STREAM_DIRECTION_NONE    = 0x0, /**< none */
+       STREAM_DIRECTION_SEND    = 0x1, /**< send (sink) */
+       STREAM_DIRECTION_RECEIVE = 0x2, /**< receive (source) */
+
+       STREAM_DIRECTION_DUPLEX  = STREAM_DIRECTION_SEND | STREAM_DIRECTION_RECEIVE /**< duplex */
+} mpf_stream_direction_e; 
+
+
+/** Stream capabilities */
+struct mpf_stream_capabilities_t {
+       /** Supported directions either send, receive or bidirectional stream (bitmask of mpf_stream_direction_e) */
+       mpf_stream_direction_e   direction;
+       /** Codec capabilities (supported codecs and named events) */
+       mpf_codec_capabilities_t codecs;
+};
+
+/** Create stream capabilities */
+MPF_DECLARE(mpf_stream_capabilities_t*) mpf_stream_capabilities_create(mpf_stream_direction_e directions, apr_pool_t *pool);
+
+/** Create source stream capabilities */
+static APR_INLINE mpf_stream_capabilities_t* mpf_source_stream_capabilities_create(apr_pool_t *pool)
+{
+       return mpf_stream_capabilities_create(STREAM_DIRECTION_RECEIVE,pool);
+}
+
+/** Create sink stream capabilities */
+static APR_INLINE mpf_stream_capabilities_t* mpf_sink_stream_capabilities_create(apr_pool_t *pool)
+{
+       return mpf_stream_capabilities_create(STREAM_DIRECTION_SEND,pool);
+}
+
+/** Clone stream capabilities */
+MPF_DECLARE(mpf_stream_capabilities_t*) mpf_stream_capabilities_clone(const mpf_stream_capabilities_t *src_capabilities, apr_pool_t *pool);
+
+/** Merge stream capabilities */
+MPF_DECLARE(apt_bool_t) mpf_stream_capabilities_merge(mpf_stream_capabilities_t *capabilities, const mpf_stream_capabilities_t *src_capabilities, apr_pool_t *pool);
+
+
+/** Get reverse direction */
+static APR_INLINE mpf_stream_direction_e mpf_stream_reverse_direction_get(mpf_stream_direction_e direction)
+{
+       mpf_stream_direction_e rev_direction = direction;
+       if(rev_direction == STREAM_DIRECTION_SEND) {
+               rev_direction = STREAM_DIRECTION_RECEIVE;
+       }
+       else if(rev_direction == STREAM_DIRECTION_RECEIVE) {
+               rev_direction = STREAM_DIRECTION_SEND;
+       }
+       return rev_direction;
+}
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_STREAM_DESCRIPTOR_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_stream_mode.h b/libs/unimrcp/libs/mpf/include/mpf_stream_mode.h
deleted file mode 100644 (file)
index 9b7cf0d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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_STREAM_MODE_H__
-#define __MPF_STREAM_MODE_H__
-
-/**
- * @file mpf_stream_mode.h
- * @brief MPF Stream Mode (Send/Receive)
- */ 
-
-#include "mpf.h"
-
-APT_BEGIN_EXTERN_C
-
-/** Enumeration of stream modes */
-typedef enum {
-       STREAM_MODE_NONE    = 0x0, /**< none */
-       STREAM_MODE_SEND    = 0x1, /**< send */
-       STREAM_MODE_RECEIVE = 0x2, /**< receive */
-
-       STREAM_MODE_SEND_RECEIVE = STREAM_MODE_SEND | STREAM_MODE_RECEIVE /**< send and receive */
-} mpf_stream_mode_e; 
-
-static APR_INLINE mpf_stream_mode_e mpf_stream_mode_negotiate(mpf_stream_mode_e remote_mode)
-{
-       mpf_stream_mode_e local_mode = remote_mode;
-       if(local_mode == STREAM_MODE_SEND) {
-               local_mode = STREAM_MODE_RECEIVE;
-       }
-       else if(local_mode == STREAM_MODE_RECEIVE) {
-               local_mode = STREAM_MODE_SEND;
-       }
-       return local_mode;
-}
-
-
-APT_END_EXTERN_C
-
-#endif /*__MPF_STREAM_MODE_H__*/
index df51fbbbf675106bc8842d7476f87721c19fe1cc..06ede3bfd8e59f4fcd00c750f561d32f6b12ffa8 100644 (file)
@@ -29,6 +29,23 @@ APT_BEGIN_EXTERN_C
 /** Prototype of termination event handler */
 typedef apt_bool_t (*mpf_termination_event_handler_f)(mpf_termination_t *termination, int event_id, void *descriptor);
 
+/** Termination vtable declaration */
+typedef struct mpf_termination_vtable_t mpf_termination_vtable_t;
+
+/** Table of termination virtual methods */
+struct mpf_termination_vtable_t {
+       /** Virtual termination destroy method */
+       apt_bool_t (*destroy)(mpf_termination_t *termination);
+
+       /** Virtual termination add method */
+       apt_bool_t (*add)(mpf_termination_t *termination, void *descriptor);
+       /** Virtual termination modify method */
+       apt_bool_t (*modify)(mpf_termination_t *termination, void *descriptor);
+       /** Virtual termination subtract method */
+       apt_bool_t (*subtract)(mpf_termination_t *termination);
+};
+
+
 /** MPF Termination */
 struct mpf_termination_t {
        /** Pool to allocate memory from */
@@ -41,6 +58,8 @@ struct mpf_termination_t {
        mpf_termination_event_handler_f event_handler;
        /** Codec manager */
        const mpf_codec_manager_t      *codec_manager;
+       /** Timer manager */
+       mpf_timer_manager_t            *timer_manager;
        /** Termination factory entire termination created by */
        mpf_termination_factory_t      *termination_factory;
        /** Table of virtual methods */
@@ -54,15 +73,6 @@ struct mpf_termination_t {
        mpf_video_stream_t             *video_stream;
 };
 
-/** MPF termination factory */
-struct mpf_termination_factory_t {
-       /** Virtual create */
-       mpf_termination_t* (*create_termination)(mpf_termination_factory_t *factory, void *obj, apr_pool_t *pool);
-
-       /* more to add */
-};
-
-
 /**
  * Create MPF termination base.
  * @param termination_factory the termination factory
@@ -81,54 +91,25 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
                                                                                apr_pool_t *pool);
 
 /**
- * Modify MPF termination.
- * @param termination the termination to modify
+ * Add MPF termination.
+ * @param termination the termination to add
  * @param descriptor the termination specific descriptor
  */
-MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor);
-
-/**
- * Validate MPF termination.
- * @param termination the termination to validate
- */
-MPF_DECLARE(apt_bool_t) mpf_termination_validate(mpf_termination_t *termination);
+MPF_DECLARE(apt_bool_t) mpf_termination_add(mpf_termination_t *termination, void *descriptor);
 
 /**
- * Destroy MPF termination.
- * @param termination the termination to destroy
- */
-MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination);
-
-/**
- * Get associated object.
- * @param termination the termination to get object from
+ * Modify MPF termination.
+ * @param termination the termination to modify
+ * @param descriptor the termination specific descriptor
  */
-MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination);
-
+MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor);
 
 /**
- * Create MPF termination by termination factory.
- * @param termination_factory the termination factory to create termination from
- * @param obj the external object associated with termination
- * @param pool the pool to allocate memory from
+ * Subtract MPF termination.
+ * @param termination the termination to subtract
  */
-MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
-                                                                               mpf_termination_factory_t *termination_factory,
-                                                                               void *obj,
-                                                                               apr_pool_t *pool);
+MPF_DECLARE(apt_bool_t) mpf_termination_subtract(mpf_termination_t *termination);
 
-/**
- * Create raw MPF termination.
- * @param obj the external object associated with termination
- * @param audio_stream the audio stream of the termination
- * @param video_stream the video stream of the termination
- * @param pool the pool to allocate memory from
- */
-MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
-                                                                               void *obj,
-                                                                               mpf_audio_stream_t *audio_stream, 
-                                                                               mpf_video_stream_t *video_stream, 
-                                                                               apr_pool_t *pool);
 
 APT_END_EXTERN_C
 
diff --git a/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h b/libs/unimrcp/libs/mpf/include/mpf_termination_factory.h
new file mode 100644 (file)
index 0000000..5645186
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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_TERMINATION_FACTORY_H__
+#define __MPF_TERMINATION_FACTORY_H__
+
+/**
+ * @file mpf_termination_factory.h
+ * @brief MPF Termination Factory
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MPF termination factory */
+struct mpf_termination_factory_t {
+       /** Virtual create */
+       mpf_termination_t* (*create_termination)(mpf_termination_factory_t *factory, void *obj, apr_pool_t *pool);
+};
+
+
+
+/**
+ * Create MPF termination from termination factory.
+ * @param termination_factory the termination factory to create termination from
+ * @param obj the external object associated with termination
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               apr_pool_t *pool);
+
+/**
+ * Create raw MPF termination.
+ * @param obj the external object associated with termination
+ * @param audio_stream the audio stream of the termination
+ * @param video_stream the video stream of the termination
+ * @param pool the pool to allocate memory from
+ */
+MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
+                                                                               void *obj,
+                                                                               mpf_audio_stream_t *audio_stream, 
+                                                                               mpf_video_stream_t *video_stream, 
+                                                                               apr_pool_t *pool);
+
+/**
+ * Destroy MPF termination.
+ * @param termination the termination to destroy
+ */
+MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination);
+
+/**
+ * Get associated object.
+ * @param termination the termination to get object from
+ */
+MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination);
+
+/**
+ * Get audio stream.
+ * @param termination the termination to get audio stream from
+ */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(mpf_termination_t *termination);
+
+/**
+ * Get video stream.
+ * @param termination the termination to get video stream from
+ */
+MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(mpf_termination_t *termination);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_TERMINATION_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mpf/include/mpf_timer_manager.h b/libs/unimrcp/libs/mpf/include/mpf_timer_manager.h
new file mode 100644 (file)
index 0000000..4de738c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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_TIMER_MANAGER_H__
+#define __MPF_TIMER_MANAGER_H__
+
+/**
+ * @file mpf_timer_manager.h
+ * @brief MPF Timer Management
+ */ 
+
+#include "mpf_types.h"
+
+APT_BEGIN_EXTERN_C
+
+
+/** Prototype of timer callback */
+typedef void (*mpf_timer_proc_f)(mpf_timer_t *timer, void *obj);
+
+
+/** Create timer manager */
+MPF_DECLARE(mpf_timer_manager_t*) mpf_timer_manager_create(mpf_scheduler_t *scheduler, apr_pool_t *pool);
+
+/** Destroy timer manager */
+MPF_DECLARE(void) mpf_timer_manager_destroy(mpf_timer_manager_t *timer_manager);
+
+
+/** Create timer */
+MPF_DECLARE(mpf_timer_t*) mpf_timer_create(mpf_timer_manager_t *timer_manager, mpf_timer_proc_f proc, void *obj, apr_pool_t *pool);
+
+/** Set one-shot timer */
+MPF_DECLARE(apt_bool_t) mpf_timer_set(mpf_timer_t *timer, apr_uint32_t timeout);
+
+/** Kill timer */
+MPF_DECLARE(apt_bool_t) mpf_timer_kill(mpf_timer_t *timer);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MPF_TIMER_MANAGER_H__*/
index 721fa61c3679f805f2d6b20c844607dfb69659b2..0b9814edb56c70fbe4527a6be91e07a02a76a0fd 100644 (file)
@@ -29,9 +29,18 @@ APT_BEGIN_EXTERN_C
 /** Opaque MPF engine declaration */
 typedef struct mpf_engine_t mpf_engine_t;
 
+/** Opaque MPF scheduler declaration */
+typedef struct mpf_scheduler_t mpf_scheduler_t;
+
 /** Opaque codec manager declaration */
 typedef struct mpf_codec_manager_t mpf_codec_manager_t;
 
+/** Opaque MPF timer manager declaration */
+typedef struct mpf_timer_manager_t mpf_timer_manager_t;
+
+/** Opaque MPF timer declaration */
+typedef struct mpf_timer_t mpf_timer_t;
+
 /** Opaque MPF context declaration */
 typedef struct mpf_context_t mpf_context_t;
 
@@ -47,16 +56,6 @@ typedef struct mpf_audio_stream_t mpf_audio_stream_t;
 /** Opaque MPF video stream declaration */
 typedef struct mpf_video_stream_t mpf_video_stream_t;
 
-/** Termination vtable declaration */
-typedef struct mpf_termination_vtable_t mpf_termination_vtable_t;
-
-/** Table of termination virtual methods */
-struct mpf_termination_vtable_t {
-       /** Virtual termination destroy method */
-       apt_bool_t (*destroy)(mpf_termination_t *termination);
-       /** Virtual termination modify method */
-       apt_bool_t (*modify)(mpf_termination_t *termination, void *descriptor);
-};
 
 APT_END_EXTERN_C
 
diff --git a/libs/unimrcp/libs/mpf/include/mpf_user.h b/libs/unimrcp/libs/mpf/include/mpf_user.h
deleted file mode 100644 (file)
index 0d6ab83..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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_USER_H__
-#define __MPF_USER_H__
-
-/**
- * @file mpf_user.h
- * @brief MPF User Interface
- */ 
-
-#include "mpf_types.h"
-
-APT_BEGIN_EXTERN_C
-
-/**
- * Create MPF context.
- * @param obj the external object associated with context
- * @param max_termination_count the max number of terminations in context
- * @param pool the pool to allocate memory from
- */
-MPF_DECLARE(mpf_context_t*) mpf_context_create(void *obj, apr_size_t max_termination_count, apr_pool_t *pool);
-
-/**
- * Destroy MPF context.
- * @param context the context to destroy
- */
-MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context);
-
-/**
- * Get external object associated with MPF context.
- * @param context the context to get object from
- */
-MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context);
-
-
-APT_END_EXTERN_C
-
-#endif /*__MPF_USER_H__*/
index 6efaf489b86df8eaf15b21a3e3688c6921339db5..c1d1d8557d013acf2d6186c00a9102adf256db55 100644 (file)
                                RelativePath=".\include\mpf_decoder.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_dtmf_detector.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_dtmf_generator.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\include\mpf_encoder.h"\r
                                >\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_media_descriptor.h"\r
+                               RelativePath=".\include\mpf_message.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_mixer.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_message.h"\r
+                               RelativePath=".\include\mpf_multiplier.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_named_event.h"\r
                                >\r
                        </File>\r
                        <File\r
                                RelativePath=".\include\mpf_object.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_resampler.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtcp_packet.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\include\mpf_rtp_attribs.h"\r
                                >\r
                                RelativePath=".\include\mpf_rtp_header.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_rtp_pt.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\include\mpf_rtp_stat.h"\r
                                >\r
                                RelativePath=".\include\mpf_rtp_termination_factory.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\include\mpf_scheduler.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\include\mpf_stream.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_stream_mode.h"\r
+                               RelativePath=".\include\mpf_stream_descriptor.h"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_timer.h"\r
+                               RelativePath=".\include\mpf_termination_factory.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_types.h"\r
+                               RelativePath=".\include\mpf_timer_manager.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\include\mpf_user.h"\r
+                               RelativePath=".\include\mpf_types.h"\r
                                >\r
                        </File>\r
                </Filter>\r
                                RelativePath=".\src\mpf_decoder.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_dtmf_detector.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_dtmf_generator.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\src\mpf_encoder.c"\r
                                >\r
                                RelativePath=".\src\mpf_jitter_buffer.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_mixer.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_multiplier.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_named_event.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_resampler.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\src\mpf_rtp_attribs.c"\r
                                >\r
                                RelativePath=".\src\mpf_rtp_termination_factory.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_scheduler.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_stream.c"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\src\mpf_termination.c"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\src\mpf_timer.c"\r
+                               RelativePath=".\src\mpf_termination_factory.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\src\mpf_timer_manager.c"\r
                                >\r
                        </File>\r
                </Filter>\r
index 8c27801069aa89db94e6d101059647fda55cce96..4aba1579e2ddd1503f03979998dc8889c6f46c68 100644 (file)
@@ -28,17 +28,19 @@ typedef enum {
 /** Activity detector */
 struct mpf_activity_detector_t {
        /* voice activity (silence) level threshold */
-       apr_size_t level_threshold;
+       apr_size_t           level_threshold;
 
-       /* period of activity/inactivity required to complete/raise an event */
-       apr_size_t complete_timeout;
+       /* period of activity required to complete transition to active state */
+       apr_size_t           speech_timeout;
+       /* period of inactivity required to complete transition to inactive state */
+       apr_size_t           silence_timeout;
        /* noinput timeout */
-       apr_size_t noinput_timeout;
+       apr_size_t           noinput_timeout;
 
        /* current state */
-       apt_bool_t state;
+       mpf_detector_state_e state;
        /* duration spent in current state  */
-       apr_size_t duration;
+       apr_size_t           duration;
 };
 
 /** Create activity detector */
@@ -46,7 +48,8 @@ MPF_DECLARE(mpf_activity_detector_t*) mpf_activity_detector_create(apr_pool_t *p
 {
        mpf_activity_detector_t *detector = apr_palloc(pool,sizeof(mpf_activity_detector_t));
        detector->level_threshold = 2; /* 0 .. 255 */
-       detector->complete_timeout = 300; /* 0.3 s */
+       detector->speech_timeout = 300; /* 0.3 s */
+       detector->silence_timeout = 300; /* 0.3 s */
        detector->noinput_timeout = 5000; /* 5 s */
        detector->duration = 0;
        detector->state = DETECTOR_STATE_INACTIVITY;
@@ -72,10 +75,16 @@ MPF_DECLARE(void) mpf_activity_detector_noinput_timeout_set(mpf_activity_detecto
        detector->noinput_timeout = noinput_timeout;
 }
 
-/** Set transition complete timeout */
-MPF_DECLARE(void) mpf_activity_detector_complete_timeout_set(mpf_activity_detector_t *detector, apr_size_t complete_timeout)
+/** Set timeout required to trigger speech (transition from inactive to active state) */
+MPF_DECLARE(void) mpf_activity_detector_speech_timeout_set(mpf_activity_detector_t *detector, apr_size_t speech_timeout)
 {
-       detector->complete_timeout = complete_timeout;
+       detector->speech_timeout = speech_timeout;
+}
+
+/** Set timeout required to trigger silence (transition from active to inactive state) */
+MPF_DECLARE(void) mpf_activity_detector_silence_timeout_set(mpf_activity_detector_t *detector, apr_size_t silence_timeout)
+{
+       detector->silence_timeout = silence_timeout;
 }
 
 
@@ -133,7 +142,7 @@ MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_det
        else if(detector->state == DETECTOR_STATE_ACTIVITY_TRANSITION) {
                if(level >= detector->level_threshold) {
                        detector->duration += CODEC_FRAME_TIME_BASE;
-                       if(detector->duration >= detector->complete_timeout) {
+                       if(detector->duration >= detector->speech_timeout) {
                                /* finally detected activity */
                                det_event = MPF_DETECTOR_EVENT_ACTIVITY;
                                mpf_activity_detector_state_change(detector,DETECTOR_STATE_ACTIVITY);
@@ -160,7 +169,7 @@ MPF_DECLARE(mpf_detector_event_e) mpf_activity_detector_process(mpf_activity_det
                }
                else {
                        detector->duration += CODEC_FRAME_TIME_BASE;
-                       if(detector->duration >= detector->complete_timeout) {
+                       if(detector->duration >= detector->silence_timeout) {
                                /* detected inactivity */
                                det_event = MPF_DETECTOR_EVENT_INACTIVITY;
                                mpf_activity_detector_state_change(detector,DETECTOR_STATE_INACTIVITY);
index e52d156cb7ac42b3b6fee5f83b6bcf8cc6b846f9..54010b69b46aed065bc8d1ad3a31f0c1ff05c304 100644 (file)
@@ -50,7 +50,7 @@ static apt_bool_t mpf_audio_file_destroy(mpf_audio_stream_t *stream)
        return TRUE;
 }
 
-static apt_bool_t mpf_audio_file_reader_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_audio_file_reader_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
@@ -76,7 +76,7 @@ static apt_bool_t mpf_audio_file_frame_read(mpf_audio_stream_t *stream, mpf_fram
 }
 
 
-static apt_bool_t mpf_audio_file_writer_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_audio_file_writer_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
@@ -116,15 +116,21 @@ static const mpf_audio_stream_vtable_t vtable = {
 MPF_DECLARE(mpf_audio_stream_t*) mpf_file_stream_create(mpf_termination_t *termination, apr_pool_t *pool)
 {
        mpf_audio_file_stream_t *file_stream = apr_palloc(pool,sizeof(mpf_audio_file_stream_t));
-       file_stream->audio_stream = mpf_audio_stream_create(file_stream,&vtable,STREAM_MODE_NONE,pool);
-       file_stream->audio_stream->termination = termination;
+       mpf_stream_capabilities_t *capabilities = mpf_stream_capabilities_create(STREAM_DIRECTION_DUPLEX,pool);
+       mpf_audio_stream_t *audio_stream = mpf_audio_stream_create(file_stream,&vtable,capabilities,pool);
+       if(!audio_stream) {
+               return NULL;
+       }
+       audio_stream->termination = termination;
 
+       file_stream->audio_stream = audio_stream;
        file_stream->write_handle = NULL;
        file_stream->read_handle = NULL;
        file_stream->eof = FALSE;
        file_stream->max_write_size = 0;
        file_stream->cur_write_size = 0;
-       return file_stream->audio_stream;
+
+       return audio_stream;
 }
 
 MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_audio_file_descriptor_t *descriptor)
@@ -136,12 +142,9 @@ MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_a
                }
                file_stream->read_handle = descriptor->read_handle;
                file_stream->eof = FALSE;
-               stream->mode |= FILE_READER;
+               stream->direction |= FILE_READER;
 
-               stream->rx_codec = mpf_codec_manager_codec_get(
-                                                               stream->termination->codec_manager,
-                                                               &descriptor->codec_descriptor,
-                                                               stream->termination->pool);
+               stream->rx_descriptor = descriptor->codec_descriptor;
        }
        if(descriptor->mask & FILE_WRITER) {
                if(file_stream->write_handle) {
@@ -150,12 +153,9 @@ MPF_DECLARE(apt_bool_t) mpf_file_stream_modify(mpf_audio_stream_t *stream, mpf_a
                file_stream->write_handle = descriptor->write_handle;
                file_stream->max_write_size = descriptor->max_write_size;
                file_stream->cur_write_size = 0;
-               stream->mode |= FILE_WRITER;
+               stream->direction |= FILE_WRITER;
 
-               stream->tx_codec = mpf_codec_manager_codec_get(
-                                                               stream->termination->codec_manager,
-                                                               &descriptor->codec_descriptor,
-                                                               stream->termination->pool);
+               stream->tx_descriptor = descriptor->codec_descriptor;
        }
        return TRUE;
 }
index 45aa1c754cb54607169374c8744e3e168afa1e2e..f4028063d3bc6bada50968e3b13b541c02552a05 100644 (file)
  */
 
 #include "mpf_bridge.h"
-#include "mpf_stream.h"
+#include "mpf_encoder.h"
+#include "mpf_decoder.h"
+#include "mpf_resampler.h"
+#include "mpf_codec_manager.h"
 #include "apt_log.h"
 
+typedef struct mpf_bridge_t mpf_bridge_t;
+
+/** MPF bridge derived from MPF object */
+struct mpf_bridge_t {
+       /** MPF bridge base */
+       mpf_object_t        base;
+       /** Audio stream source */
+       mpf_audio_stream_t *source;
+       /** Audio stream sink */
+       mpf_audio_stream_t *sink;
+
+       /** Media frame used to read data from source and write it to sink */
+       mpf_frame_t         frame;
+};
+
 static apt_bool_t mpf_bridge_process(mpf_object_t *object)
 {
-       object->frame.type = MEDIA_FRAME_TYPE_NONE;
-       object->source->vtable->read_frame(object->source,&object->frame);
+       mpf_bridge_t *bridge = (mpf_bridge_t*) object;
+       bridge->frame.type = MEDIA_FRAME_TYPE_NONE;
+       bridge->frame.marker = MPF_MARKER_NONE;
+       bridge->source->vtable->read_frame(bridge->source,&bridge->frame);
        
-       if((object->frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) {
-               memset( object->frame.codec_frame.buffer,
+       if((bridge->frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) {
+               memset( bridge->frame.codec_frame.buffer,
                                0,
-                               object->frame.codec_frame.size);
+                               bridge->frame.codec_frame.size);
        }
 
-       object->sink->vtable->write_frame(object->sink,&object->frame);
+       bridge->sink->vtable->write_frame(bridge->sink,&bridge->frame);
        return TRUE;
 }
 
 static apt_bool_t mpf_null_bridge_process(mpf_object_t *object)
 {
-       object->frame.type = MEDIA_FRAME_TYPE_NONE;
-       object->source->vtable->read_frame(object->source,&object->frame);
-       object->sink->vtable->write_frame(object->sink,&object->frame);
+       mpf_bridge_t *bridge = (mpf_bridge_t*) object;
+       bridge->frame.type = MEDIA_FRAME_TYPE_NONE;
+       bridge->source->vtable->read_frame(bridge->source,&bridge->frame);
+       bridge->sink->vtable->write_frame(bridge->sink,&bridge->frame);
        return TRUE;
 }
 
+static void mpf_bridge_trace(mpf_object_t *object)
+{
+       mpf_bridge_t *bridge = (mpf_bridge_t*) object;
+       char buf[1024];
+       apr_size_t offset;
+
+       apt_text_stream_t output;
+       apt_text_stream_init(&output,buf,sizeof(buf)-1);
+
+       mpf_audio_stream_trace(bridge->source,STREAM_DIRECTION_RECEIVE,&output);
+       
+       offset = output.pos - output.text.buf;
+       output.pos += apr_snprintf(output.pos, output.text.length - offset,
+               "->Bridge->");
+
+       mpf_audio_stream_trace(bridge->sink,STREAM_DIRECTION_SEND,&output);
+
+       *output.pos = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf);
+}
+
 
 static apt_bool_t mpf_bridge_destroy(mpf_object_t *object)
 {
-       mpf_object_t *bridge = object;
+       mpf_bridge_t *bridge = (mpf_bridge_t*) object;
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Destroy Audio Bridge");
        mpf_audio_stream_rx_close(bridge->source);
        mpf_audio_stream_tx_close(bridge->sink);
        return TRUE;
 }
 
-static mpf_object_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+static mpf_bridge_t* mpf_bridge_base_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
 {
-       mpf_object_t *bridge;
+       mpf_bridge_t *bridge;
        if(!source || !sink) {
                return NULL;
        }
 
-       bridge = apr_palloc(pool,sizeof(mpf_object_t));
+       bridge = apr_palloc(pool,sizeof(mpf_bridge_t));
        bridge->source = source;
        bridge->sink = sink;
-       bridge->process = mpf_bridge_process;
-       bridge->destroy = mpf_bridge_destroy;
-
-       if(mpf_audio_stream_rx_open(source) == FALSE) {
-               return NULL;
-       }
-       if(mpf_audio_stream_tx_open(sink) == FALSE) {
-               mpf_audio_stream_rx_close(source);
-               return NULL;
-       }
+       mpf_object_init(&bridge->base);
+       bridge->base.destroy = mpf_bridge_destroy;
+       bridge->base.process = mpf_bridge_process;
+       bridge->base.trace = mpf_bridge_trace;
        return bridge;
 }
 
-MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+static mpf_object_t* mpf_linear_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool)
 {
        mpf_codec_descriptor_t *descriptor;
        apr_size_t frame_size;
-       mpf_object_t *bridge;
-       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Audio Bridge");
+       mpf_bridge_t *bridge;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Linear Audio Bridge");
        bridge = mpf_bridge_base_create(source,sink,pool);
        if(!bridge) {
                return NULL;
        }
 
-       descriptor = source->rx_codec->descriptor;
+       descriptor = source->rx_descriptor;
        frame_size = mpf_codec_linear_frame_size_calculate(descriptor->sampling_rate,descriptor->channel_count);
        bridge->frame.codec_frame.size = frame_size;
        bridge->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
-       return bridge;
+       
+       if(mpf_audio_stream_rx_open(source,NULL) == FALSE) {
+               return NULL;
+       }
+       if(mpf_audio_stream_tx_open(sink,NULL) == FALSE) {
+               mpf_audio_stream_rx_close(source);
+               return NULL;
+       }
+       return &bridge->base;
 }
 
-MPF_DECLARE(mpf_object_t*) mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+static mpf_object_t* mpf_null_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool)
 {
        mpf_codec_t *codec;
        apr_size_t frame_size;
-       mpf_object_t *bridge;
-       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Audio Null Bridge");
+       mpf_bridge_t *bridge;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Create Null Audio Bridge");
        bridge = mpf_bridge_base_create(source,sink,pool);
        if(!bridge) {
                return NULL;
        }
-       bridge->process = mpf_null_bridge_process;
+       bridge->base.process = mpf_null_bridge_process;
+
+       codec = mpf_codec_manager_codec_get(codec_manager,source->rx_descriptor,pool);
+       if(!codec) {
+               return NULL;
+       }
 
-       codec = source->rx_codec;
-       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       frame_size = mpf_codec_frame_size_calculate(source->rx_descriptor,codec->attribs);
        bridge->frame.codec_frame.size = frame_size;
        bridge->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
-       return bridge;
+
+       if(mpf_audio_stream_rx_open(source,codec) == FALSE) {
+               return NULL;
+       }
+       if(mpf_audio_stream_tx_open(sink,codec) == FALSE) {
+               mpf_audio_stream_rx_close(source);
+               return NULL;
+       }
+       return &bridge->base;
+}
+
+MPF_DECLARE(mpf_object_t*) mpf_bridge_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, const mpf_codec_manager_t *codec_manager, apr_pool_t *pool)
+{
+       if(!source || !sink) {
+               return NULL;
+       }
+
+       if(mpf_audio_stream_rx_validate(source,sink->tx_descriptor,sink->tx_event_descriptor,pool) == FALSE ||
+               mpf_audio_stream_tx_validate(sink,source->rx_descriptor,source->rx_event_descriptor,pool) == FALSE) {
+               return NULL;
+       }
+
+       if(mpf_codec_descriptors_match(source->rx_descriptor,sink->tx_descriptor) == TRUE) {
+               return mpf_null_bridge_create(source,sink,codec_manager,pool);
+       }
+
+       if(mpf_codec_lpcm_descriptor_match(source->rx_descriptor) == FALSE) {
+               mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,source->rx_descriptor,pool);
+               if(codec) {
+                       /* set decoder before bridge */
+                       mpf_audio_stream_t *decoder = mpf_decoder_create(source,codec,pool);
+                       source = decoder;
+               }
+       }
+
+       if(mpf_codec_lpcm_descriptor_match(sink->tx_descriptor) == FALSE) {
+               mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,sink->tx_descriptor,pool);
+               if(codec) {
+                       /* set encoder after bridge */
+                       mpf_audio_stream_t *encoder = mpf_encoder_create(sink,codec,pool);
+                       sink = encoder;
+               }
+       }
+
+       if(source->rx_descriptor->sampling_rate != sink->tx_descriptor->sampling_rate) {
+               /* set resampler before bridge */
+               mpf_audio_stream_t *resampler = mpf_resampler_create(source,sink,pool);
+               if(!resampler) {
+                       return NULL;
+               }
+               source = resampler;
+       }
+
+       return mpf_linear_bridge_create(source,sink,codec_manager,pool);
 }
index 0a811ac058bab1e9b6326c2b9c36ce41186713fb..2995cf94a5ff5f70cbffa6030255959d6731d493 100644 (file)
  */
 
 #include "mpf_codec_descriptor.h"
+#include "mpf_named_event.h"
+#include "mpf_rtp_pt.h"
+
+/* linear PCM (host horder) */
+#define LPCM_CODEC_NAME        "LPCM"
+#define LPCM_CODEC_NAME_LENGTH (sizeof(LPCM_CODEC_NAME)-1)
+
+/* linear PCM atrributes */
+static const mpf_codec_attribs_t lpcm_attribs = {
+       {LPCM_CODEC_NAME, LPCM_CODEC_NAME_LENGTH},    /* codec name */
+       16,                                           /* bits per sample */
+       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 |
+       MPF_SAMPLE_RATE_32000 | MPF_SAMPLE_RATE_48000 /* supported sampling rates */
+};
+
+/** Find matched attribs in codec capabilities by descriptor specified */
+static mpf_codec_attribs_t* mpf_codec_capabilities_attribs_find(const mpf_codec_capabilities_t *capabilities, const mpf_codec_descriptor_t *descriptor);
+
+
+/** Get sampling rate mask (mpf_sample_rate_e) by integer value  */
+MPF_DECLARE(int) mpf_sample_rate_mask_get(apr_uint16_t sampling_rate)
+{
+       switch(sampling_rate) {
+               case 8000:
+                       return MPF_SAMPLE_RATE_8000;
+               case 16000:
+                       return MPF_SAMPLE_RATE_16000;
+               case 32000:
+                       return MPF_SAMPLE_RATE_32000;
+               case 48000:
+                       return MPF_SAMPLE_RATE_48000;
+       }
+       return MPF_SAMPLE_RATE_NONE;
+}
+
+static APR_INLINE apt_bool_t mpf_sampling_rate_check(apr_uint16_t sampling_rate, int mask)
+{
+       return (mpf_sample_rate_mask_get(sampling_rate) & mask) ? TRUE : FALSE;
+}
+
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_lpcm_descriptor_create(apr_uint16_t sampling_rate, apr_byte_t channel_count, apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *descriptor = mpf_codec_descriptor_create(pool);
+       descriptor->payload_type = RTP_PT_UNKNOWN;
+       descriptor->name = lpcm_attribs.name;
+       descriptor->sampling_rate = sampling_rate;
+       descriptor->channel_count = channel_count;
+       return descriptor;
+}
+
+/** Create codec descriptor by capabilities */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_descriptor_create_by_capabilities(const mpf_codec_capabilities_t *capabilities, const mpf_codec_descriptor_t *peer, apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *descriptor;
+       mpf_codec_attribs_t *attribs = NULL;
+       if(capabilities && peer) {
+               attribs = mpf_codec_capabilities_attribs_find(capabilities,peer);
+       }
+       
+       if(!attribs) {
+               return mpf_codec_lpcm_descriptor_create(8000,1,pool);
+       }
+
+       descriptor = mpf_codec_descriptor_create(pool);
+       *descriptor = *peer;
+       if(apt_string_compare(&peer->name,&attribs->name) == FALSE) {
+               descriptor->payload_type = RTP_PT_UNKNOWN;
+               descriptor->name = attribs->name;
+       }
+       return descriptor;
+}
+
 
 /** Match two codec descriptors */
-MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2)
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptors_match(const mpf_codec_descriptor_t *descriptor1, const mpf_codec_descriptor_t *descriptor2)
 {
        apt_bool_t match = FALSE;
-       if(descriptor1->payload_type < 96 && descriptor2->payload_type < 96) {
+       if(descriptor1->payload_type < RTP_PT_DYNAMIC && descriptor2->payload_type < RTP_PT_DYNAMIC) {
                if(descriptor1->payload_type == descriptor2->payload_type) {
                        match = TRUE;
                }
@@ -36,37 +108,158 @@ MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match(const mpf_codec_descriptor_t
        return match;
 }
 
+/** Match specified codec descriptor and the default lpcm one */
+MPF_DECLARE(apt_bool_t) mpf_codec_lpcm_descriptor_match(const mpf_codec_descriptor_t *descriptor)
+{
+       return apt_string_compare(&descriptor->name,&lpcm_attribs.name);
+}
+
+/** Add default (liear PCM) capabilities */
+MPF_DECLARE(apt_bool_t) mpf_codec_default_capabilities_add(mpf_codec_capabilities_t *capabilities)
+{
+       return mpf_codec_capabilities_add(capabilities,MPF_SAMPLE_RATE_8000,lpcm_attribs.name.buf);
+}
+
+/** Match codec descriptors by attribs specified */
+MPF_DECLARE(apt_bool_t) mpf_codec_descriptor_match_by_attribs(mpf_codec_descriptor_t *descriptor, const mpf_codec_descriptor_t *static_descriptor, const mpf_codec_attribs_t *attribs)
+{
+       apt_bool_t match = FALSE;
+       if(descriptor->payload_type < RTP_PT_DYNAMIC) {
+               if(static_descriptor && static_descriptor->payload_type == descriptor->payload_type) {
+                       descriptor->name = static_descriptor->name;
+                       descriptor->sampling_rate = static_descriptor->sampling_rate;
+                       descriptor->channel_count = static_descriptor->channel_count;
+                       match = TRUE;
+               }
+       }
+       else {
+               if(apt_string_compare(&attribs->name,&descriptor->name) == TRUE) {
+                       if(mpf_sampling_rate_check(descriptor->sampling_rate,attribs->sample_rates) == TRUE) {
+                               match = TRUE;
+                       }
+               }
+       }
+       return match;
+}
+
+/** Find matched descriptor in codec list */
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_codec_list_descriptor_find(const mpf_codec_list_t *codec_list, const mpf_codec_descriptor_t *descriptor)
+{
+       int i;
+       mpf_codec_descriptor_t *matched_descriptor;
+       for(i=0; i<codec_list->descriptor_arr->nelts; i++) {
+               matched_descriptor = &APR_ARRAY_IDX(codec_list->descriptor_arr,i,mpf_codec_descriptor_t);
+               if(mpf_codec_descriptors_match(descriptor,matched_descriptor) == TRUE) {
+                       return matched_descriptor;
+               }
+       }
+       return NULL;
+}
+
+/** Find matched attribs in codec capabilities by descriptor specified */
+static mpf_codec_attribs_t* mpf_codec_capabilities_attribs_find(const mpf_codec_capabilities_t *capabilities, const mpf_codec_descriptor_t *descriptor)
+{
+       int i;
+       mpf_codec_attribs_t *attribs;
+       for(i=0; i<capabilities->attrib_arr->nelts; i++) {
+               attribs = &APR_ARRAY_IDX(capabilities->attrib_arr,i,mpf_codec_attribs_t);
+               if(mpf_sampling_rate_check(descriptor->sampling_rate,attribs->sample_rates) == TRUE) {
+                       return attribs;
+               }
+       }
+       return NULL;
+}
+
+/** Modify codec list according to capabilities specified */
+MPF_DECLARE(apt_bool_t) mpf_codec_list_modify(mpf_codec_list_t *codec_list, const mpf_codec_capabilities_t *capabilities)
+{
+       int i;
+       mpf_codec_descriptor_t *descriptor;
+       if(!capabilities) {
+               return FALSE;
+       }
+
+       for(i=0; i<codec_list->descriptor_arr->nelts; i++) {
+               descriptor = &APR_ARRAY_IDX(codec_list->descriptor_arr,i,mpf_codec_descriptor_t);
+               /* match capabilities */
+               if(!mpf_codec_capabilities_attribs_find(capabilities,descriptor)) {
+                       descriptor->enabled = FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
 /** Intersect two codec lists */
-MPF_DECLARE(apt_bool_t) mpf_codec_list_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2)
+MPF_DECLARE(apt_bool_t) mpf_codec_lists_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2)
 {
        int i;
-       int j;
        mpf_codec_descriptor_t *descriptor1;
        mpf_codec_descriptor_t *descriptor2;
-       codec_list1->preffered = NULL;
-       codec_list2->preffered = NULL;
-       /* find only one match, set the matched codec as preffered, disable the others */
+       codec_list1->primary_descriptor = NULL;
+       codec_list1->event_descriptor = NULL;
+       codec_list2->primary_descriptor = NULL;
+       codec_list2->event_descriptor = NULL;
+       /* find only one match for primary and named event descriptors, 
+       set the matched descriptors as preffered, disable the others */
        for(i=0; i<codec_list1->descriptor_arr->nelts; i++) {
-               descriptor1 = (mpf_codec_descriptor_t*)codec_list1->descriptor_arr->elts + i;
-               if(codec_list1->preffered) {
-                       descriptor1->enabled = FALSE;
+               descriptor1 = &APR_ARRAY_IDX(codec_list1->descriptor_arr,i,mpf_codec_descriptor_t);
+               if(descriptor1->enabled == FALSE) {
+                       /* this descriptor has been already disabled, process only enabled ones */
                        continue;
                }
 
-               for(j=0; j<codec_list2->descriptor_arr->nelts; j++) {
-                       descriptor2 = (mpf_codec_descriptor_t*)codec_list2->descriptor_arr->elts + j;
-
-                       descriptor1->enabled = mpf_codec_descriptor_match(descriptor1,descriptor2);
-                       if(descriptor1->enabled == TRUE) {
-                               codec_list1->preffered = descriptor1;
-                               codec_list2->preffered = descriptor2;
-                               break;
+               /* check whether this is a named event descriptor */
+               if(mpf_event_descriptor_check(descriptor1) == TRUE) {
+                       /* named event descriptor */
+                       if(codec_list1->event_descriptor) {
+                               /* named event descriptor has been already set, disable this one */
+                               descriptor1->enabled = FALSE;
+                       }
+                       else {
+                               /* find if there is a match */
+                               descriptor2 = mpf_codec_list_descriptor_find(codec_list2,descriptor1);
+                               if(descriptor2 && descriptor2->enabled == TRUE) {
+                                       descriptor1->enabled = TRUE;
+                                       codec_list1->event_descriptor = descriptor1;
+                                       codec_list2->event_descriptor = descriptor2;
+                               }
+                               else {
+                                       /* no match found, disable this descriptor */
+                                       descriptor1->enabled = FALSE;
+                               }
+                       }
+               }
+               else {
+                       /* primary descriptor */
+                       if(codec_list1->primary_descriptor) {
+                               /* primary descriptor has been already set, disable this one */
+                               descriptor1->enabled = FALSE;
+                       }
+                       else {
+                               /* find if there is a match */
+                               descriptor2 = mpf_codec_list_descriptor_find(codec_list2,descriptor1);
+                               if(descriptor2 && descriptor2->enabled == TRUE) {
+                                       descriptor1->enabled = TRUE;
+                                       codec_list1->primary_descriptor = descriptor1;
+                                       codec_list2->primary_descriptor = descriptor2;
+                               }
+                               else {
+                                       /* no match found, disable this descriptor */
+                                       descriptor1->enabled = FALSE;
+                               }
                        }
                }
        }
-       for(j=0; j<codec_list2->descriptor_arr->nelts; j++) {
-               descriptor2 = (mpf_codec_descriptor_t*)codec_list2->descriptor_arr->elts + j;
-               descriptor2->enabled = (codec_list2->preffered == descriptor2) ? TRUE : FALSE;
+
+       for(i=0; i<codec_list2->descriptor_arr->nelts; i++) {
+               descriptor2 = &APR_ARRAY_IDX(codec_list2->descriptor_arr,i,mpf_codec_descriptor_t);
+               if(descriptor2 == codec_list2->primary_descriptor || descriptor2 == codec_list2->event_descriptor) {
+                       descriptor2->enabled = TRUE;
+               }
+               else {
+                       descriptor2->enabled = FALSE;
+               }
        }
 
        return TRUE;
index da644c7c91be5adf89cfb0a32e5f125e3af90829..ab20a278f94c4011c519e448238bc246e4e487ac 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "mpf_codec.h"
+#include "mpf_rtp_pt.h"
 #include "g711/g711.h"
 
 #define G711u_CODEC_NAME        "PCMU"
@@ -35,14 +36,14 @@ static apt_bool_t g711_close(mpf_codec_t *codec)
 
 static apt_bool_t g711u_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
-       const short *decode_buf;
+       const apr_int16_t *decode_buf;
        unsigned char *encode_buf;
-       apr_uint32_t i;
+       apr_size_t i;
 
        decode_buf = frame_in->buffer;
        encode_buf = frame_out->buffer;
 
-       frame_out->size = frame_in->size / sizeof(short);
+       frame_out->size = frame_in->size / sizeof(apr_int16_t);
 
        for(i=0; i<frame_out->size; i++) {
                encode_buf[i] = linear_to_ulaw(decode_buf[i]);
@@ -53,14 +54,14 @@ static apt_bool_t g711u_encode(mpf_codec_t *codec, const mpf_codec_frame_t *fram
 
 static apt_bool_t g711u_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
-       short *decode_buf;
+       apr_int16_t *decode_buf;
        const unsigned char *encode_buf;
-       apr_uint32_t i;
+       apr_size_t i;
 
        decode_buf = frame_out->buffer;
        encode_buf = frame_in->buffer;
 
-       frame_out->size = frame_in->size * sizeof(short);
+       frame_out->size = frame_in->size * sizeof(apr_int16_t);
 
        for(i=0; i<frame_in->size; i++) {
                decode_buf[i] = ulaw_to_linear(encode_buf[i]);
@@ -71,14 +72,14 @@ static apt_bool_t g711u_decode(mpf_codec_t *codec, const mpf_codec_frame_t *fram
 
 static apt_bool_t g711a_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
-       const short *decode_buf;
+       const apr_int16_t *decode_buf;
        unsigned char *encode_buf;
-       apr_uint32_t i;
+       apr_size_t i;
 
        decode_buf = frame_in->buffer;
        encode_buf = frame_out->buffer;
 
-       frame_out->size = frame_in->size / sizeof(short);
+       frame_out->size = frame_in->size / sizeof(apr_int16_t);
 
        for(i=0; i<frame_out->size; i++) {
                encode_buf[i] = linear_to_alaw(decode_buf[i]);
@@ -89,14 +90,14 @@ static apt_bool_t g711a_encode(mpf_codec_t *codec, const mpf_codec_frame_t *fram
 
 static apt_bool_t g711a_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
-       short *decode_buf;
+       apr_int16_t *decode_buf;
        const unsigned char *encode_buf;
-       apr_uint32_t i;
+       apr_size_t i;
 
        decode_buf = frame_out->buffer;
        encode_buf = frame_in->buffer;
 
-       frame_out->size = frame_in->size * sizeof(short);
+       frame_out->size = frame_in->size * sizeof(apr_int16_t);
 
        for(i=0; i<frame_in->size; i++) {
                decode_buf[i] = alaw_to_linear(encode_buf[i]);
@@ -122,20 +123,20 @@ static const mpf_codec_vtable_t g711a_vtable = {
 };
 
 static const mpf_codec_descriptor_t g711u_descriptor = {
-       0,
+       RTP_PT_PCMU,
        {G711u_CODEC_NAME, G711u_CODEC_NAME_LENGTH},
        8000,
        1,
-       NULL,
+       {NULL, 0},
        TRUE
 };
 
 static const mpf_codec_descriptor_t g711a_descriptor = {
-       8,
+       RTP_PT_PCMA,
        {G711a_CODEC_NAME, G711a_CODEC_NAME_LENGTH},
        8000,
        1,
-       NULL,
+       {NULL,0},
        TRUE
 };
 
index c968c74c18beda1583f5a8381899b8317a6789df..7f342b0a318362dbf9838786a8bc168222f70bb8 100644 (file)
 #define APR_WANT_BYTEFUNC
 #include <apr_want.h>
 #include "mpf_codec.h"
-
-/* linear 16-bit PCM (host horder) */
-#define LPCM_CODEC_NAME        "LPCM"
-#define LPCM_CODEC_NAME_LENGTH (sizeof(LPCM_CODEC_NAME)-1)
+#include "mpf_rtp_pt.h"
 
 /* linear 16-bit PCM (RFC3551) */
 #define L16_CODEC_NAME        "L16"
@@ -40,9 +37,9 @@ static apt_bool_t l16_close(mpf_codec_t *codec)
 static apt_bool_t l16_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
        apr_uint32_t i;
-       const short *buf_in = frame_in->buffer;
-       short *buf_out = frame_out->buffer;
-       apr_size_t samples = frame_in->size / sizeof(short);
+       const apr_int16_t *buf_in = frame_in->buffer;
+       apr_int16_t *buf_out = frame_out->buffer;
+       apr_size_t samples = frame_in->size / sizeof(apr_int16_t);
 
        frame_out->size = frame_in->size;
 
@@ -56,9 +53,9 @@ static apt_bool_t l16_encode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_
 static apt_bool_t l16_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_in, mpf_codec_frame_t *frame_out)
 {
        apr_uint32_t i;
-       const short *buf_in = frame_in->buffer;
-       short *buf_out = frame_out->buffer;
-       apr_size_t samples = frame_in->size / sizeof(short);
+       const apr_int16_t *buf_in = frame_in->buffer;
+       apr_int16_t *buf_out = frame_out->buffer;
+       apr_size_t samples = frame_in->size / sizeof(apr_int16_t);
 
        frame_out->size = frame_in->size;
 
@@ -69,12 +66,6 @@ static apt_bool_t l16_decode(mpf_codec_t *codec, const mpf_codec_frame_t *frame_
        return TRUE;
 }
 
-
-
-static const mpf_codec_vtable_t lpcm_vtable = {
-       NULL
-};
-
 static const mpf_codec_vtable_t l16_vtable = {
        l16_open,
        l16_close,
@@ -83,13 +74,6 @@ static const mpf_codec_vtable_t l16_vtable = {
        NULL
 };
 
-static const mpf_codec_attribs_t lpcm_attribs = {
-       {LPCM_CODEC_NAME, LPCM_CODEC_NAME_LENGTH},    /* codec name */
-       16,                                           /* bits per sample */
-       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000 |
-       MPF_SAMPLE_RATE_32000 | MPF_SAMPLE_RATE_48000 /* supported sampling rates */
-};
-
 static const mpf_codec_attribs_t l16_attribs = {
        {L16_CODEC_NAME, L16_CODEC_NAME_LENGTH},      /* codec name */
        16,                                           /* bits per sample */
@@ -97,23 +81,6 @@ static const mpf_codec_attribs_t l16_attribs = {
        MPF_SAMPLE_RATE_32000 | MPF_SAMPLE_RATE_48000 /* supported sampling rates */
 };
 
-mpf_codec_descriptor_t* mpf_codec_lpcm_descriptor_create(apr_uint16_t sampling_rate, apr_byte_t channel_count, apr_pool_t *pool)
-{
-       mpf_codec_descriptor_t *descriptor = apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
-       mpf_codec_descriptor_init(descriptor);
-       descriptor->payload_type = 96;
-       descriptor->name.buf = LPCM_CODEC_NAME;
-       descriptor->name.length = LPCM_CODEC_NAME_LENGTH;
-       descriptor->sampling_rate = sampling_rate;
-       descriptor->channel_count = channel_count;
-       return descriptor;
-}
-
-mpf_codec_t* mpf_codec_lpcm_create(apr_pool_t *pool)
-{
-       return mpf_codec_create(&lpcm_vtable,&lpcm_attribs,NULL,pool);
-}
-
 mpf_codec_t* mpf_codec_l16_create(apr_pool_t *pool)
 {
        return mpf_codec_create(&l16_vtable,&l16_attribs,NULL,pool);
index 15bda89c51601e324c77ef9add5cd42aad6fd934..b83581a25a056c25715888e8f1565cc1046f38df 100644 (file)
 
 #include <stdlib.h>
 #include "mpf_codec_manager.h"
+#include "mpf_rtp_pt.h"
+#include "mpf_named_event.h"
 #include "apt_log.h"
 
 
 struct mpf_codec_manager_t {
        /** Memory pool */
-       apr_pool_t   *pool;
+       apr_pool_t             *pool;
 
-       /** Dynamic array of codecs (mpf_codec_t*) */
-       apr_array_header_t *codec_arr;
+       /** Dynamic (resizable) array of codecs (mpf_codec_t*) */
+       apr_array_header_t     *codec_arr;
+       /** Default named event descriptor */
+       mpf_codec_descriptor_t *event_descriptor;
 };
 
 
-mpf_codec_descriptor_t* mpf_codec_lpcm_descriptor_create(apr_uint16_t sampling_rate, apr_byte_t channel_count, apr_pool_t *pool);
-
 MPF_DECLARE(mpf_codec_manager_t*) mpf_codec_manager_create(apr_size_t codec_count, apr_pool_t *pool)
 {
        mpf_codec_manager_t *codec_manager = apr_palloc(pool,sizeof(mpf_codec_manager_t));
        codec_manager->pool = pool;
        codec_manager->codec_arr = apr_array_make(pool,(int)codec_count,sizeof(mpf_codec_t*));
+       codec_manager->event_descriptor = mpf_event_descriptor_create(8000,pool);
        return codec_manager;
 }
 
@@ -45,62 +48,32 @@ MPF_DECLARE(void) mpf_codec_manager_destroy(mpf_codec_manager_t *codec_manager)
 
 MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_register(mpf_codec_manager_t *codec_manager, mpf_codec_t *codec)
 {
-       mpf_codec_t **slot;
        if(!codec || !codec->attribs || !codec->attribs->name.buf) {
                return FALSE;
        }
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Codec [%s]",codec->attribs->name.buf);
 
-       slot = apr_array_push(codec_manager->codec_arr);
-       *slot = codec;
+       APR_ARRAY_PUSH(codec_manager->codec_arr,mpf_codec_t*) = codec;
        return TRUE;
 }
 
 MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_codec_get(const mpf_codec_manager_t *codec_manager, mpf_codec_descriptor_t *descriptor, apr_pool_t *pool)
 {
        int i;
-       mpf_codec_t *codec = NULL;
-       mpf_codec_t *ret_codec = NULL;
+       mpf_codec_t *codec;
        if(!descriptor) {
                return NULL;
        }
 
        for(i=0; i<codec_manager->codec_arr->nelts; i++) {
-               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
-               if(descriptor->payload_type < 96) {
-                       if(codec->static_descriptor && codec->static_descriptor->payload_type == descriptor->payload_type) {
-                               descriptor->name = codec->static_descriptor->name;
-                               descriptor->sampling_rate = codec->static_descriptor->sampling_rate;
-                               descriptor->channel_count = codec->static_descriptor->channel_count;
-                               break;
-                       }
-               }
-               else {
-                       if(apt_string_compare(&codec->attribs->name,&descriptor->name) == TRUE) {
-                               /* sampling rate must be checked as well */
-                               break;
-                       }
+               codec = APR_ARRAY_IDX(codec_manager->codec_arr,i,mpf_codec_t*);
+               if(mpf_codec_descriptor_match_by_attribs(descriptor,codec->static_descriptor,codec->attribs) == TRUE) {
+                       return mpf_codec_clone(codec,pool);
                }
        }
 
-       if(i == codec_manager->codec_arr->nelts) {
-               /* no match found */
-               return NULL;
-       }
-       if(codec) {
-               ret_codec = mpf_codec_clone(codec,pool);
-               ret_codec->descriptor = descriptor;
-       }
-       return ret_codec;
-}
-
-MPF_DECLARE(mpf_codec_t*) mpf_codec_manager_default_codec_get(const mpf_codec_manager_t *codec_manager, apr_pool_t *pool)
-{
-       mpf_codec_t *codec;
-       mpf_codec_descriptor_t *descriptor = mpf_codec_lpcm_descriptor_create(8000,1,pool);
-       codec = mpf_codec_manager_codec_get(codec_manager,descriptor,pool);
-       return codec;
+       return NULL;
 }
 
 MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager_t *codec_manager, mpf_codec_list_t *codec_list, apr_pool_t *pool)
@@ -112,7 +85,7 @@ MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager
 
        mpf_codec_list_init(codec_list,codec_manager->codec_arr->nelts,pool);
        for(i=0; i<codec_manager->codec_arr->nelts; i++) {
-               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
+               codec = APR_ARRAY_IDX(codec_manager->codec_arr,i,mpf_codec_t*);
                static_descriptor = codec->static_descriptor;
                if(static_descriptor) {
                        descriptor = mpf_codec_list_add(codec_list);
@@ -121,6 +94,12 @@ MPF_DECLARE(apt_bool_t) mpf_codec_manager_codec_list_get(const mpf_codec_manager
                        }
                }
        }
+       if(codec_manager->event_descriptor) {
+               descriptor = mpf_codec_list_add(codec_list);
+               if(descriptor) {
+                       *descriptor = *codec_manager->event_descriptor;
+               }
+       }
        return TRUE;
 }
 
@@ -138,26 +117,35 @@ static apt_bool_t mpf_codec_manager_codec_parse(const mpf_codec_manager_t *codec
                apt_string_assign(&name,str,pool);
                /* find codec by name */
                codec = mpf_codec_manager_codec_find(codec_manager,&name);
-               if(!codec) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Codec [%s]",str);
-                       return FALSE;
-               }
-
-               descriptor = mpf_codec_list_add(codec_list);
-               descriptor->name = name;
+               if(codec) {
+                       descriptor = mpf_codec_list_add(codec_list);
+                       descriptor->name = name;
 
-               /* set defualt attributes */
-               if(codec->static_descriptor) {
-                       descriptor->payload_type = codec->static_descriptor->payload_type;
-                       descriptor->sampling_rate = codec->static_descriptor->sampling_rate;
-                       descriptor->channel_count = codec->static_descriptor->channel_count;
+                       /* set default attributes */
+                       if(codec->static_descriptor) {
+                               descriptor->payload_type = codec->static_descriptor->payload_type;
+                               descriptor->sampling_rate = codec->static_descriptor->sampling_rate;
+                               descriptor->channel_count = codec->static_descriptor->channel_count;
+                       }
+                       else {
+                               descriptor->payload_type = RTP_PT_DYNAMIC;
+                               descriptor->sampling_rate = 8000;
+                               descriptor->channel_count = 1;
+                       }
                }
                else {
-                       descriptor->payload_type = 96;
-                       descriptor->sampling_rate = 8000;
-                       descriptor->channel_count = 1;
+                       mpf_codec_descriptor_t *event_descriptor = codec_manager->event_descriptor;
+                       if(event_descriptor && apt_string_compare(&event_descriptor->name,&name) == TRUE) {
+                               descriptor = mpf_codec_list_add(codec_list);
+                               *descriptor = *event_descriptor;
+                       }
+                       else {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Codec [%s]",str);
+                               return FALSE;
+                       }
                }
 
+
                /* parse optional payload type */
                str = apr_strtok(codec_desc_str, separator, &state);
                if(str) {
@@ -200,7 +188,7 @@ MPF_DECLARE(const mpf_codec_t*) mpf_codec_manager_codec_find(const mpf_codec_man
        int i;
        mpf_codec_t *codec;
        for(i=0; i<codec_manager->codec_arr->nelts; i++) {
-               codec = ((mpf_codec_t**)codec_manager->codec_arr->elts)[i];
+               codec = APR_ARRAY_IDX(codec_manager->codec_arr,i,mpf_codec_t*);
                if(apt_string_compare(&codec->attribs->name,codec_name) == TRUE) {
                        return codec;
                }
index b2091547536ceaa4ae21aefcad4ae5996dfe2178..c6978d8e37aba023f226896abdd7984d864655c1 100644 (file)
  * limitations under the License.
  */
 
+#ifdef WIN32
+#pragma warning(disable: 4127)
+#endif
+#include <apr_ring.h> 
 #include "mpf_context.h"
 #include "mpf_termination.h"
 #include "mpf_stream.h"
-#include "mpf_encoder.h"
-#include "mpf_decoder.h"
 #include "mpf_bridge.h"
+#include "mpf_multiplier.h"
+#include "mpf_mixer.h"
 #include "apt_log.h"
 
-static mpf_object_t* mpf_context_connection_create(mpf_context_t *context, mpf_termination_t *src_termination, mpf_termination_t *sink_termination);
+/** Item of the association matrix */
+typedef struct {
+       unsigned char on;
+} matrix_item_t;
 
-MPF_DECLARE(mpf_context_t*) mpf_context_create(void *obj, apr_size_t max_termination_count, apr_pool_t *pool)
+/** Item of the association matrix header */
+typedef struct {
+       mpf_termination_t *termination;
+       unsigned char      tx_count;
+       unsigned char      rx_count;
+} header_item_t;
+
+/** Media processing context */
+struct mpf_context_t {
+       /** Ring entry */
+       APR_RING_ENTRY(mpf_context_t) link;
+       /** Back pointer to the context factory */
+       mpf_context_factory_t        *factory;
+       /** Pool to allocate memory from */
+       apr_pool_t                   *pool;
+       /** External object */
+       void                         *obj;
+
+       /** Max number of terminations in the context */
+       apr_size_t                    capacity;
+       /** Current number of terminations in the context */
+       apr_size_t                    count;
+       /** Header of the association matrix */
+       header_item_t                *header;
+       /** Association matrix, which represents the topology */
+       matrix_item_t                **matrix;
+
+       /** Array of media processing objects constructed while 
+       applying topology based on association matrix */
+       apr_array_header_t           *mpf_objects;
+};
+
+/** Factory of media contexts */
+struct mpf_context_factory_t {
+       /** Ring head */
+       APR_RING_HEAD(mpf_context_head_t, mpf_context_t) head;
+};
+
+
+static APR_INLINE apt_bool_t stream_direction_compatibility_check(mpf_termination_t *termination1, mpf_termination_t *termination2);
+static mpf_object_t* mpf_context_bridge_create(mpf_context_t *context, apr_size_t i);
+static mpf_object_t* mpf_context_multiplier_create(mpf_context_t *context, apr_size_t i);
+static mpf_object_t* mpf_context_mixer_create(mpf_context_t *context, apr_size_t j);
+
+
+MPF_DECLARE(mpf_context_factory_t*) mpf_context_factory_create(apr_pool_t *pool)
+{
+       mpf_context_factory_t *factory = apr_palloc(pool, sizeof(mpf_context_factory_t));
+       APR_RING_INIT(&factory->head, mpf_context_t, link);
+       return factory;
+}
+
+MPF_DECLARE(void) mpf_context_factory_destroy(mpf_context_factory_t *factory)
+{
+       mpf_context_t *context;
+       while(!APR_RING_EMPTY(&factory->head, mpf_context_t, link)) {
+               context = APR_RING_FIRST(&factory->head);
+               mpf_context_destroy(context);
+               APR_RING_REMOVE(context, link);
+       }
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_factory_process(mpf_context_factory_t *factory)
+{
+       mpf_context_t *context;
+       for(context = APR_RING_FIRST(&factory->head);
+                       context != APR_RING_SENTINEL(&factory->head, mpf_context_t, link);
+                               context = APR_RING_NEXT(context, link)) {
+               
+               mpf_context_process(context);
+       }
+
+       return TRUE;
+}
+
+MPF_DECLARE(mpf_context_t*) mpf_context_create(
+                                                               mpf_context_factory_t *factory,
+                                                               void *obj,
+                                                               apr_size_t max_termination_count,
+                                                               apr_pool_t *pool)
 {
        apr_size_t i,j;
+       matrix_item_t *matrix_item;
+       header_item_t *header_item;
        mpf_context_t *context = apr_palloc(pool,sizeof(mpf_context_t));
+       context->factory = factory;
        context->obj = obj;
        context->pool = pool;
-       context->elem = NULL;
-       context->max_termination_count = max_termination_count;
-       context->termination_count = 0;
-       context->table = apr_palloc(pool,sizeof(table_item_t)*max_termination_count);
-       for(i=0; i<max_termination_count; i++) {
-               context->table[i] = apr_palloc(pool,sizeof(table_item_t)*max_termination_count);
-               for(j=0; j<max_termination_count; j++) {
-                       context->table[i][j] = NULL;
+       context->capacity = max_termination_count;
+       context->count = 0;
+       context->mpf_objects = apr_array_make(pool,1,sizeof(mpf_object_t*));
+       context->header = apr_palloc(pool,context->capacity * sizeof(header_item_t));
+       context->matrix = apr_palloc(pool,context->capacity * sizeof(matrix_item_t*));
+       for(i=0; i<context->capacity; i++) {
+               header_item = &context->header[i];
+               header_item->termination = NULL;
+               header_item->tx_count = 0;
+               header_item->rx_count = 0;
+               context->matrix[i] = apr_palloc(pool,context->capacity * sizeof(matrix_item_t));
+               for(j=0; j<context->capacity; j++) {
+                       matrix_item = &context->matrix[i][j];
+                       matrix_item->on = 0;
                }
        }
 
@@ -47,15 +143,12 @@ MPF_DECLARE(mpf_context_t*) mpf_context_create(void *obj, apr_size_t max_termina
 MPF_DECLARE(apt_bool_t) mpf_context_destroy(mpf_context_t *context)
 {
        apr_size_t i;
-       apr_size_t count = context->max_termination_count;
        mpf_termination_t *termination;
-       for(i=0; i<count; i++){
-               termination = context->table[i][i];
+       for(i=0; i<context->capacity; i++){
+               termination = context->header[i].termination;
                if(termination) {
                        mpf_context_termination_subtract(context,termination);
-                       if(termination->audio_stream) {
-                               mpf_audio_stream_destroy(termination->audio_stream);
-                       }
+                       mpf_termination_subtract(termination);
                }
        }
        return TRUE;
@@ -69,164 +162,376 @@ MPF_DECLARE(void*) mpf_context_object_get(mpf_context_t *context)
 MPF_DECLARE(apt_bool_t) mpf_context_termination_add(mpf_context_t *context, mpf_termination_t *termination)
 {
        apr_size_t i;
-       apr_size_t count = context->max_termination_count;
-       for(i=0; i<count; i++) {
-               if(!context->table[i][i]) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Termination");
-                       context->table[i][i] = termination;
-                       termination->slot = i;
-                       context->termination_count++;
-                       return TRUE;
+       header_item_t *header_item;
+       for(i=0; i<context->capacity; i++) {
+               header_item = &context->header[i];
+               if(header_item->termination) {
+                       continue;
                }
+               if(!context->count) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Context");
+                       APR_RING_INSERT_TAIL(&context->factory->head,context,mpf_context_t,link);
+               }
+
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Termination");
+               header_item->termination = termination;
+               header_item->tx_count = 0;
+               header_item->rx_count = 0;
+               
+               termination->slot = i;
+               context->count++;
+               return TRUE;
        }
        return FALSE;
 }
 
 MPF_DECLARE(apt_bool_t) mpf_context_termination_subtract(mpf_context_t *context, mpf_termination_t *termination)
 {
+       header_item_t *header_item1;
+       header_item_t *header_item2;
+       matrix_item_t *item;
+       apr_size_t j,k;
        apr_size_t i = termination->slot;
-       if(i >= context->max_termination_count) {
+       if(i >= context->capacity) {
                return FALSE;
        }
-       if(context->table[i][i] != termination) {
+       header_item1 = &context->header[i];
+       if(header_item1->termination != termination) {
                return FALSE;
        }
 
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination");
-       context->table[i][i] = NULL;
+       for(j=0,k=0; j<context->capacity && k<context->count; j++) {
+               header_item2 = &context->header[j];
+               if(!header_item2->termination) {
+                       continue;
+               }
+               k++;
+
+               item = &context->matrix[i][j];
+               if(item->on) {
+                       item->on = 0;
+                       header_item1->tx_count--;
+                       header_item2->rx_count--;
+               }
+
+               item = &context->matrix[j][i];
+               if(item->on) {
+                       item->on = 0;
+                       header_item2->tx_count--;
+                       header_item1->rx_count--;
+               }
+       }
+       header_item1->termination = NULL;
+
        termination->slot = (apr_size_t)-1;
-       context->termination_count--;
+       context->count--;
+       if(!context->count) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Context");
+               APR_RING_REMOVE(context,link);
+       }
        return TRUE;
 }
 
-MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context)
+MPF_DECLARE(apt_bool_t) mpf_context_association_add(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2)
 {
-       mpf_object_t *object;
-       apr_size_t i,j;
-       for(i=0; i<context->max_termination_count; i++) {
-               for(j=0; j<context->max_termination_count; j++) {
-                       if(i==j) continue;
+       header_item_t *header_item1;
+       matrix_item_t *matrix_item1;
+       header_item_t *header_item2;
+       matrix_item_t *matrix_item2;
+       apr_size_t i = termination1->slot;
+       apr_size_t j = termination2->slot;
+       if(i >= context->capacity || j >= context->capacity) {
+               return FALSE;
+       }
 
-                       object = context->table[i][j];
-                       if(object && object->process) {
-                               object->process(object);
-                       }
+       header_item1 = &context->header[i];
+       header_item2 = &context->header[j];
+
+       if(header_item1->termination != termination1 || header_item2->termination != termination2) {
+               return FALSE;
+       }
+
+       matrix_item1 = &context->matrix[i][j];
+       matrix_item2 = &context->matrix[j][i];
+
+       /* 1 -> 2 */
+       if(!matrix_item1->on) {
+               if(stream_direction_compatibility_check(header_item1->termination,header_item2->termination) == TRUE) {
+                       matrix_item1->on = 1;
+                       header_item1->tx_count ++;
+                       header_item2->rx_count ++;
+               }
+       }
+
+       /* 2 -> 1 */
+       if(!matrix_item2->on) {
+               if(stream_direction_compatibility_check(header_item2->termination,header_item1->termination) == TRUE) {
+                       matrix_item2->on = 1;
+                       header_item2->tx_count ++;
+                       header_item1->rx_count ++;
                }
        }
        return TRUE;
 }
 
-MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context, mpf_termination_t *termination)
+MPF_DECLARE(apt_bool_t) mpf_context_association_remove(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2)
 {
-       apr_size_t i,j;
-       mpf_object_t *object;
-       mpf_termination_t *sink_termination;
-       mpf_termination_t *source_termination;
-       if(context->termination_count <= 1) {
-               /* at least 2 terminations are required to apply topology on them */
-               return TRUE;
+       header_item_t *header_item1;
+       matrix_item_t *matrix_item1;
+       header_item_t *header_item2;
+       matrix_item_t *matrix_item2;
+       apr_size_t i = termination1->slot;
+       apr_size_t j = termination2->slot;
+       if(i >= context->capacity || j >= context->capacity) {
+               return FALSE;
        }
 
-       i = termination->slot;
-       for(j=0; j<context->max_termination_count; j++) {
-               if(i == j) continue;
+       header_item1 = &context->header[i];
+       header_item2 = &context->header[j];
 
-               sink_termination = context->table[j][j];
-               object = mpf_context_connection_create(context,termination,sink_termination);
-               if(object) {
-                       context->table[i][j] = object;
-               }
+       if(header_item1->termination != termination1 || header_item2->termination != termination2) {
+               return FALSE;
        }
 
-       j = termination->slot;
-       for(i=0; i<context->max_termination_count; i++) {
-               if(i == j) continue;
+       matrix_item1 = &context->matrix[i][j];
+       matrix_item2 = &context->matrix[j][i];
 
-               source_termination = context->table[i][i];
-               object = mpf_context_connection_create(context,source_termination,termination);
-               if(object) {
-                       context->table[i][j] = object;
-               }
+       /* 1 -> 2 */
+       if(matrix_item1->on == 1) {
+               matrix_item1->on = 0;
+               header_item1->tx_count --;
+               header_item2->rx_count --;
        }
 
+       /* 2 -> 1 */
+       if(matrix_item2->on == 1) {
+               matrix_item2->on = 0;
+               header_item2->tx_count --;
+               header_item1->rx_count --;
+       }
        return TRUE;
 }
 
-MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context, mpf_termination_t *termination)
+MPF_DECLARE(apt_bool_t) mpf_context_associations_reset(mpf_context_t *context)
 {
-       apr_size_t i,j;
-       mpf_object_t *object;
-       if(context->termination_count <= 1) {
-               /* at least 2 terminations are required to destroy topology */
-               return TRUE;
-       }
+       apr_size_t i,j,k;
+       header_item_t *header_item1;
+       header_item_t *header_item2;
+       matrix_item_t *item;
+
+       /* destroy existing topology / if any */
+       mpf_context_topology_destroy(context);
 
-       i = termination->slot;
-       for(j=0; j<context->max_termination_count; j++) {
-               if(i == j) continue;
+       /* reset assigned associations */
+       for(i=0,k=0; i<context->capacity && k<context->count; i++) {
+               header_item1 = &context->header[i];
+               if(!header_item1->termination) {
+                       continue;
+               }
+               k++;
+               
+               if(!header_item1->tx_count && !header_item1->rx_count) {
+                       continue;
+               }
+               
+               for(j=i; j<context->capacity; j++) {
+                       header_item2 = &context->header[j];
+                       if(!header_item2->termination) {
+                               continue;
+                       }
+                       
+                       item = &context->matrix[i][j];
+                       if(item->on) {
+                               item->on = 0;
+                               header_item1->tx_count--;
+                               header_item2->rx_count--;
+                       }
 
-               object = context->table[i][j];
-               if(object) {
-                       if(object->destroy) {
-                               object->destroy(object);
+                       item = &context->matrix[j][i];
+                       if(item->on) {
+                               item->on = 0;
+                               header_item2->tx_count--;
+                               header_item1->rx_count--;
                        }
-                       context->table[i][j] = NULL;
                }
        }
+       return TRUE;
+}
 
-       j = termination->slot;
-       for(i=0; i<context->max_termination_count; i++) {
-               if(i == j) continue;
+static apt_bool_t mpf_context_object_add(mpf_context_t *context, mpf_object_t *object)
+{
+       if(!object) {
+               return FALSE;
+       }
+       
+       APR_ARRAY_PUSH(context->mpf_objects, mpf_object_t*) = object;
+#if 1
+       mpf_object_trace(object);
+#endif
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context)
+{
+       apr_size_t i,k;
+       header_item_t *header_item;
+       mpf_object_t *object;
+       
+       /* first destroy existing topology / if any */
+       mpf_context_topology_destroy(context);
 
-               object = context->table[i][j];
-               if(object) {
-                       if(object->destroy) {
-                               object->destroy(object);
+       for(i=0,k=0; i<context->capacity && k<context->count; i++) {
+               header_item = &context->header[i];
+               if(!header_item->termination) {
+                       continue;
+               }
+               k++;
+               
+               if(header_item->tx_count > 0) {
+                       object = NULL;
+                       if(header_item->tx_count == 1) {
+                               object = mpf_context_bridge_create(context,i);
                        }
-                       context->table[i][j] = NULL;
+                       else { /* tx_count > 1 */
+                               object = mpf_context_multiplier_create(context,i);
+                       }
+
+                       mpf_context_object_add(context,object);
+               }
+               if(header_item->rx_count > 1) {
+                       object = mpf_context_mixer_create(context,i);
+                       mpf_context_object_add(context,object);
                }
        }
+
        return TRUE;
 }
 
-static mpf_object_t* mpf_context_connection_create(mpf_context_t *context, mpf_termination_t *src_termination, mpf_termination_t *sink_termination)
+MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context)
 {
-       mpf_object_t *object = NULL;
-       mpf_audio_stream_t *source;
-       mpf_audio_stream_t *sink;
-       if(!src_termination || !sink_termination) {
-               return NULL;
+       if(context->mpf_objects->nelts) {
+               int i;
+               mpf_object_t *object;
+               for(i=0; i<context->mpf_objects->nelts; i++) {
+                       object = APR_ARRAY_IDX(context->mpf_objects,i,mpf_object_t*);
+                       mpf_object_destroy(object);
+               }
+               apr_array_clear(context->mpf_objects);
        }
-       source = src_termination->audio_stream;
-       sink = sink_termination->audio_stream;
-       if(source && (source->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE &&
-               sink && (sink->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
-               mpf_codec_t *rx_codec = source->rx_codec;
-               mpf_codec_t *tx_codec = sink->tx_codec;
-               if(rx_codec && tx_codec) {
-                       if(mpf_codec_descriptor_match(rx_codec->descriptor,tx_codec->descriptor) == TRUE) {
-                               object = mpf_null_bridge_create(source,sink,context->pool);
-                       }
-                       else {
-                               if(rx_codec->descriptor->sampling_rate != tx_codec->descriptor->sampling_rate) {
-                                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,
-                                               "Resampling is not supported now. "
-                                               "Try to configure and use the same sampling rate on both ends");
-                                       return NULL;
-                               }
-                               if(rx_codec->vtable && rx_codec->vtable->decode) {
-                                       /* set decoder before bridge */
-                                       mpf_audio_stream_t *decoder = mpf_decoder_create(source,context->pool);
-                                       source = decoder;
-                               }
-                               if(tx_codec->vtable && tx_codec->vtable->encode) {
-                                       /* set encoder after bridge */
-                                       mpf_audio_stream_t *encoder = mpf_encoder_create(sink,context->pool);
-                                       sink = encoder;
-                               }
-                               object = mpf_bridge_create(source,sink,context->pool);
-                       }
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context)
+{
+       int i;
+       mpf_object_t *object;
+       for(i=0; i<context->mpf_objects->nelts; i++) {
+               object = APR_ARRAY_IDX(context->mpf_objects,i,mpf_object_t*);
+               if(object && object->process) {
+                       object->process(object);
                }
        }
-       return object;
+       return TRUE;
+}
+
+
+static mpf_object_t* mpf_context_bridge_create(mpf_context_t *context, apr_size_t i)
+{
+       header_item_t *header_item1 = &context->header[i];
+       header_item_t *header_item2;
+       matrix_item_t *item;
+       apr_size_t j;
+       for(j=0; j<context->capacity; j++) {
+               header_item2 = &context->header[j];
+               if(!header_item2->termination) {
+                       continue;
+               }
+               item = &context->matrix[i][j];
+               if(!item->on) {
+                       continue;
+               }
+
+               if(header_item2->rx_count > 1) {
+                       /* mixer will be created instead */
+                       return NULL;
+               }
+               
+               /* create bridge i -> j */
+               if(header_item1->termination && header_item2->termination) {
+                       return mpf_bridge_create(
+                               header_item1->termination->audio_stream,
+                               header_item2->termination->audio_stream,
+                               header_item1->termination->codec_manager,
+                               context->pool);
+               }
+       }
+       return NULL;
+}
+
+static mpf_object_t* mpf_context_multiplier_create(mpf_context_t *context, apr_size_t i)
+{
+       mpf_audio_stream_t **sink_arr;
+       header_item_t *header_item1 = &context->header[i];
+       header_item_t *header_item2;
+       matrix_item_t *item;
+       apr_size_t j,k;
+       sink_arr = apr_palloc(context->pool,header_item1->tx_count * sizeof(mpf_audio_stream_t*));
+       for(j=0,k=0; j<context->capacity && k<header_item1->tx_count; j++) {
+               header_item2 = &context->header[j];
+               if(!header_item2->termination) {
+                       continue;
+               }
+               item = &context->matrix[i][j];
+               if(!item->on) {
+                       continue;
+               }
+               sink_arr[k] = header_item2->termination->audio_stream;
+               k++;
+       }
+       return mpf_multiplier_create(
+                               header_item1->termination->audio_stream,
+                               sink_arr,
+                               header_item1->tx_count,
+                               header_item1->termination->codec_manager,
+                               context->pool);
+}
+
+static mpf_object_t* mpf_context_mixer_create(mpf_context_t *context, apr_size_t j)
+{
+       mpf_audio_stream_t **source_arr;
+       header_item_t *header_item1 = &context->header[j];
+       header_item_t *header_item2;
+       matrix_item_t *item;
+       apr_size_t i,k;
+       source_arr = apr_palloc(context->pool,header_item1->rx_count * sizeof(mpf_audio_stream_t*));
+       for(i=0,k=0; i<context->capacity && k<header_item1->rx_count; i++) {
+               header_item2 = &context->header[i];
+               if(!header_item2->termination) {
+                       continue;
+               }
+               item = &context->matrix[i][j];
+               if(!item->on) {
+                       continue;
+               }
+               source_arr[k] = header_item2->termination->audio_stream;
+               k++;
+       }
+       return mpf_mixer_create(
+                               source_arr,
+                               header_item1->rx_count,
+                               header_item1->termination->audio_stream,
+                               header_item1->termination->codec_manager,
+                               context->pool);
+}
+
+static APR_INLINE apt_bool_t stream_direction_compatibility_check(mpf_termination_t *termination1, mpf_termination_t *termination2)
+{
+       mpf_audio_stream_t *source = termination1->audio_stream;
+       mpf_audio_stream_t *sink = termination2->audio_stream;
+       if(source && (source->direction & STREAM_DIRECTION_RECEIVE) == STREAM_DIRECTION_RECEIVE &&
+               sink && (sink->direction & STREAM_DIRECTION_SEND) == STREAM_DIRECTION_SEND) {
+               return TRUE;
+       }
+       return FALSE;
 }
index 2add5e43d04f769d2cbf2e15ca4e0a13d54fa901..878dbbf459cd1a8b5adb100d9f21d7641b5f738f 100644 (file)
@@ -22,6 +22,7 @@ typedef struct mpf_decoder_t mpf_decoder_t;
 struct mpf_decoder_t {
        mpf_audio_stream_t *base;
        mpf_audio_stream_t *source;
+       mpf_codec_t        *codec;
        mpf_frame_t         frame_in;
 };
 
@@ -32,10 +33,10 @@ static apt_bool_t mpf_decoder_destroy(mpf_audio_stream_t *stream)
        return mpf_audio_stream_destroy(decoder->source);
 }
 
-static apt_bool_t mpf_decoder_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_decoder_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        mpf_decoder_t *decoder = stream->obj;
-       return mpf_audio_stream_rx_open(decoder->source);
+       return mpf_audio_stream_rx_open(decoder->source,decoder->codec);
 }
 
 static apt_bool_t mpf_decoder_close(mpf_audio_stream_t *stream)
@@ -47,20 +48,41 @@ static apt_bool_t mpf_decoder_close(mpf_audio_stream_t *stream)
 static apt_bool_t mpf_decoder_process(mpf_audio_stream_t *stream, mpf_frame_t *frame)
 {
        mpf_decoder_t *decoder = stream->obj;
+       decoder->frame_in.type = MEDIA_FRAME_TYPE_NONE;
+       decoder->frame_in.marker = MPF_MARKER_NONE;
        if(mpf_audio_stream_frame_read(decoder->source,&decoder->frame_in) != TRUE) {
                return FALSE;
        }
 
        frame->type = decoder->frame_in.type;
+       frame->marker = decoder->frame_in.marker;
        if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
                frame->event_frame = decoder->frame_in.event_frame;
        }
        if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
-               mpf_codec_decode(decoder->source->rx_codec,&decoder->frame_in.codec_frame,&frame->codec_frame);
+               mpf_codec_decode(decoder->codec,&decoder->frame_in.codec_frame,&frame->codec_frame);
        }
        return TRUE;
 }
 
+static void mpf_decoder_trace(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output)
+{
+       apr_size_t offset;
+       mpf_codec_descriptor_t *descriptor;
+       mpf_decoder_t *decoder = stream->obj;
+
+       mpf_audio_stream_trace(decoder->source,direction,output);
+
+       descriptor = decoder->base->rx_descriptor;
+       if(descriptor) {
+               offset = output->pos - output->text.buf;
+               output->pos += apr_snprintf(output->pos, output->text.length - offset,
+                       "->Decoder->[%s/%d/%d]",
+                       descriptor->name.buf,
+                       descriptor->sampling_rate,
+                       descriptor->channel_count);
+       }
+}
 
 static const mpf_audio_stream_vtable_t vtable = {
        mpf_decoder_destroy,
@@ -69,24 +91,34 @@ static const mpf_audio_stream_vtable_t vtable = {
        mpf_decoder_process,
        NULL,
        NULL,
-       NULL
+       NULL,
+       mpf_decoder_trace
 };
 
-MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, apr_pool_t *pool)
+MPF_DECLARE(mpf_audio_stream_t*) mpf_decoder_create(mpf_audio_stream_t *source, mpf_codec_t *codec, apr_pool_t *pool)
 {
        apr_size_t frame_size;
-       mpf_codec_t *codec;
        mpf_decoder_t *decoder;
-       if(!source || !source->rx_codec) {
+       mpf_stream_capabilities_t *capabilities;
+       if(!source || !codec) {
                return NULL;
        }
        decoder = apr_palloc(pool,sizeof(mpf_decoder_t));
-       decoder->base = mpf_audio_stream_create(decoder,&vtable,STREAM_MODE_RECEIVE,pool);
+       capabilities = mpf_stream_capabilities_create(STREAM_DIRECTION_RECEIVE,pool);
+       decoder->base = mpf_audio_stream_create(decoder,&vtable,capabilities,pool);
+       if(!decoder->base) {
+               return NULL;
+       }
+       decoder->base->rx_descriptor = mpf_codec_lpcm_descriptor_create(
+               source->rx_descriptor->sampling_rate,
+               source->rx_descriptor->channel_count,
+               pool);
+       decoder->base->rx_event_descriptor = source->rx_event_descriptor;
+
        decoder->source = source;
+       decoder->codec = codec;
 
-       codec = source->rx_codec;
-       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
-       decoder->base->rx_codec = codec;
+       frame_size = mpf_codec_frame_size_calculate(source->rx_descriptor,codec->attribs);
        decoder->frame_in.codec_frame.size = frame_size;
        decoder->frame_in.codec_frame.buffer = apr_palloc(pool,frame_size);
        return decoder->base;
diff --git a/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c b/libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c
new file mode 100644 (file)
index 0000000..e40096a
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2009 Tomas Valenta, 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_dtmf_detector.h"
+#include "apr_thread_mutex.h"
+#include "apt_log.h"
+#include "mpf_named_event.h"
+#include <math.h>
+
+#ifndef M_PI
+#      define M_PI 3.141592653589793238462643
+#endif
+
+/** Max detected DTMF digits buffer length */
+#define MPF_DTMFDET_BUFFER_LEN  32
+
+/** Number of DTMF frequencies */
+#define DTMF_FREQUENCIES         8
+
+/** Window length in samples (at 8kHz) for Goertzel's frequency analysis */
+#define GOERTZEL_SAMPLES_8K    102
+
+/** See RFC4733 */
+#define DTMF_EVENT_ID_MAX       15  /* 0123456789*#ABCD */
+
+/**
+ * Goertzel frequency detector (second-order IIR filter) state:
+ *
+ * s(t) = x(t) + coef * s(t-1) - s(t-2), where s(0)=0; s(1) = 0;
+ * x(t) is the input signal
+ *
+ * Then energy of frequency f in the signal is:
+ * X(f)X'(f) = s(t-2)^2 + s(t-1)^2 - coef*s(t-2)*s(t-1)
+ */
+typedef struct goertzel_state_t {
+       /** coef = cos(2*pi*f_tone/f_sampling) */
+       double coef;
+       /** s(t-2) or resulting energy @see goertzel_state_t */
+       double s1;
+       /** s(t-1) @see goertzel_state_t */
+       double s2;
+} goertzel_state_t;
+
+/** DTMF frequencies */
+static const double dtmf_freqs[DTMF_FREQUENCIES] = {
+        697,  770,  852,  941,  /* Row frequencies */
+       1209, 1336, 1477, 1633}; /* Col frequencies */
+
+/** [row, col] major frequency to digit mapping */
+static const char freq2digits[DTMF_FREQUENCIES/2][DTMF_FREQUENCIES/2] =
+       { { '1', '2', '3', 'A' },
+         { '4', '5', '6', 'B' },
+         { '7', '8', '9', 'C' },
+         { '*', '0', '#', 'D' } };
+
+/** Media Processing Framework's Dual Tone Multiple Frequncy detector */
+struct mpf_dtmf_detector_t {
+       /** Mutex to guard the buffer */
+       struct apr_thread_mutex_t     *mutex;
+       /** Recognizer band */
+       enum mpf_dtmf_detector_band_e  band;
+       /** Detected digits buffer */
+       char                           buf[MPF_DTMFDET_BUFFER_LEN+1];
+       /** Number of digits in the buffer */
+       apr_size_t                     digits;
+       /** Number of lost digits due to full buffer */
+       apr_size_t                     lost_digits;
+       /** Frequency analyzators */
+       struct goertzel_state_t        energies[DTMF_FREQUENCIES];
+       /** Total energy of signal */
+       double                         totenergy;
+       /** Number of samples in a window */
+       apr_size_t                     wsamples;
+       /** Number of samples processed */
+       apr_size_t                     nsamples;
+       /** Previously detected and last reported digits */
+       char                           last1, last2, curr;
+};
+
+
+MPF_DECLARE(struct mpf_dtmf_detector_t *) mpf_dtmf_detector_create_ex(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               enum mpf_dtmf_detector_band_e band,
+                                                               struct apr_pool_t *pool)
+{
+       apr_status_t status;
+       struct mpf_dtmf_detector_t *det;
+       int flg_band = band;
+
+       if (!stream->tx_descriptor) flg_band &= ~MPF_DTMF_DETECTOR_INBAND;
+/*
+       Event descriptor is not important actually
+       if (!stream->tx_event_descriptor) flg_band &= ~MPF_DTMF_DETECTOR_OUTBAND;
+*/
+       if (!flg_band) return NULL;
+
+       det = apr_palloc(pool, sizeof(mpf_dtmf_detector_t));
+       if (!det) return NULL;
+       status = apr_thread_mutex_create(&det->mutex, APR_THREAD_MUTEX_DEFAULT, pool);
+       if (status != APR_SUCCESS) return NULL;
+
+       det->band = (enum mpf_dtmf_detector_band_e) flg_band;
+       det->buf[0] = 0;
+       det->digits = 0;
+       det->lost_digits = 0;
+
+       if (det->band & MPF_DTMF_DETECTOR_INBAND) {
+               apr_size_t i;
+               for (i = 0; i < DTMF_FREQUENCIES; i++) {
+                       det->energies[i].coef = 2 * cos(2 * M_PI * dtmf_freqs[i] /
+                               stream->tx_descriptor->sampling_rate);
+                       det->energies[i].s1 = 0;
+                       det->energies[i].s2 = 0;
+               }
+               det->nsamples = 0;
+               det->wsamples = GOERTZEL_SAMPLES_8K * (stream->tx_descriptor->sampling_rate / 8000);
+               det->last1 = det->last2 = det->curr = 0;
+               det->totenergy = 0;
+       }
+
+       return det;
+}
+
+MPF_DECLARE(char) mpf_dtmf_detector_digit_get(struct mpf_dtmf_detector_t *detector)
+{
+       char digit;
+       apr_thread_mutex_lock(detector->mutex);
+       digit = detector->buf[0];
+       if (digit) {
+               strcpy(detector->buf, detector->buf + 1);
+               detector->digits--;
+       }
+       apr_thread_mutex_unlock(detector->mutex);
+       return digit;
+}
+
+MPF_DECLARE(apr_size_t) mpf_dtmf_detector_digits_lost(const struct mpf_dtmf_detector_t *detector)
+{
+       return detector->lost_digits;
+}
+
+MPF_DECLARE(void) mpf_dtmf_detector_reset(struct mpf_dtmf_detector_t *detector)
+{
+       apr_thread_mutex_lock(detector->mutex);
+       detector->buf[0] = 0;
+       detector->lost_digits = 0;
+       detector->digits = 0;
+       detector->curr = detector->last1 = detector->last2 = 0;
+       detector->nsamples = 0;
+       detector->totenergy = 0;
+       apr_thread_mutex_unlock(detector->mutex);
+}
+
+static APR_INLINE void mpf_dtmf_detector_add_digit(
+                                                               struct mpf_dtmf_detector_t *detector,
+                                                               char digit)
+{
+       if (!digit) return;
+       apr_thread_mutex_lock(detector->mutex);
+       if (detector->digits < MPF_DTMFDET_BUFFER_LEN) {
+               detector->buf[detector->digits++] = digit;
+               detector->buf[detector->digits] = 0;
+       } else
+               detector->lost_digits++;
+       apr_thread_mutex_unlock(detector->mutex);
+}
+
+static APR_INLINE void goertzel_sample(
+                                                               struct mpf_dtmf_detector_t *detector,
+                                                               apr_int16_t sample)
+{
+       apr_size_t i;
+       double s;
+       for (i = 0; i < DTMF_FREQUENCIES; i++) {
+               s = detector->energies[i].s1;
+               detector->energies[i].s1 = detector->energies[i].s2;
+               detector->energies[i].s2 = sample +
+                       detector->energies[i].coef * detector->energies[i].s1 - s;
+       }
+       detector->totenergy += sample * sample;
+}
+
+static void goertzel_energies_digit(struct mpf_dtmf_detector_t *detector)
+{
+       apr_size_t i, rmax = 0, cmax = 0;
+       double reng = 0, ceng = 0;
+       char digit = 0;
+
+       /* Calculate energies and maxims */
+       for (i = 0; i < DTMF_FREQUENCIES; i++) {
+               double eng = detector->energies[i].s1 * detector->energies[i].s1 +
+                       detector->energies[i].s2 * detector->energies[i].s2 -
+                       detector->energies[i].coef * detector->energies[i].s1 * detector->energies[i].s2;
+               if (i < DTMF_FREQUENCIES/2) {
+                       if (eng > reng) {
+                               rmax = i;
+                               reng = eng;
+                       }
+               } else {
+                       if (eng > ceng) {
+                               cmax = i;
+                               ceng = eng;
+                       }
+               }
+       }
+
+       if ((reng < 8.0e8 * detector->wsamples / GOERTZEL_SAMPLES_8K) ||
+               (ceng < 8.0e8 * detector->wsamples / GOERTZEL_SAMPLES_8K))
+       {
+               /* energy not high enough */
+       } else if ((ceng > reng) && (reng < ceng * 0.398)) {  /* twist > 4dB, error */
+               /* Twist check
+                * CEPT => twist < 6dB
+                * AT&T => forward twist < 4dB and reverse twist < 8dB
+                *  -ndB < 10 log10( v1 / v2 ), where v1 < v2
+                *  -4dB < 10 log10( v1 / v2 )
+                *  -0.4  < log10( v1 / v2 )
+                *  0.398 < v1 / v2
+                *  0.398 * v2 < v1
+                */
+       } else if ((ceng < reng) && (ceng < reng * 0.158)) {  /* twist > 8db, error */
+               /* Reverse twist check failed */
+       } else if (0.025 * detector->totenergy > (reng + ceng)) {  /* 16db */
+               /* Signal energy to total energy ratio test failed */
+       } else {
+               digit = freq2digits[rmax][cmax - DTMF_FREQUENCIES/2];
+       }
+
+       /* Three successive detections will trigger the detection */
+       if (digit != detector->curr) {
+               if (digit && ((detector->last1 == digit) && (detector->last2 == digit))) {
+                       detector->curr = digit;
+                       mpf_dtmf_detector_add_digit(detector, digit);
+               } else if ((detector->last1 != detector->curr) && (detector->last2 != detector->curr)) {
+                       detector->curr = 0;
+               }
+       }
+       detector->last1 = detector->last2;
+       detector->last2 = digit;
+
+       /* Reset Goertzel's detectors */
+       for (i = 0; i < DTMF_FREQUENCIES; i++) {
+               detector->energies[i].s1 = 0;
+               detector->energies[i].s2 = 0;
+       }
+       detector->totenergy = 0;
+}
+
+MPF_DECLARE(void) mpf_dtmf_detector_get_frame(
+                                                               struct mpf_dtmf_detector_t *detector,
+                                                               const struct mpf_frame_t *frame)
+{
+       if ((detector->band & MPF_DTMF_DETECTOR_OUTBAND) &&
+               (frame->type & MEDIA_FRAME_TYPE_EVENT) &&
+               (frame->event_frame.event_id <= DTMF_EVENT_ID_MAX) &&
+               (frame->marker == MPF_MARKER_START_OF_EVENT))
+       {
+               if (detector->band & MPF_DTMF_DETECTOR_INBAND) {
+                       detector->band &= ~MPF_DTMF_DETECTOR_INBAND;
+                       apt_log(APT_LOG_MARK, APT_PRIO_INFO, "Out-of-band digit arrived, turning "
+                               "in-band DTMF detector off");
+               }
+               mpf_dtmf_detector_add_digit(detector, mpf_event_id_to_dtmf_char(
+                       frame->event_frame.event_id));
+               return;
+       }
+
+       if ((detector->band & MPF_DTMF_DETECTOR_INBAND) && (frame->type & MEDIA_FRAME_TYPE_AUDIO)) {
+               apr_int16_t *samples = frame->codec_frame.buffer;
+               apr_size_t i;
+
+               for (i = 0; i < frame->codec_frame.size / 2; i++) {
+                       goertzel_sample(detector, samples[i]);
+                       if (++detector->nsamples >= detector->wsamples) {
+                               goertzel_energies_digit(detector);
+                               detector->nsamples = 0;
+                       }
+               }
+       }
+}
+
+MPF_DECLARE(void) mpf_dtmf_detector_destroy(struct mpf_dtmf_detector_t *detector)
+{
+       apr_thread_mutex_destroy(detector->mutex);
+       detector->mutex = NULL;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c b/libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c
new file mode 100644 (file)
index 0000000..66d870f
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2009 Tomas Valenta, 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_dtmf_generator.h"
+#include "apr.h"
+#include "apr_thread_mutex.h"
+#include "apt_log.h"
+#include "mpf_named_event.h"
+#include <math.h>
+
+#ifndef M_PI
+#      define M_PI 3.141592653589793238462643
+#endif
+
+/** Max DTMF digits waiting to be sent */
+#define MPF_DTMFGEN_QUEUE_LEN  32
+
+/** See RFC4733 */
+#define DTMF_EVENT_ID_MAX      15  /* 0123456789*#ABCD */
+
+/** See RFC4733 */
+#define DTMF_EVENT_VOLUME      10
+
+/** Amplitude of single sine wave from tone generator */
+#define DTMF_SINE_AMPLITUDE 12288
+
+/** State of the DTMF generator */
+typedef enum mpf_dtmf_generator_state_e {
+       /** Ready to generate next digit in queue */
+       DTMF_GEN_STATE_IDLE,
+       /** Generating tone */
+       DTMF_GEN_STATE_TONE,
+       /** Retransmitting final RTP packet */
+       DTMF_GEN_STATE_ENDING,
+       /** Generating silence between tones */
+       DTMF_GEN_STATE_SILENCE
+} mpf_dtmf_generator_state_e;
+
+/**
+ * Sine wave generator (second-order IIR filter) state:
+ *
+ * s(t) = Amp*sin(2*pi*f_tone/f_sampling*t)
+ *
+ * s(t) = coef * s(t-1) - s(t-2); s(0)=0; s(1)=Amp*sin(2*pi*f_tone/f_sampling)
+ */
+typedef struct sine_state_t {
+       /** coef = cos(2*pi*f_tone/f_sampling) */
+       double coef;
+       /** s(t-2) @see sine_state_t */
+       double s1;
+       /** s(t-1) @see sine_state_t */
+       double s2;
+} sine_state_t;
+
+/** Mapping event_it to frequency pair */
+static const double dtmf_freq[DTMF_EVENT_ID_MAX+1][2] = {
+       {941, 1336},  /* 0 */
+       {697, 1209},  /* 1 */
+       {697, 1336},  /* 2 */
+       {697, 1477},  /* 3 */
+       {770, 1209},  /* 4 */
+       {770, 1336},  /* 5 */
+       {770, 1477},  /* 6 */
+       {852, 1209},  /* 7 */
+       {852, 1336},  /* 8 */
+       {852, 1477},  /* 9 */
+       {941, 1209},  /* * */
+       {941, 1477},  /* # */
+       {697, 1633},  /* A */
+       {770, 1633},  /* B */
+       {852, 1633},  /* C */
+       {941, 1633}   /* D */
+};
+
+/** Media Processing Framework's Dual Tone Multiple Frequncy generator */
+struct mpf_dtmf_generator_t {
+       /** Generator state */
+       enum mpf_dtmf_generator_state_e  state;
+       /** In-band or out-of-band */
+       enum mpf_dtmf_generator_band_e   band;
+       /** Mutex to guard the queue */
+       struct apr_thread_mutex_t       *mutex;
+       /** Queue of digits to generate */
+       char                             queue[MPF_DTMFGEN_QUEUE_LEN+1];
+       /** DTMF event_id according to RFC4733 */
+       apr_byte_t                       event_id;
+       /** Duration in RTP units: (sample_rate / 1000) * milliseconds */
+       apr_uint32_t                     tone_duration;
+       /** Duration of inter-digit silence @see tone_duration */
+       apr_uint32_t                     silence_duration;
+       /** Multipurpose counter; mostly in RTP time units */
+       apr_uint32_t                     counter;
+       /** Frame duration in RTP units */
+       apr_uint32_t                     frame_duration;
+       /** RTP named event duration (0..0xFFFF) */
+       apr_uint32_t                     event_duration;
+       /** Set MPF_MARKER_NEW_SEGMENT in the next event frame */
+       apt_bool_t                       new_segment;
+       /** Lower frequency generator */
+       struct sine_state_t              sine1;
+       /** Higher frequency generator */
+       struct sine_state_t              sine2;
+       /** Sampling rate of audio in Hz; used in tone generator */
+       apr_size_t                       sample_rate_audio;
+       /** Sampling rate of telephone-events in Hz; used for timing */
+       apr_size_t                       sample_rate_events;
+       /** How often to issue event packet */
+       apr_size_t                       events_ptime;
+       /** Milliseconds elapsed since last event packet */
+       apr_size_t                       since_last_event;
+};
+
+
+MPF_DECLARE(struct mpf_dtmf_generator_t *) mpf_dtmf_generator_create_ex(
+                                                               const struct mpf_audio_stream_t *stream,
+                                                               enum mpf_dtmf_generator_band_e band,
+                                                               apr_size_t tone_ms,
+                                                               apr_size_t silence_ms,
+                                                               struct apr_pool_t *pool)
+{
+       struct mpf_dtmf_generator_t *gen;
+       apr_status_t status;
+       int flg_band = band;
+
+       if (!stream->rx_descriptor) flg_band &= ~MPF_DTMF_GENERATOR_INBAND;
+       if (!stream->rx_event_descriptor) flg_band &= ~MPF_DTMF_GENERATOR_OUTBAND;
+       if (!flg_band) return NULL;
+
+       gen = apr_palloc(pool, sizeof(struct mpf_dtmf_generator_t));
+       if (!gen) return NULL;
+       status = apr_thread_mutex_create(&gen->mutex, APR_THREAD_MUTEX_DEFAULT, pool);
+       if (status != APR_SUCCESS) return NULL;
+       gen->band = (enum mpf_dtmf_generator_band_e) flg_band;
+       gen->queue[0] = 0;
+       gen->state = DTMF_GEN_STATE_IDLE;
+       if (stream->rx_descriptor)
+               gen->sample_rate_audio = stream->rx_descriptor->sampling_rate;
+       gen->sample_rate_events = stream->rx_event_descriptor ?
+               stream->rx_event_descriptor->sampling_rate : gen->sample_rate_audio;
+       gen->frame_duration = gen->sample_rate_events / 1000 * CODEC_FRAME_TIME_BASE;
+       gen->tone_duration = gen->sample_rate_events / 1000 * tone_ms;
+       gen->silence_duration = gen->sample_rate_events / 1000 * silence_ms;
+       gen->events_ptime = CODEC_FRAME_TIME_BASE;  /* Should be got from event_descriptor */
+       return gen;
+}
+
+
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_enqueue(
+                                                               struct mpf_dtmf_generator_t *generator,
+                                                               const char *digits)
+{
+       apr_size_t qlen, dlen;
+       apt_bool_t ret;
+
+       dlen = strlen(digits);
+       apr_thread_mutex_lock(generator->mutex);
+       qlen = strlen(generator->queue);
+       if (qlen + dlen > MPF_DTMFGEN_QUEUE_LEN) {
+               ret = FALSE;
+               apt_log(APT_LOG_MARK, APT_PRIO_WARNING, "DTMF queue too short (%d), "
+                       "cannot add %d digit%s, already has %d", MPF_DTMFGEN_QUEUE_LEN,
+                       dlen, dlen > 1 ? "s" : "", qlen);
+       } else {
+               strcpy(generator->queue + qlen, digits);
+               ret = TRUE;
+       }
+       apr_thread_mutex_unlock(generator->mutex);
+       return ret;
+}
+
+
+MPF_DECLARE(void) mpf_dtmf_generator_reset(struct mpf_dtmf_generator_t *generator)
+{
+       apr_thread_mutex_lock(generator->mutex);
+       generator->state = DTMF_GEN_STATE_IDLE;
+       generator->queue[0] = 0;
+       apr_thread_mutex_unlock(generator->mutex);
+}
+
+
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_sending(const struct mpf_dtmf_generator_t *generator)
+{
+       return *generator->queue || ((generator->state != DTMF_GEN_STATE_IDLE) &&
+               (generator->state != DTMF_GEN_STATE_SILENCE));
+}
+
+
+MPF_DECLARE(apt_bool_t) mpf_dtmf_generator_put_frame(
+                                                               struct mpf_dtmf_generator_t *generator,
+                                                               struct mpf_frame_t *frame)
+{
+       apr_thread_mutex_lock(generator->mutex);
+       if ((generator->state == DTMF_GEN_STATE_IDLE) && *generator->queue) {
+               /* Get next valid digit from queue */
+               do {
+                       generator->event_id = (apr_byte_t) mpf_dtmf_char_to_event_id(*generator->queue);
+                       strcpy(generator->queue, generator->queue + 1);
+               } while (*generator->queue && (generator->event_id > DTMF_EVENT_ID_MAX));
+               /* Reset state */
+               if (generator->event_id <= DTMF_EVENT_ID_MAX) {
+                       generator->state = DTMF_GEN_STATE_TONE;
+                       generator->counter = 0;
+                       generator->event_duration = 0;
+                       generator->since_last_event = generator->events_ptime;
+                       generator->new_segment = FALSE;
+                       /* Initialize tone generator */
+                       if (generator->band & MPF_DTMF_GENERATOR_INBAND) {
+                               double omega;
+
+                               omega = 2 * M_PI * dtmf_freq[generator->event_id][0] / generator->sample_rate_audio;
+                               generator->sine1.s1 = 0;
+                               generator->sine1.s2 = DTMF_SINE_AMPLITUDE * sin(omega);
+                               generator->sine1.coef = 2 * cos(omega);
+
+                               omega = 2 * M_PI * dtmf_freq[generator->event_id][1] / generator->sample_rate_audio;
+                               generator->sine2.s1 = 0;
+                               generator->sine2.s2 = DTMF_SINE_AMPLITUDE * sin(omega);
+                               generator->sine2.coef = 2 * cos(omega);
+                       }
+               }
+       }
+       apr_thread_mutex_unlock(generator->mutex);
+       if (generator->state == DTMF_GEN_STATE_IDLE) return FALSE;
+
+       if (generator->state == DTMF_GEN_STATE_TONE) {
+               generator->counter += generator->frame_duration;
+               generator->event_duration += generator->frame_duration;
+               if (generator->band & MPF_DTMF_GENERATOR_INBAND) {
+                       apr_size_t i;
+                       apr_int16_t *samples = (apr_int16_t *) frame->codec_frame.buffer;
+                       double s;
+
+                       frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       /* Tone generator */
+                       for (i = 0; i < frame->codec_frame.size / 2; i++) {
+                               s = generator->sine1.s1;
+                               generator->sine1.s1 = generator->sine1.s2;
+                               generator->sine1.s2 = generator->sine1.coef * generator->sine1.s1 - s;
+                               samples[i] = (apr_int16_t) (s + generator->sine2.s1);
+                               s = generator->sine2.s1;
+                               generator->sine2.s1 = generator->sine2.s2;
+                               generator->sine2.s2 = generator->sine2.coef * generator->sine2.s1 - s;
+                       }
+               }
+               if (generator->band & MPF_DTMF_GENERATOR_OUTBAND) {
+                       generator->since_last_event += CODEC_FRAME_TIME_BASE;
+                       if (generator->since_last_event >= generator->events_ptime)
+                               generator->since_last_event = 0;
+                       else
+                               return TRUE;
+                       frame->type |= MEDIA_FRAME_TYPE_EVENT;
+                       frame->event_frame.reserved = 0;
+                       frame->event_frame.event_id = generator->event_id;
+                       frame->event_frame.volume = DTMF_EVENT_VOLUME;
+                       if (generator->counter >= generator->tone_duration) {
+                               generator->state = DTMF_GEN_STATE_ENDING;
+                               generator->counter = 0;
+                               frame->event_frame.edge = 1;
+                               frame->marker = MPF_MARKER_END_OF_EVENT;
+                               if (generator->event_duration > 0xFFFF) {
+                                       /* Shorten the tone a bit instead of lenghtening */
+                                       generator->new_segment = TRUE;
+                                       frame->event_frame.duration = 0xFFFF;
+                                       generator->event_duration = 0;
+                               } else
+                                       frame->event_frame.duration = generator->event_duration;
+                       } else {
+                               frame->event_frame.edge = 0;
+                               if (generator->counter == generator->frame_duration)  /* First chunk of event */
+                                       frame->marker = MPF_MARKER_START_OF_EVENT;
+                               else if (generator->new_segment) {
+                                       frame->marker = MPF_MARKER_NEW_SEGMENT;
+                                       generator->new_segment = FALSE;
+                               } else
+                                       frame->marker = MPF_MARKER_NONE;
+                               if (generator->event_duration > 0xFFFF) {
+                                       frame->event_frame.duration = 0xFFFF;
+                                       generator->event_duration = 0;
+                                       generator->new_segment = TRUE;
+                               } else
+                                       frame->event_frame.duration = generator->event_duration;
+                       }
+                       return TRUE;
+               }  /* MPF_DTMF_GENERATOR_OUTBAND */
+               if (generator->counter >= generator->tone_duration) {
+                       generator->state = DTMF_GEN_STATE_SILENCE;
+                       generator->counter = 0;
+               }
+               return TRUE;
+       }
+       else if (generator->state == DTMF_GEN_STATE_ENDING) {
+               generator->since_last_event += CODEC_FRAME_TIME_BASE;
+               if (generator->since_last_event >= generator->events_ptime)
+                       generator->since_last_event = 0;
+               else
+                       return TRUE;
+               generator->counter++;
+               frame->type |= MEDIA_FRAME_TYPE_EVENT;
+               frame->marker = MPF_MARKER_END_OF_EVENT;
+               frame->event_frame.event_id = generator->event_id;
+               frame->event_frame.volume = DTMF_EVENT_VOLUME;
+               frame->event_frame.reserved = 0;
+               frame->event_frame.edge = 1;
+               if (generator->new_segment)
+                       /* Tone was shortened a little bit */
+                       frame->event_frame.duration = 0xFFFF;
+               else
+                       frame->event_frame.duration = generator->event_duration;
+               if (generator->counter >= 2) {
+                       generator->state = DTMF_GEN_STATE_SILENCE;
+                       generator->counter *= generator->frame_duration;
+               }
+               if (generator->band & MPF_DTMF_GENERATOR_INBAND) {
+                       frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       memset(frame->codec_frame.buffer, 0, frame->codec_frame.size);
+               }
+               return TRUE;
+       }
+       else if (generator->state == DTMF_GEN_STATE_SILENCE) {
+               generator->counter += generator->frame_duration;
+               if (generator->counter >= generator->silence_duration)
+                       generator->state = DTMF_GEN_STATE_IDLE;
+       }
+
+       return FALSE;
+}
+
+
+MPF_DECLARE(void) mpf_dtmf_generator_destroy(struct mpf_dtmf_generator_t *generator)
+{
+       mpf_dtmf_generator_reset(generator);
+       apr_thread_mutex_destroy(generator->mutex);
+       generator->mutex = NULL;
+}
index 0c85ac9dc748117f9e4402079303487896db207d..797600192fd494728c5453f7ba92c3414a847e5c 100644 (file)
@@ -22,6 +22,7 @@ typedef struct mpf_encoder_t mpf_encoder_t;
 struct mpf_encoder_t {
        mpf_audio_stream_t *base;
        mpf_audio_stream_t *sink;
+       mpf_codec_t        *codec;
        mpf_frame_t         frame_out;
 };
 
@@ -32,10 +33,10 @@ static apt_bool_t mpf_encoder_destroy(mpf_audio_stream_t *stream)
        return mpf_audio_stream_destroy(encoder->sink);
 }
 
-static apt_bool_t mpf_encoder_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_encoder_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        mpf_encoder_t *encoder = stream->obj;
-       return mpf_audio_stream_tx_open(encoder->sink);
+       return mpf_audio_stream_tx_open(encoder->sink,encoder->codec);
 }
 
 static apt_bool_t mpf_encoder_close(mpf_audio_stream_t *stream)
@@ -49,15 +50,35 @@ static apt_bool_t mpf_encoder_process(mpf_audio_stream_t *stream, const mpf_fram
        mpf_encoder_t *encoder = stream->obj;
 
        encoder->frame_out.type = frame->type;
+       encoder->frame_out.marker = frame->marker;
        if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
                encoder->frame_out.event_frame = frame->event_frame;
        }
        if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
-               mpf_codec_encode(encoder->sink->tx_codec,&frame->codec_frame,&encoder->frame_out.codec_frame);
+               mpf_codec_encode(encoder->codec,&frame->codec_frame,&encoder->frame_out.codec_frame);
        }
        return mpf_audio_stream_frame_write(encoder->sink,&encoder->frame_out);
 }
 
+static void mpf_encoder_trace(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output)
+{
+       apr_size_t offset;
+       mpf_codec_descriptor_t *descriptor;
+       mpf_encoder_t *encoder = stream->obj;
+
+       descriptor = encoder->base->tx_descriptor;
+       if(descriptor) {
+               offset = output->pos - output->text.buf;
+               output->pos += apr_snprintf(output->pos, output->text.length - offset,
+                       "[%s/%d/%d]->Encoder->",
+                       descriptor->name.buf,
+                       descriptor->sampling_rate,
+                       descriptor->channel_count);
+       }
+
+       mpf_audio_stream_trace(encoder->sink,direction,output);
+}
+
 
 static const mpf_audio_stream_vtable_t vtable = {
        mpf_encoder_destroy,
@@ -66,24 +87,34 @@ static const mpf_audio_stream_vtable_t vtable = {
        NULL,
        mpf_encoder_open,
        mpf_encoder_close,
-       mpf_encoder_process
+       mpf_encoder_process,
+       mpf_encoder_trace
 };
 
-MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, apr_pool_t *pool)
+MPF_DECLARE(mpf_audio_stream_t*) mpf_encoder_create(mpf_audio_stream_t *sink, mpf_codec_t *codec, apr_pool_t *pool)
 {
        apr_size_t frame_size;
-       mpf_codec_t *codec;
        mpf_encoder_t *encoder;
-       if(!sink || !sink->tx_codec) {
+       mpf_stream_capabilities_t *capabilities;
+       if(!sink || !codec) {
                return NULL;
        }
        encoder = apr_palloc(pool,sizeof(mpf_encoder_t));
-       encoder->base = mpf_audio_stream_create(encoder,&vtable,STREAM_MODE_SEND,pool);
+       capabilities = mpf_stream_capabilities_create(STREAM_DIRECTION_SEND,pool);
+       encoder->base = mpf_audio_stream_create(encoder,&vtable,capabilities,pool);
+       if(!encoder->base) {
+               return NULL;
+       }
+       encoder->base->tx_descriptor = mpf_codec_lpcm_descriptor_create(
+               sink->tx_descriptor->sampling_rate,
+               sink->tx_descriptor->channel_count,
+               pool);
+       encoder->base->tx_event_descriptor = sink->tx_event_descriptor;
+       
        encoder->sink = sink;
+       encoder->codec = codec;
 
-       codec = sink->tx_codec;
-       frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
-       encoder->base->tx_codec = codec;
+       frame_size = mpf_codec_frame_size_calculate(sink->tx_descriptor,codec->attribs);
        encoder->frame_out.codec_frame.size = frame_size;
        encoder->frame_out.codec_frame.buffer = apr_palloc(pool,frame_size);
        return encoder->base;
index 2d34b67cfea2bdb3796779ea0858e717e247789c..ad78904d5baedc07b025f3177af7c35018b8d980 100644 (file)
  */
 
 #include "mpf_engine.h"
-#include "mpf_user.h"
 #include "mpf_context.h"
 #include "mpf_termination.h"
 #include "mpf_stream.h"
-#include "mpf_timer.h"
+#include "mpf_scheduler.h"
 #include "mpf_codec_descriptor.h"
 #include "mpf_codec_manager.h"
+#include "mpf_timer_manager.h"
 #include "apt_obj_list.h"
 #include "apt_cyclic_queue.h"
 #include "apt_log.h"
@@ -34,36 +34,35 @@ struct mpf_engine_t {
        apt_task_msg_type_e        task_msg_type;
        apr_thread_mutex_t        *request_queue_guard;
        apt_cyclic_queue_t        *request_queue;
-       apt_obj_list_t            *contexts;
-       mpf_timer_t               *timer;
+       mpf_context_factory_t     *context_factory;
+       mpf_scheduler_t           *scheduler;
+       mpf_timer_manager_t       *timer_manager;
        const mpf_codec_manager_t *codec_manager;
 };
 
-static void mpf_engine_main(mpf_timer_t *timer, void *data);
+static void mpf_engine_main(mpf_scheduler_t *scheduler, void *data);
 static apt_bool_t mpf_engine_destroy(apt_task_t *task);
 static apt_bool_t mpf_engine_start(apt_task_t *task);
 static apt_bool_t mpf_engine_terminate(apt_task_t *task);
 static apt_bool_t mpf_engine_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
 static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg);
 
-static apt_bool_t mpf_engine_contexts_destroy(mpf_engine_t *engine);
 
-mpf_codec_t* mpf_codec_lpcm_create(apr_pool_t *pool);
 mpf_codec_t* mpf_codec_l16_create(apr_pool_t *pool);
 mpf_codec_t* mpf_codec_g711u_create(apr_pool_t *pool);
 mpf_codec_t* mpf_codec_g711a_create(apr_pool_t *pool);
 
-MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool)
+MPF_DECLARE(mpf_engine_t*) mpf_engine_create(unsigned long rate, apr_pool_t *pool)
 {
        apt_task_vtable_t *vtable;
        apt_task_msg_pool_t *msg_pool;
        mpf_engine_t *engine = apr_palloc(pool,sizeof(mpf_engine_t));
        engine->pool = pool;
        engine->request_queue = NULL;
-       engine->contexts = NULL;
+       engine->context_factory = NULL;
        engine->codec_manager = NULL;
 
-       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mpf_message_t),pool);
+       msg_pool = apt_task_msg_pool_create_dynamic(sizeof(mpf_message_container_t),pool);
 
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create "MPF_TASK_NAME);
        engine->task = apt_task_create(engine,msg_pool,pool);
@@ -84,14 +83,36 @@ MPF_DECLARE(mpf_engine_t*) mpf_engine_create(apr_pool_t *pool)
 
        engine->task_msg_type = TASK_MSG_USER;
 
+       engine->context_factory = mpf_context_factory_create(engine->pool);
        engine->request_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
        apr_thread_mutex_create(&engine->request_queue_guard,APR_THREAD_MUTEX_UNNESTED,engine->pool);
 
-       engine->contexts = apt_list_create(engine->pool);
+       engine->scheduler = mpf_scheduler_create(rate,engine->pool);
+       mpf_scheduler_media_clock_set(engine->scheduler,CODEC_FRAME_TIME_BASE,mpf_engine_main,engine);
 
+       engine->timer_manager = mpf_timer_manager_create(engine->scheduler,engine->pool);
        return engine;
 }
 
+MPF_DECLARE(mpf_context_t*) mpf_engine_context_create(
+                                                               mpf_engine_t *engine, 
+                                                               void *obj, 
+                                                               apr_size_t max_termination_count, 
+                                                               apr_pool_t *pool)
+{
+       return mpf_context_create(engine->context_factory,obj,max_termination_count,pool);
+}
+
+MPF_DECLARE(apt_bool_t) mpf_engine_context_destroy(mpf_context_t *context)
+{
+       return mpf_context_destroy(context);
+}
+
+MPF_DECLARE(void*) mpf_engine_context_object_get(mpf_context_t *context)
+{
+       return mpf_context_object_get(context);
+}
+
 MPF_DECLARE(apt_task_t*) mpf_task_get(mpf_engine_t *engine)
 {
        return engine->task;
@@ -102,12 +123,109 @@ MPF_DECLARE(void) mpf_engine_task_msg_type_set(mpf_engine_t *engine, apt_task_ms
        engine->task_msg_type = type;
 }
 
+static mpf_message_t* mpf_engine_message_get(mpf_engine_t *engine, mpf_task_msg_t **task_msg)
+{
+       mpf_message_container_t *container;
+       mpf_message_t *mpf_message;
+       if(*task_msg) {
+               container = (mpf_message_container_t*) (*task_msg)->data;
+               if(container->count >= MAX_MPF_MESSAGE_COUNT) {
+                       /* container has been already filled,
+                       implicitly send the requests and get new task message */
+                       mpf_engine_message_send(engine,task_msg);
+                       return mpf_engine_message_get(engine,task_msg);
+               }
+       }
+       else {
+               *task_msg = apt_task_msg_get(engine->task);
+               container = (mpf_message_container_t*) (*task_msg)->data;
+               container->count = 0;
+       }
+
+       mpf_message = &container->messages[container->count];
+       container->count++;
+       return mpf_message;
+}
+
+
+MPF_DECLARE(apt_bool_t) mpf_engine_termination_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_termination_t *termination,
+                                                       void *descriptor,
+                                                       mpf_task_msg_t **task_msg)
+{
+       mpf_message_t *mpf_message = mpf_engine_message_get(engine,task_msg);
+       if(!mpf_message) {
+               return FALSE;
+       }
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = command_id;
+       mpf_message->context = context;
+       mpf_message->termination = termination;
+       mpf_message->assoc_termination = NULL;
+       mpf_message->descriptor = descriptor;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_engine_assoc_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_termination_t *termination,
+                                                       mpf_termination_t *assoc_termination,
+                                                       mpf_task_msg_t **task_msg)
+{
+       mpf_message_t *mpf_message = mpf_engine_message_get(engine,task_msg);
+       if(!mpf_message) {
+               return FALSE;
+       }
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = command_id;
+       mpf_message->context = context;
+       mpf_message->termination = termination;
+       mpf_message->assoc_termination = assoc_termination;
+       mpf_message->descriptor = NULL;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_engine_topology_message_add(
+                                                       mpf_engine_t *engine,
+                                                       mpf_command_type_e command_id,
+                                                       mpf_context_t *context,
+                                                       mpf_task_msg_t **task_msg)
+{
+       mpf_message_t *mpf_message = mpf_engine_message_get(engine,task_msg);
+       if(!mpf_message) {
+               return FALSE;
+       }
+       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
+       mpf_message->command_id = command_id;
+       mpf_message->context = context;
+       mpf_message->termination = NULL;
+       mpf_message->assoc_termination = NULL;
+       mpf_message->descriptor = NULL;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_engine_message_send(mpf_engine_t *engine, mpf_task_msg_t **task_msg)
+{
+       apt_bool_t status = FALSE;
+       if(*task_msg) {
+               status = apt_task_msg_signal(engine->task,*task_msg);
+               *task_msg = NULL;
+       }
+       return status;
+}
+
 static apt_bool_t mpf_engine_destroy(apt_task_t *task)
 {
        mpf_engine_t *engine = apt_task_object_get(task);
 
-       apt_list_destroy(engine->contexts);
-
+       mpf_timer_manager_destroy(engine->timer_manager);
+       mpf_scheduler_destroy(engine->scheduler);
+       mpf_context_factory_destroy(engine->context_factory);
        apt_cyclic_queue_destroy(engine->request_queue);
        apr_thread_mutex_destroy(engine->request_queue_guard);
        return TRUE;
@@ -117,7 +235,7 @@ static apt_bool_t mpf_engine_start(apt_task_t *task)
 {
        mpf_engine_t *engine = apt_task_object_get(task);
 
-       engine->timer = mpf_timer_start(CODEC_FRAME_TIME_BASE,mpf_engine_main,engine,engine->pool);
+       mpf_scheduler_start(engine->scheduler);
        apt_task_child_start(task);
        return TRUE;
 }
@@ -126,28 +244,16 @@ static apt_bool_t mpf_engine_terminate(apt_task_t *task)
 {
        mpf_engine_t *engine = apt_task_object_get(task);
 
-       mpf_timer_stop(engine->timer);
-       mpf_engine_contexts_destroy(engine);
+       mpf_scheduler_stop(engine->scheduler);
        apt_task_child_terminate(task);
        return TRUE;
 }
 
-static apt_bool_t mpf_engine_contexts_destroy(mpf_engine_t *engine)
-{
-       mpf_context_t *context;
-       context = apt_list_pop_front(engine->contexts);
-       while(context) {
-               mpf_context_destroy(context);
-               
-               context = apt_list_pop_front(engine->contexts);
-       }
-       return TRUE;
-}
-
 static apt_bool_t mpf_engine_event_raise(mpf_termination_t *termination, int event_id, void *descriptor)
 {
        apt_task_msg_t *task_msg;
-       mpf_message_t *event_msg;
+       mpf_message_container_t *event_msg;
+       mpf_message_t *mpf_message;
        mpf_engine_t *engine;
        engine = termination->event_handler_obj;
        if(!engine) {
@@ -156,13 +262,16 @@ static apt_bool_t mpf_engine_event_raise(mpf_termination_t *termination, int eve
 
        task_msg = apt_task_msg_get(engine->task);
        task_msg->type = engine->task_msg_type;
-       event_msg = (mpf_message_t*) task_msg->data;
-       event_msg->command_id = event_id;
-       event_msg->message_type = MPF_MESSAGE_TYPE_EVENT;
-       event_msg->status_code = MPF_STATUS_CODE_SUCCESS;
-       event_msg->context = NULL;
-       event_msg->termination = termination;
-       event_msg->descriptor = descriptor;
+       event_msg = (mpf_message_container_t*) task_msg->data;
+       mpf_message = event_msg->messages;
+       event_msg->count = 1;
+
+       mpf_message->command_id = event_id;
+       mpf_message->message_type = MPF_MESSAGE_TYPE_EVENT;
+       mpf_message->status_code = MPF_STATUS_CODE_SUCCESS;
+       mpf_message->context = NULL;
+       mpf_message->termination = termination;
+       mpf_message->descriptor = descriptor;
        
        return apt_task_msg_parent_signal(engine->task,task_msg);
 }
@@ -181,86 +290,103 @@ static apt_bool_t mpf_engine_msg_signal(apt_task_t *task, apt_task_msg_t *msg)
 
 static apt_bool_t mpf_engine_msg_process(apt_task_t *task, apt_task_msg_t *msg)
 {
+       apr_size_t i;
        mpf_engine_t *engine = apt_task_object_get(task);
        apt_task_msg_t *response_msg;
-       mpf_message_t *response;
+       mpf_message_container_t *response;
+       mpf_message_t *mpf_response;
        mpf_context_t *context;
        mpf_termination_t *termination;
-       const mpf_message_t *request = (const mpf_message_t*) msg->data;
+       const mpf_message_t *mpf_request;
+       const mpf_message_container_t *request = (const mpf_message_container_t*) msg->data;
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Message");
-       if(request->message_type != MPF_MESSAGE_TYPE_REQUEST) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid MPF Message Type [%d]",request->message_type);
-               return FALSE;
-       }
 
        response_msg = apt_task_msg_get(engine->task);
        response_msg->type = engine->task_msg_type;
-       response = (mpf_message_t*) response_msg->data;
+       response = (mpf_message_container_t*) response_msg->data;
        *response = *request;
-       response->message_type = MPF_MESSAGE_TYPE_RESPONSE;
-       response->status_code = MPF_STATUS_CODE_SUCCESS;
-       context = request->context;
-       termination = request->termination;
-       switch(request->command_id) {
-               case MPF_COMMAND_ADD:
-               {
-                       termination->event_handler_obj = engine;
-                       termination->event_handler = mpf_engine_event_raise;
-                       termination->codec_manager = engine->codec_manager;
-                       if(request->descriptor) {
-                               mpf_termination_modify(termination,request->descriptor);
+       for(i=0; i<request->count; i++) {
+               mpf_request = &request->messages[i];
+               mpf_response = &response->messages[i];
+
+               if(mpf_request->message_type != MPF_MESSAGE_TYPE_REQUEST) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid MPF Message Type [%d]",mpf_request->message_type);
+                       continue;
+               }
+
+               mpf_response->message_type = MPF_MESSAGE_TYPE_RESPONSE;
+               mpf_response->status_code = MPF_STATUS_CODE_SUCCESS;
+               context = mpf_request->context;
+               termination = mpf_request->termination;
+               switch(mpf_request->command_id) {
+                       case MPF_ADD_TERMINATION:
+                       {
+                               termination->event_handler_obj = engine;
+                               termination->event_handler = mpf_engine_event_raise;
+                               termination->codec_manager = engine->codec_manager;
+                               termination->timer_manager = engine->timer_manager;
+
+                               mpf_termination_add(termination,mpf_request->descriptor);
+                               if(mpf_context_termination_add(context,termination) == FALSE) {
+                                       mpf_termination_subtract(termination);
+                                       mpf_response->status_code = MPF_STATUS_CODE_FAILURE;
+                                       break;
+                               }
+                               break;
                        }
-                       mpf_termination_validate(termination);
-                       if(mpf_context_termination_add(context,termination) == FALSE) {
-                               response->status_code = MPF_STATUS_CODE_FAILURE;
+                       case MPF_MODIFY_TERMINATION:
+                       {
+                               mpf_termination_modify(termination,mpf_request->descriptor);
                                break;
                        }
-                       mpf_context_topology_apply(context,termination);
-                       if(context->termination_count == 1) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Context");
-                               context->elem = apt_list_push_back(engine->contexts,context,context->pool);
+                       case MPF_SUBTRACT_TERMINATION:
+                       {
+                               if(mpf_context_termination_subtract(context,termination) == FALSE) {
+                                       mpf_response->status_code = MPF_STATUS_CODE_FAILURE;
+                                       break;
+                               }
+                               mpf_termination_subtract(termination);
+                               break;
                        }
-                       break;
-               }
-               case MPF_COMMAND_SUBTRACT:
-               {
-                       mpf_context_topology_destroy(context,termination);
-                       if(mpf_context_termination_subtract(context,termination) == FALSE) {
-                               response->status_code = MPF_STATUS_CODE_FAILURE;
+                       case MPF_ADD_ASSOCIATION:
+                       {
+                               mpf_context_association_add(context,termination,mpf_request->assoc_termination);
                                break;
                        }
-                       if(context->termination_count == 0) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Context");
-                               apt_list_elem_remove(engine->contexts,context->elem);
-                               context->elem = NULL;
+                       case MPF_REMOVE_ASSOCIATION:
+                       {
+                               mpf_context_association_remove(context,termination,mpf_request->assoc_termination);
+                               break;
                        }
-                       break;
-               }
-               case MPF_COMMAND_MODIFY:
-               {
-                       if(request->descriptor) {
-                               mpf_context_topology_destroy(context,termination);
-                               mpf_termination_modify(termination,request->descriptor);
-                               mpf_termination_validate(termination);
-                               mpf_context_topology_apply(context,termination);
+                       case MPF_RESET_ASSOCIATIONS:
+                       {
+                               mpf_context_associations_reset(context);
+                               break;
+                       }
+                       case MPF_APPLY_TOPOLOGY:
+                       {
+                               mpf_context_topology_apply(context);
+                               break;
+                       }
+                       case MPF_DESTROY_TOPOLOGY:
+                       {
+                               mpf_context_topology_destroy(context);
+                               break;
+                       }
+                       default:
+                       {
+                               mpf_response->status_code = MPF_STATUS_CODE_FAILURE;
                        }
-                       break;
-               }
-               default:
-               {
-                       response->status_code = MPF_STATUS_CODE_FAILURE;
                }
        }
 
        return apt_task_msg_parent_signal(engine->task,response_msg);
 }
 
-static void mpf_engine_main(mpf_timer_t *timer, void *data)
+static void mpf_engine_main(mpf_scheduler_t *scheduler, void *data)
 {
        mpf_engine_t *engine = data;
        apt_task_msg_t *msg;
-       apt_list_elem_t *elem;
-       mpf_context_t *context;
 
        /* process request queue */
        apr_thread_mutex_lock(engine->request_queue_guard);
@@ -273,24 +399,15 @@ static void mpf_engine_main(mpf_timer_t *timer, void *data)
        }
        apr_thread_mutex_unlock(engine->request_queue_guard);
 
-       /* process contexts */
-       elem = apt_list_first_elem_get(engine->contexts);
-       while(elem) {
-               context = apt_list_elem_object_get(elem);
-               if(context) {
-                       mpf_context_process(context);
-               }
-               elem = apt_list_next_elem_get(engine->contexts,elem);
-       }
+       /* process factory of media contexts */
+       mpf_context_factory_process(engine->context_factory);
 }
 
 MPF_DECLARE(mpf_codec_manager_t*) mpf_engine_codec_manager_create(apr_pool_t *pool)
 {
-       mpf_codec_manager_t *codec_manager = mpf_codec_manager_create(3,pool);
+       mpf_codec_manager_t *codec_manager = mpf_codec_manager_create(4,pool);
        if(codec_manager) {
                mpf_codec_t *codec;
-               codec = mpf_codec_lpcm_create(pool);
-               mpf_codec_manager_codec_register(codec_manager,codec);
 
                codec = mpf_codec_g711u_create(pool);
                mpf_codec_manager_codec_register(codec_manager,codec);
index 4bab083ffaf9c885b6bed314519866d1d6d9f740..dd1bc6e280d23496a931d13ac1b4df7597d21065 100644 (file)
@@ -23,8 +23,9 @@ static apt_bool_t mpf_file_termination_destroy(mpf_termination_t *termination)
        return TRUE;
 }
 
-static apt_bool_t mpf_file_termination_modify(mpf_termination_t *termination, void *descriptor)
+static apt_bool_t mpf_file_termination_add(mpf_termination_t *termination, void *descriptor)
 {
+       apt_bool_t status = TRUE;
        mpf_audio_stream_t *audio_stream = termination->audio_stream;
        if(!audio_stream) {
                audio_stream = mpf_file_stream_create(termination,termination->pool);
@@ -34,12 +35,36 @@ static apt_bool_t mpf_file_termination_modify(mpf_termination_t *termination, vo
                termination->audio_stream = audio_stream;
        }
 
-       return mpf_file_stream_modify(audio_stream,descriptor);
+       if(descriptor) {
+               status = mpf_file_stream_modify(audio_stream,descriptor);
+       }
+       return status;
+}
+
+static apt_bool_t mpf_file_termination_modify(mpf_termination_t *termination, void *descriptor)
+{
+       apt_bool_t status = TRUE;
+       mpf_audio_stream_t *audio_stream = termination->audio_stream;
+       if(!audio_stream) {
+               return FALSE;
+       }
+
+       if(descriptor) {
+               status = mpf_file_stream_modify(audio_stream,descriptor);
+       }
+       return status;
+}
+
+static apt_bool_t mpf_file_termination_subtract(mpf_termination_t *termination)
+{
+       return TRUE;
 }
 
 static const mpf_termination_vtable_t file_vtable = {
        mpf_file_termination_destroy,
+       mpf_file_termination_add,
        mpf_file_termination_modify,
+       mpf_file_termination_subtract
 };
 
 static mpf_termination_t* mpf_file_termination_create(
index bec7e5a0bce641d74c92f261567e50a2e7f1ea71..d93e5c56aa48c67cd8a684deb8ea6562aca1b270 100644 (file)
@@ -33,6 +33,7 @@ struct mpf_frame_buffer_t {
 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_t *frame;
        mpf_frame_buffer_t *buffer = apr_palloc(pool,sizeof(mpf_frame_buffer_t));
 
        buffer->frame_size = frame_size;
@@ -40,8 +41,10 @@ mpf_frame_buffer_t* mpf_frame_buffer_create(apr_size_t frame_size, apr_size_t fr
        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;
+               frame = &buffer->frames[i];
+               frame->type = MEDIA_FRAME_TYPE_NONE;
+               frame->marker = MPF_MARKER_NONE;
+               frame->codec_frame.buffer = buffer->raw_data + i*buffer->frame_size;
        }
 
        buffer->write_pos = buffer->read_pos = 0;
@@ -102,6 +105,7 @@ apt_bool_t mpf_frame_buffer_read(mpf_frame_buffer_t *buffer, mpf_frame_t *media_
                /* normal read */
                mpf_frame_t *src_media_frame = mpf_frame_buffer_frame_get(buffer,buffer->read_pos);
                media_frame->type = src_media_frame->type;
+               media_frame->marker = src_media_frame->marker;
                if(media_frame->type & MEDIA_FRAME_TYPE_AUDIO) {
                        media_frame->codec_frame.size = src_media_frame->codec_frame.size;
                        memcpy(
@@ -113,11 +117,13 @@ apt_bool_t mpf_frame_buffer_read(mpf_frame_buffer_t *buffer, mpf_frame_t *media_
                        media_frame->event_frame = src_media_frame->event_frame;
                }
                src_media_frame->type = MEDIA_FRAME_TYPE_NONE;
+               src_media_frame->marker = MPF_MARKER_NONE;
                buffer->read_pos ++;
        }
        else {
                /* underflow */
                media_frame->type = MEDIA_FRAME_TYPE_NONE;
+               media_frame->marker = MPF_MARKER_NONE;
        }
        apr_thread_mutex_unlock(buffer->guard);
        return TRUE;
index 55a90bfc60ac6f7137f922194fe5dad48b4636fe..1cc6b33141f3a7e486b3f0e7f8ad7d00e629334b 100644 (file)
 
 #include "mpf_jitter_buffer.h"
 
+#if ENABLE_JB_TRACE
+#define JB_TRACE printf
+#else
+static APR_INLINE void null_trace() {}
+#define JB_TRACE null_trace
+#endif
+
 struct mpf_jitter_buffer_t {
+       /* jitter buffer config */
        mpf_jb_config_t *config;
+       /* codec to be used to dissect payload */
+       mpf_codec_t     *codec;
 
+       /* cyclic raw data */
        apr_byte_t      *raw_data;
+       /* frames (out of raw data) */
        mpf_frame_t     *frames;
+       /* number of frames */
        apr_size_t       frame_count;
+       /* frame timestamp units (samples) */
        apr_size_t       frame_ts;
+       /* frame size in bytes */
        apr_size_t       frame_size;
 
+       /* playout delay in timetsamp units */
        apr_size_t       playout_delay_ts;
 
+       /* write should be synchronized (offset calculated) */
        apr_byte_t       write_sync;
+       /* write timestamp offset */
        int              write_ts_offset;
        
+       /* write pointer in timestamp units */
        apr_size_t       write_ts;
+       /* read pointer in timestamp units */
        apr_size_t       read_ts;
 
-       apr_pool_t      *pool;
+       /* timestamp event starts at */
+       apr_size_t              event_write_base_ts;
+       /* the first (base) frame of the event */
+       mpf_named_event_frame_t event_write_base;
+       /* the last received update for the event */
+       const mpf_named_event_frame_t *event_write_update;
 };
 
 
-mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_t *codec, apr_pool_t *pool)
+mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_codec_descriptor_t *descriptor, mpf_codec_t *codec, apr_pool_t *pool)
 {
        size_t i;
+       mpf_frame_t *frame;
        mpf_jitter_buffer_t *jb = apr_palloc(pool,sizeof(mpf_jitter_buffer_t));
        if(!jb_config) {
                /* create default jb config */
@@ -62,24 +88,31 @@ mpf_jitter_buffer_t* mpf_jitter_buffer_create(mpf_jb_config_t *jb_config, mpf_co
                }
        }
        jb->config = jb_config;
+       jb->codec = codec;
 
-       jb->frame_ts = mpf_codec_frame_samples_calculate(codec->descriptor);
-       jb->frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
+       jb->frame_ts = mpf_codec_frame_samples_calculate(descriptor);
+       jb->frame_size = mpf_codec_frame_size_calculate(descriptor,codec->attribs);
        jb->frame_count = jb->config->max_playout_delay / CODEC_FRAME_TIME_BASE;
        jb->raw_data = apr_palloc(pool,jb->frame_size*jb->frame_count);
        jb->frames = apr_palloc(pool,sizeof(mpf_frame_t)*jb->frame_count);
        for(i=0; i<jb->frame_count; i++) {
-               jb->frames[i].type = MEDIA_FRAME_TYPE_NONE;
-               jb->frames[i].codec_frame.buffer = jb->raw_data + i*jb->frame_size;
+               frame = &jb->frames[i];
+               frame->type = MEDIA_FRAME_TYPE_NONE;
+               frame->marker = MPF_MARKER_NONE;
+               frame->codec_frame.buffer = jb->raw_data + i*jb->frame_size;
        }
 
        jb->playout_delay_ts = jb->config->initial_playout_delay *
-               codec->descriptor->channel_count * codec->descriptor->sampling_rate / 1000;
+               descriptor->channel_count * descriptor->sampling_rate / 1000;
 
        jb->write_sync = 1;
        jb->write_ts_offset = 0;
        jb->write_ts = jb->read_ts = 0;
 
+       jb->event_write_base_ts = 0;
+       memset(&jb->event_write_base,0,sizeof(mpf_named_event_frame_t));
+       jb->event_write_update = NULL;
+
        return jb;
 }
 
@@ -92,6 +125,11 @@ apt_bool_t mpf_jitter_buffer_restart(mpf_jitter_buffer_t *jb)
        jb->write_sync = 1;
        jb->write_ts_offset = 0;
        jb->write_ts = jb->read_ts;
+
+       jb->event_write_base_ts = 0;
+       memset(&jb->event_write_base,0,sizeof(mpf_named_event_frame_t));
+       jb->event_write_update = NULL;
+
        return TRUE;
 }
 
@@ -101,10 +139,8 @@ static APR_INLINE mpf_frame_t* mpf_jitter_buffer_frame_get(mpf_jitter_buffer_t *
        return &jb->frames[index];
 }
 
-static APR_INLINE jb_result_t mpf_jitter_buffer_write_prepare(mpf_jitter_buffer_t *jb, apr_uint32_t ts, 
-                                                                                               apr_size_t *write_ts, apr_size_t *available_frame_count)
+static APR_INLINE jb_result_t mpf_jitter_buffer_write_prepare(mpf_jitter_buffer_t *jb, apr_uint32_t ts, apr_size_t *write_ts)
 {
-       jb_result_t result = JB_OK;
        if(jb->write_sync) {
                jb->write_ts_offset = ts - jb->write_ts;
                jb->write_sync = 0;
@@ -115,40 +151,47 @@ static APR_INLINE jb_result_t mpf_jitter_buffer_write_prepare(mpf_jitter_buffer_
                /* not frame alligned */
                return JB_DISCARD_NOT_ALLIGNED;
        }
+       return JB_OK;
+}
 
-       if(*write_ts >= jb->write_ts) {
-               if(*write_ts - jb->write_ts > jb->frame_ts) {
+jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, void *buffer, apr_size_t size, apr_uint32_t ts)
+{
+       mpf_frame_t *media_frame;
+       apr_size_t write_ts;
+       apr_size_t available_frame_count;
+       jb_result_t result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts);
+       if(result != JB_OK) {
+               return result;
+       }
+
+       if(write_ts >= jb->write_ts) {
+               if(write_ts - jb->write_ts > jb->frame_ts) {
                        /* gap */
                }
                /* normal write */
        }
        else {
-               if(*write_ts >= jb->read_ts) {
+               if(write_ts >= jb->read_ts) {
                        /* backward write */
                }
                else {
                        /* too late */
-                       result = JB_DISCARD_TOO_LATE;
+                       JB_TRACE("JB write ts=%d too late\n",write_ts);
+                       return JB_DISCARD_TOO_LATE;
                }
        }
-       *available_frame_count = jb->frame_count - (*write_ts - jb->read_ts)/jb->frame_ts;
-       return result;
-}
-
-jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, mpf_codec_t *codec, void *buffer, apr_size_t size, apr_uint32_t ts)
-{
-       mpf_frame_t *media_frame;
-       apr_size_t write_ts;
-       apr_size_t available_frame_count = 0;
-       jb_result_t result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts,&available_frame_count);
-       if(result != JB_OK) {
-               return result;
+       available_frame_count = jb->frame_count - (write_ts - jb->read_ts)/jb->frame_ts;
+       if(available_frame_count <= 0) {
+               /* too early */
+               JB_TRACE("JB write ts=%d too early\n",write_ts);
+               return JB_DISCARD_TOO_EARLY;
        }
 
+       JB_TRACE("JB write ts=%d size=%d\n",write_ts,size);
        while(available_frame_count && size) {
                media_frame = mpf_jitter_buffer_frame_get(jb,write_ts);
                media_frame->codec_frame.size = jb->frame_size;
-               if(mpf_codec_dissect(codec,&buffer,&size,&media_frame->codec_frame) == FALSE) {
+               if(mpf_codec_dissect(jb->codec,&buffer,&size,&media_frame->codec_frame) == FALSE) {
                        break;
                }
 
@@ -167,9 +210,84 @@ jb_result_t mpf_jitter_buffer_write(mpf_jitter_buffer_t *jb, mpf_codec_t *codec,
        return result;
 }
 
-jb_result_t mpf_jitter_buffer_write_named_event(mpf_jitter_buffer_t *jb, mpf_named_event_frame_t *named_event, apr_uint32_t ts)
+jb_result_t mpf_jitter_buffer_event_write(mpf_jitter_buffer_t *jb, const mpf_named_event_frame_t *named_event, apr_uint32_t ts, apr_byte_t marker)
 {
-       return JB_OK;
+       mpf_frame_t *media_frame;
+       apr_size_t write_ts;
+       jb_result_t result = mpf_jitter_buffer_write_prepare(jb,ts,&write_ts);
+       if(result != JB_OK) {
+               return result;
+       }
+
+       /* new event detection */
+       if(!marker) {
+               if(jb->event_write_base.event_id != named_event->event_id) {
+                       /* new event detected, marker is missing though */
+                       marker = 1;
+               }
+               else if(jb->event_write_base_ts != write_ts) {
+                       /* detect whether this is a new segment of the same event or new event with missing marker
+                       assuming a threshold which equals to 4 frames */
+                       if(write_ts > jb->event_write_base_ts + jb->event_write_update->duration + 4*jb->frame_ts) {
+                               /* new event detected, marker is missing though */
+                               marker = 1;
+                       }
+                       else {
+                               /* new segment of the same long-lasting event detected */
+                               jb->event_write_base = *named_event;
+                               jb->event_write_update = &jb->event_write_base;
+                               jb->event_write_base_ts = write_ts;
+                       }
+               }
+       }
+       if(marker) {
+               /* new event */
+               jb->event_write_base = *named_event;
+               jb->event_write_update = &jb->event_write_base;
+               jb->event_write_base_ts = write_ts;
+       }
+       else {
+               /* an update */
+               if(named_event->duration <= jb->event_write_update->duration) {
+                       /* ignore this update, it's either a retransmission or
+                       something from the past, which makes no sense now */
+                       return JB_OK;
+               }
+               /* calculate position in jitter buffer considering the last received event (update) */
+               write_ts += jb->event_write_update->duration;
+       }
+
+       if(write_ts < jb->read_ts) {
+               /* too late */
+               JB_TRACE("JB write ts=%d event=%d duration=%d too late\n",
+                       write_ts,named_event->event_id,named_event->duration);
+               return JB_DISCARD_TOO_LATE;
+       }
+       else if( (write_ts - jb->read_ts)/jb->frame_ts >= jb->frame_count) {
+               /* too early */
+               JB_TRACE("JB write ts=%d event=%d duration=%d too early\n",
+                       write_ts,named_event->event_id,named_event->duration);
+               return JB_DISCARD_TOO_EARLY;
+       }
+
+       JB_TRACE("JB write ts=%d event=%d duration=%d\n",
+               write_ts,named_event->event_id,named_event->duration);
+       media_frame = mpf_jitter_buffer_frame_get(jb,write_ts);
+       media_frame->event_frame = *named_event;
+       media_frame->type |= MEDIA_FRAME_TYPE_EVENT;
+       if(marker) {
+               media_frame->marker = MPF_MARKER_START_OF_EVENT;
+       }
+       else if(named_event->edge == 1) {
+               media_frame->marker = MPF_MARKER_END_OF_EVENT;
+       }
+       jb->event_write_update = &media_frame->event_frame;
+
+       write_ts += jb->frame_ts;
+       if(write_ts > jb->write_ts) {
+               jb->write_ts = write_ts;
+       }
+       return result;
 }
 
 apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_frame)
@@ -177,7 +295,9 @@ apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_fr
        mpf_frame_t *src_media_frame = mpf_jitter_buffer_frame_get(jb,jb->read_ts);
        if(jb->write_ts > jb->read_ts) {
                /* normal read */
+               JB_TRACE("JB read ts=%d\n",     jb->read_ts);
                media_frame->type = src_media_frame->type;
+               media_frame->marker = src_media_frame->marker;
                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);
@@ -188,10 +308,13 @@ apt_bool_t mpf_jitter_buffer_read(mpf_jitter_buffer_t *jb, mpf_frame_t *media_fr
        }
        else {
                /* underflow */
+               JB_TRACE("JB read ts=%d underflow\n", jb->read_ts);
                media_frame->type = MEDIA_FRAME_TYPE_NONE;
+               media_frame->marker = MPF_MARKER_NONE;
                jb->write_ts += jb->frame_ts;
        }
        src_media_frame->type = MEDIA_FRAME_TYPE_NONE;
+       src_media_frame->marker = MPF_MARKER_NONE;
        jb->read_ts += jb->frame_ts;
        return TRUE;
 }
diff --git a/libs/unimrcp/libs/mpf/src/mpf_mixer.c b/libs/unimrcp/libs/mpf/src/mpf_mixer.c
new file mode 100644 (file)
index 0000000..0d5c0f1
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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 "mpf_mixer.h"
+#include "mpf_encoder.h"
+#include "mpf_decoder.h"
+#include "mpf_resampler.h"
+#include "mpf_codec_manager.h"
+#include "apt_log.h"
+
+typedef struct mpf_mixer_t mpf_mixer_t;
+
+/** MPF mixer derived from MPF object */
+struct mpf_mixer_t {
+       /** MPF mixer base */
+       mpf_object_t         base;
+       /** Array of audio sources */
+       mpf_audio_stream_t **source_arr;
+       /** Number of audio sources */
+       apr_size_t           source_count;
+       /** Audio sink */
+       mpf_audio_stream_t  *sink;
+
+       /** Frame to read from audio source */
+       mpf_frame_t          frame;
+       /** Mixed frame to write to audio sink */
+       mpf_frame_t          mix_frame;
+};
+
+static apt_bool_t mpf_frames_mix(mpf_frame_t *mix_frame, const mpf_frame_t *frame)
+{
+       apr_size_t i;
+       apr_int16_t *mix_buf = mix_frame->codec_frame.buffer;
+       const apr_int16_t *buf = frame->codec_frame.buffer;
+       apr_size_t samples = frame->codec_frame.size / sizeof(apr_int16_t);
+
+       if(mix_frame->codec_frame.size != frame->codec_frame.size) {
+               return FALSE;
+       }
+
+       if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) {
+               for(i=0; i<samples; i++) {
+                       /* overflow MUST be considered */
+                       mix_buf[i] = mix_buf[i] + buf[i];
+               }
+               mix_frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+       }
+
+       return TRUE;
+}
+
+static apt_bool_t mpf_mixer_process(mpf_object_t *object)
+{
+       apr_size_t i;
+       mpf_audio_stream_t *source;
+       mpf_mixer_t *mixer = (mpf_mixer_t*) object;
+
+       mixer->mix_frame.type = MEDIA_FRAME_TYPE_NONE;
+       mixer->mix_frame.marker = MPF_MARKER_NONE;
+       memset(mixer->mix_frame.codec_frame.buffer,0,mixer->mix_frame.codec_frame.size);
+       for(i=0; i<mixer->source_count; i++) {
+               source = mixer->source_arr[i];
+               if(source) {
+                       mixer->frame.type = MEDIA_FRAME_TYPE_NONE;
+                       mixer->frame.marker = MPF_MARKER_NONE;
+                       source->vtable->read_frame(source,&mixer->frame);
+                       mpf_frames_mix(&mixer->mix_frame,&mixer->frame);
+               }
+       }
+       mixer->sink->vtable->write_frame(mixer->sink,&mixer->mix_frame);
+       return TRUE;
+}
+
+static apt_bool_t mpf_mixer_destroy(mpf_object_t *object)
+{
+       apr_size_t i;
+       mpf_audio_stream_t *source;
+       mpf_mixer_t *mixer = (mpf_mixer_t*) object;
+
+       for(i=0; i<mixer->source_count; i++)    {
+               source = mixer->source_arr[i];
+               if(source) {
+                       mpf_audio_stream_rx_close(source);
+               }
+       }
+       mpf_audio_stream_tx_close(mixer->sink);
+       return TRUE;
+}
+
+static void mpf_mixer_trace(mpf_object_t *object)
+{
+       mpf_mixer_t *mixer = (mpf_mixer_t*) object;
+       apr_size_t i;
+       mpf_audio_stream_t *source;
+       char buf[2048];
+       apr_size_t offset;
+
+       apt_text_stream_t output;
+       apt_text_stream_init(&output,buf,sizeof(buf)-1);
+
+       for(i=0; i<mixer->source_count; i++)    {
+               source = mixer->source_arr[i];
+               if(source) {
+                       mpf_audio_stream_trace(source,STREAM_DIRECTION_RECEIVE,&output);
+                       if(apt_text_is_eos(&output) == FALSE) {
+                               *output.pos++ = ';';
+                       }
+               }
+       }
+
+       offset = output.pos - output.text.buf;
+       output.pos += apr_snprintf(output.pos, output.text.length - offset,
+               "->Mixer->");
+
+       mpf_audio_stream_trace(mixer->sink,STREAM_DIRECTION_SEND,&output);
+
+       *output.pos = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf);
+}
+
+MPF_DECLARE(mpf_object_t*) mpf_mixer_create(
+                                                               mpf_audio_stream_t **source_arr, 
+                                                               apr_size_t source_count, 
+                                                               mpf_audio_stream_t *sink, 
+                                                               const mpf_codec_manager_t *codec_manager, 
+                                                               apr_pool_t *pool)
+{
+       apr_size_t i;
+       apr_size_t frame_size;
+       mpf_codec_descriptor_t *descriptor;
+       mpf_audio_stream_t *source;
+       mpf_mixer_t *mixer;
+       if(!source_arr || !source_count || !sink) {
+               return NULL;
+       }
+
+       mixer = apr_palloc(pool,sizeof(mpf_mixer_t));
+       mixer->source_arr = NULL;
+       mixer->source_count = 0;
+       mixer->sink = NULL;
+       mpf_object_init(&mixer->base);
+       mixer->base.process = mpf_mixer_process;
+       mixer->base.destroy = mpf_mixer_destroy;
+       mixer->base.trace = mpf_mixer_trace;
+
+       if(mpf_audio_stream_tx_validate(sink,NULL,NULL,pool) == FALSE) {
+               return NULL;
+       }
+
+       descriptor = sink->tx_descriptor;
+       if(descriptor && mpf_codec_lpcm_descriptor_match(descriptor) == FALSE) {
+               mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,descriptor,pool);
+               if(codec) {
+                       /* set encoder after mixer */
+                       mpf_audio_stream_t *encoder = mpf_encoder_create(sink,codec,pool);
+                       sink = encoder;
+               }
+       }
+       mixer->sink = sink;
+       mpf_audio_stream_tx_open(sink,NULL);
+
+       for(i=0; i<source_count; i++)   {
+               source = source_arr[i];
+               if(!source) continue;
+
+               if(mpf_audio_stream_rx_validate(source,NULL,NULL,pool) == FALSE) {
+                       continue;
+               }
+
+               descriptor = source->rx_descriptor;
+               if(descriptor && mpf_codec_lpcm_descriptor_match(descriptor) == FALSE) {
+                       mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,descriptor,pool);
+                       if(codec) {
+                               /* set decoder before mixer */
+                               mpf_audio_stream_t *decoder = mpf_decoder_create(source,codec,pool);
+                               source = decoder;
+                       }
+               }
+               source_arr[i] = source;
+               mpf_audio_stream_rx_open(source,NULL);
+       }
+       mixer->source_arr = source_arr;
+       mixer->source_count = source_count;
+
+       descriptor = sink->tx_descriptor;
+       frame_size = mpf_codec_linear_frame_size_calculate(descriptor->sampling_rate,descriptor->channel_count);
+       mixer->frame.codec_frame.size = frame_size;
+       mixer->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
+       mixer->mix_frame.codec_frame.size = frame_size;
+       mixer->mix_frame.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return &mixer->base;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_multiplier.c b/libs/unimrcp/libs/mpf/src/mpf_multiplier.c
new file mode 100644 (file)
index 0000000..289a194
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 "mpf_multiplier.h"
+#include "mpf_encoder.h"
+#include "mpf_decoder.h"
+#include "mpf_resampler.h"
+#include "mpf_codec_manager.h"
+#include "apt_log.h"
+
+typedef struct mpf_multiplier_t mpf_multiplier_t;
+
+/** MPF multiplier derived from MPF object */
+struct mpf_multiplier_t {
+       /** MPF multiplier base */
+       mpf_object_t         base;
+       /** Audio source */
+       mpf_audio_stream_t  *source;
+       /** Array of audio sinks */
+       mpf_audio_stream_t **sink_arr;
+       /** Number of audio sinks */
+       apr_size_t           sink_count;
+
+       /** Media frame used to read data from source and write it to sinks */
+       mpf_frame_t          frame;
+};
+
+static apt_bool_t mpf_multiplier_process(mpf_object_t *object)
+{
+       apr_size_t i;
+       mpf_audio_stream_t *sink;
+       mpf_multiplier_t *multiplier = (mpf_multiplier_t*) object;
+
+       multiplier->frame.type = MEDIA_FRAME_TYPE_NONE;
+       multiplier->frame.marker = MPF_MARKER_NONE;
+       multiplier->source->vtable->read_frame(multiplier->source,&multiplier->frame);
+       
+       if((multiplier->frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) {
+               memset( multiplier->frame.codec_frame.buffer,
+                               0,
+                               multiplier->frame.codec_frame.size);
+       }
+
+       for(i=0; i<multiplier->sink_count; i++) {
+               sink = multiplier->sink_arr[i];
+               if(sink) {
+                       sink->vtable->write_frame(sink,&multiplier->frame);
+               }
+       }
+       return TRUE;
+}
+
+static apt_bool_t mpf_multiplier_destroy(mpf_object_t *object)
+{
+       apr_size_t i;
+       mpf_audio_stream_t *sink;
+       mpf_multiplier_t *multiplier = (mpf_multiplier_t*) object;
+
+       mpf_audio_stream_rx_close(multiplier->source);
+       for(i=0; i<multiplier->sink_count; i++) {
+               sink = multiplier->sink_arr[i];
+               if(sink) {
+                       mpf_audio_stream_tx_close(sink);
+               }
+       }
+       return TRUE;
+}
+
+static void mpf_multiplier_trace(mpf_object_t *object)
+{
+       mpf_multiplier_t *multiplier = (mpf_multiplier_t*) object;
+       apr_size_t i;
+       mpf_audio_stream_t *sink;
+       char buf[2048];
+       apr_size_t offset;
+
+       apt_text_stream_t output;
+       apt_text_stream_init(&output,buf,sizeof(buf)-1);
+
+       mpf_audio_stream_trace(multiplier->source,STREAM_DIRECTION_RECEIVE,&output);
+       
+       offset = output.pos - output.text.buf;
+       output.pos += apr_snprintf(output.pos, output.text.length - offset,
+               "->Multiplier->");
+
+       for(i=0; i<multiplier->sink_count; i++) {
+               sink = multiplier->sink_arr[i];
+               if(sink) {
+                       mpf_audio_stream_trace(sink,STREAM_DIRECTION_SEND,&output);
+                       if(apt_text_is_eos(&output) == FALSE) {
+                               *output.pos++ = ';';
+                       }
+               }
+       }
+
+       *output.pos = '\0';
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,output.text.buf);
+}
+
+MPF_DECLARE(mpf_object_t*) mpf_multiplier_create(
+                                                               mpf_audio_stream_t *source,
+                                                               mpf_audio_stream_t **sink_arr,
+                                                               apr_size_t sink_count,
+                                                               const mpf_codec_manager_t *codec_manager,
+                                                               apr_pool_t *pool)
+{
+       apr_size_t i;
+       apr_size_t frame_size;
+       mpf_codec_descriptor_t *descriptor;
+       mpf_audio_stream_t *sink;
+       mpf_multiplier_t *multiplier;
+       if(!source || !sink_arr || !sink_count) {
+               return NULL;
+       }
+
+       multiplier = apr_palloc(pool,sizeof(mpf_multiplier_t));
+       multiplier->source = NULL;
+       multiplier->sink_arr = NULL;
+       multiplier->sink_count = 0;
+       mpf_object_init(&multiplier->base);
+       multiplier->base.process = mpf_multiplier_process;
+       multiplier->base.destroy = mpf_multiplier_destroy;
+       multiplier->base.trace = mpf_multiplier_trace;
+
+       if(mpf_audio_stream_rx_validate(source,NULL,NULL,pool) == FALSE) {
+               return NULL;
+       }
+
+       descriptor = source->rx_descriptor;
+       if(descriptor && mpf_codec_lpcm_descriptor_match(descriptor) == FALSE) {
+               mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,descriptor,pool);
+               if(codec) {
+                       /* set decoder before bridge */
+                       mpf_audio_stream_t *decoder = mpf_decoder_create(source,codec,pool);
+                       source = decoder;
+               }
+       }
+       multiplier->source = source;
+       mpf_audio_stream_rx_open(source,NULL);
+       
+       for(i=0; i<sink_count; i++)     {
+               sink = sink_arr[i];
+               if(!sink) continue;
+
+               if(mpf_audio_stream_tx_validate(sink,NULL,NULL,pool) == FALSE) {
+                       continue;
+               }
+
+               descriptor = sink->tx_descriptor;
+               if(descriptor && mpf_codec_lpcm_descriptor_match(descriptor) == FALSE) {
+                       mpf_codec_t *codec = mpf_codec_manager_codec_get(codec_manager,descriptor,pool);
+                       if(codec) {
+                               /* set encoder after bridge */
+                               mpf_audio_stream_t *encoder = mpf_encoder_create(sink,codec,pool);
+                               sink = encoder;
+                       }
+               }
+               sink_arr[i] = sink;
+               mpf_audio_stream_tx_open(sink,NULL);
+       }
+       multiplier->sink_arr = sink_arr;
+       multiplier->sink_count = sink_count;
+       
+       descriptor = source->rx_descriptor;
+       frame_size = mpf_codec_linear_frame_size_calculate(descriptor->sampling_rate,descriptor->channel_count);
+       multiplier->frame.codec_frame.size = frame_size;
+       multiplier->frame.codec_frame.buffer = apr_palloc(pool,frame_size);
+       return &multiplier->base;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_named_event.c b/libs/unimrcp/libs/mpf/src/mpf_named_event.c
new file mode 100644 (file)
index 0000000..f8bc753
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 "mpf_named_event.h"
+
+#define TEL_EVENT_NAME        "telephone-event"
+#define TEL_EVENT_NAME_LENGTH (sizeof(TEL_EVENT_NAME)-1)
+
+#define TEL_EVENT_FMTP        "0-15"
+#define TEL_EVENT_FMTP_LENGTH (sizeof(TEL_EVENT_FMTP)-1)
+
+
+MPF_DECLARE(mpf_codec_descriptor_t*) mpf_event_descriptor_create(apr_uint16_t sampling_rate, apr_pool_t *pool)
+{
+       mpf_codec_descriptor_t *descriptor = apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+       mpf_codec_descriptor_init(descriptor);
+       descriptor->payload_type = 101;
+       descriptor->name.buf = TEL_EVENT_NAME;
+       descriptor->name.length = TEL_EVENT_NAME_LENGTH;
+       descriptor->sampling_rate = sampling_rate;
+       descriptor->channel_count = 1;
+       descriptor->format.buf = TEL_EVENT_FMTP;
+       descriptor->format.length = TEL_EVENT_FMTP_LENGTH;
+       return descriptor;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_event_descriptor_check(const mpf_codec_descriptor_t *descriptor)
+{
+       apt_str_t name;
+       name.buf = TEL_EVENT_NAME;
+       name.length = TEL_EVENT_NAME_LENGTH;
+       return apt_string_compare(&descriptor->name,&name);
+}
+
+MPF_DECLARE(apr_uint32_t) mpf_dtmf_char_to_event_id(const char dtmf_char)
+{
+       if ((dtmf_char >= '0') && (dtmf_char <= '9'))
+               return dtmf_char - '0';
+       else if (dtmf_char == '*')
+               return 10;
+       else if (dtmf_char == '#')
+               return 11;
+       else if ((dtmf_char >= 'A') && (dtmf_char <= 'D'))
+               return 12 + dtmf_char - 'A';
+
+       return 255; /* Invalid DTMF event */
+}
+
+MPF_DECLARE(char) mpf_event_id_to_dtmf_char(const apr_uint32_t event_id)
+{
+       if (event_id <= 9)
+               return '0' + (char)event_id;
+       else if (event_id == 10)
+               return '*';
+       else if (event_id == 11)
+               return '#';
+       else if (event_id <= 15)
+               return 'A' + (char)event_id - 12;
+
+       return 0; /* Not a DTMF event */
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_resampler.c b/libs/unimrcp/libs/mpf/src/mpf_resampler.c
new file mode 100644 (file)
index 0000000..113ffac
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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 "mpf_resampler.h"
+#include "apt_log.h"
+
+MPF_DECLARE(mpf_audio_stream_t*) mpf_resampler_create(mpf_audio_stream_t *source, mpf_audio_stream_t *sink, apr_pool_t *pool)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,
+               "Currently resampling is not supported. "
+               "Try to configure and use the same sampling rate on both ends");
+       return NULL;
+}
index 5b5931546f5aff1f8c10d40d53bbc60463da3dcf..a34f05fc93a80113882da2ef98de12487f50c3a8 100644 (file)
@@ -38,17 +38,17 @@ MPF_DECLARE(mpf_rtp_attrib_e) mpf_rtp_attrib_id_find(const apt_str_t *attrib)
        return apt_string_table_id_find(mpf_rtp_attrib_table,RTP_ATTRIB_COUNT,attrib);
 }
 
-MPF_DECLARE(const apt_str_t*) mpf_stream_mode_str_get(mpf_stream_mode_e direction)
+MPF_DECLARE(const apt_str_t*) mpf_rtp_direction_str_get(mpf_stream_direction_e direction)
 {
        mpf_rtp_attrib_e attrib_id = RTP_ATTRIB_UNKNOWN;
        switch(direction) {
-               case STREAM_MODE_SEND:
+               case STREAM_DIRECTION_SEND:
                        attrib_id = RTP_ATTRIB_SENDONLY;
                        break;
-               case STREAM_MODE_RECEIVE:
+               case STREAM_DIRECTION_RECEIVE:
                        attrib_id = RTP_ATTRIB_RECVONLY;
                        break;
-               case STREAM_MODE_SEND_RECEIVE:
+               case STREAM_DIRECTION_DUPLEX:
                        attrib_id = RTP_ATTRIB_SENDRECV;
                        break;
                default:
index d97b1a81cbbbfecd515728250597a6bd6f094a84..9e98c4144ae95f9ce0c376abde94610f8c75ae27 100644 (file)
  */
 
 #include <apr_network_io.h>
+#include "apt_net.h"
 #include "mpf_rtp_stream.h"
 #include "mpf_termination.h"
 #include "mpf_codec_manager.h"
+#include "mpf_timer_manager.h"
 #include "mpf_rtp_header.h"
+#include "mpf_rtcp_packet.h"
 #include "mpf_rtp_defs.h"
+#include "mpf_rtp_pt.h"
 #include "apt_log.h"
 
+/** Max size of RTP packet */
+#define MAX_RTP_PACKET_SIZE  1500
+/** Max size of RTCP packet */
+#define MAX_RTCP_PACKET_SIZE 1500
+
+/* Reason strings used in RTCP BYE messages (informative only) */
+#define RTCP_BYE_SESSION_ENDED "Session ended"
+#define RTCP_BYE_TALKSPURT_ENDED "Talskpurt ended"
+
+#if ENABLE_RTP_PACKET_TRACE
+#define RTP_TRACE printf
+#else
+static APR_INLINE void null_trace() {}
+#define RTP_TRACE null_trace
+#endif
 
 /** RTP stream */
 typedef struct mpf_rtp_stream_t mpf_rtp_stream_t;
@@ -30,24 +49,31 @@ struct mpf_rtp_stream_t {
 
        mpf_rtp_media_descriptor_t *local_media;
        mpf_rtp_media_descriptor_t *remote_media;
+       mpf_media_state_e           state;
 
        rtp_transmitter_t           transmitter;
        rtp_receiver_t              receiver;
 
        mpf_rtp_config_t           *config;
 
-       apr_socket_t               *socket;
-       apr_sockaddr_t             *local_sockaddr;
-       apr_sockaddr_t             *remote_sockaddr;
+       apr_socket_t               *rtp_socket;
+       apr_socket_t               *rtcp_socket;
+       apr_sockaddr_t             *rtp_l_sockaddr;
+       apr_sockaddr_t             *rtp_r_sockaddr;
+       apr_sockaddr_t             *rtcp_l_sockaddr;
+       apr_sockaddr_t             *rtcp_r_sockaddr;
+
+       mpf_timer_t                *rtcp_tx_timer;
+       mpf_timer_t                *rtcp_rx_timer;
        
        apr_pool_t                 *pool;
 };
 
 static apt_bool_t mpf_rtp_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t mpf_rtp_stream_receive(mpf_audio_stream_t *stream, mpf_frame_t *frame);
-static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t mpf_rtp_tx_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
 
@@ -61,67 +87,102 @@ static const mpf_audio_stream_vtable_t vtable = {
        mpf_rtp_stream_transmit
 };
 
-static apt_bool_t mpf_rtp_socket_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media);
+static apt_bool_t mpf_rtp_socket_pair_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media);
+static void mpf_rtp_socket_pair_close(mpf_rtp_stream_t *stream);
+
+static apt_bool_t mpf_rtcp_report_send(mpf_rtp_stream_t *stream);
+static apt_bool_t mpf_rtcp_bye_send(mpf_rtp_stream_t *stream, apt_str_t *reason);
+static void mpf_rtcp_tx_timer_proc(mpf_timer_t *timer, void *obj);
+static void mpf_rtcp_rx_timer_proc(mpf_timer_t *timer, void *obj);
 
 
 MPF_DECLARE(mpf_audio_stream_t*) mpf_rtp_stream_create(mpf_termination_t *termination, mpf_rtp_config_t *config, apr_pool_t *pool)
 {
        mpf_rtp_stream_t *rtp_stream = apr_palloc(pool,sizeof(mpf_rtp_stream_t));
+       mpf_stream_capabilities_t *capabilities = mpf_stream_capabilities_create(STREAM_DIRECTION_DUPLEX,pool);
+       mpf_audio_stream_t *audio_stream = mpf_audio_stream_create(rtp_stream,&vtable,capabilities,pool);
+       if(!audio_stream) {
+               return NULL;
+       }
+
+       audio_stream->direction = STREAM_DIRECTION_NONE;
+       audio_stream->termination = termination;
+
+       rtp_stream->base = audio_stream;
        rtp_stream->pool = pool;
        rtp_stream->config = config;
        rtp_stream->local_media = NULL;
        rtp_stream->remote_media = NULL;
-       rtp_stream->socket = NULL;
-       rtp_stream->local_sockaddr = NULL;
-       rtp_stream->remote_sockaddr = NULL;
-       rtp_stream->base = mpf_audio_stream_create(rtp_stream,&vtable,STREAM_MODE_NONE,pool);
-       rtp_stream->base->termination = termination;
+       rtp_stream->rtp_socket = NULL;
+       rtp_stream->rtcp_socket = NULL;
+       rtp_stream->rtp_l_sockaddr = NULL;
+       rtp_stream->rtp_r_sockaddr = NULL;
+       rtp_stream->rtcp_l_sockaddr = NULL;
+       rtp_stream->rtcp_r_sockaddr = NULL;
+       rtp_stream->rtcp_tx_timer = NULL;
+       rtp_stream->rtcp_rx_timer = NULL;
+       rtp_stream->state = MPF_MEDIA_DISABLED;
        rtp_receiver_init(&rtp_stream->receiver);
        rtp_transmitter_init(&rtp_stream->transmitter);
-       rtp_stream->transmitter.ssrc = (apr_uint32_t)apr_time_now();
+       rtp_stream->transmitter.sr_stat.ssrc = (apr_uint32_t)apr_time_now();
+
+       if(config->rtcp == TRUE) {
+               if(config->rtcp_tx_interval) {
+                       rtp_stream->rtcp_tx_timer = mpf_timer_create(
+                                                                               termination->timer_manager,
+                                                                               mpf_rtcp_tx_timer_proc,
+                                                                               rtp_stream, pool);
+               }
+               if(config->rtcp_rx_resolution) {
+                       rtp_stream->rtcp_rx_timer = mpf_timer_create(
+                                                                               termination->timer_manager,
+                                                                               mpf_rtcp_rx_timer_proc,
+                                                                               rtp_stream, pool);
+               }
+       }
 
-       return rtp_stream->base;
+       return audio_stream;
 }
 
-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)
+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, mpf_stream_capabilities_t *capabilities)
 {
        apt_bool_t status = TRUE;
        if(!local_media) {
                /* local media is not specified, create the default one */
                local_media = apr_palloc(rtp_stream->pool,sizeof(mpf_rtp_media_descriptor_t));
                mpf_rtp_media_descriptor_init(local_media);
-               local_media->base.state = MPF_MEDIA_ENABLED;
-               local_media->mode = STREAM_MODE_SEND_RECEIVE;
+               local_media->state = MPF_MEDIA_ENABLED;
+               local_media->direction = STREAM_DIRECTION_DUPLEX;
        }
        if(remote_media) {
-               local_media->base.id = remote_media->base.id;
+               local_media->id = remote_media->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->ip.length == 0) {
+               local_media->ip = rtp_stream->config->ip;
+               local_media->ext_ip = rtp_stream->config->ext_ip;
        }
-       if(local_media->base.port == 0) {
+       if(local_media->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;
 
                do {
-                       local_media->base.port = rtp_stream->config->rtp_port_cur;
+                       local_media->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) {
+                       if(mpf_rtp_socket_pair_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;
+                       local_media->state = MPF_MEDIA_DISABLED;
                        status = FALSE;
                }
        }
-       else if(mpf_rtp_socket_create(rtp_stream,local_media) == FALSE) {
-               local_media->base.state = MPF_MEDIA_DISABLED;
+       else if(mpf_rtp_socket_pair_create(rtp_stream,local_media) == FALSE) {
+               local_media->state = MPF_MEDIA_DISABLED;
                status = FALSE;
        }
 
@@ -141,20 +202,24 @@ static apt_bool_t mpf_rtp_stream_local_media_create(mpf_rtp_stream_t *rtp_stream
                                                                &rtp_stream->config->codec_list,
                                                                rtp_stream->pool);
                }
+               
+               if(capabilities) {
+                       mpf_codec_list_modify(&local_media->codec_list,&capabilities->codecs);
+               }
        }
 
        rtp_stream->local_media = local_media;
        return status;
 }
 
-static apt_bool_t mpf_rtp_stream_local_media_update(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *media)
+static apt_bool_t mpf_rtp_stream_local_media_update(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *media, mpf_stream_capabilities_t *capabilities)
 {
        apt_bool_t status = TRUE;
-       if(apt_string_compare(&rtp_stream->local_media->base.ip,&media->base.ip) == FALSE ||
-               rtp_stream->local_media->base.port != media->base.port) {
+       if(apt_string_compare(&rtp_stream->local_media->ip,&media->ip) == FALSE ||
+               rtp_stream->local_media->port != media->port) {
 
-               if(mpf_rtp_socket_create(rtp_stream,media) == FALSE) {
-                       media->base.state = MPF_MEDIA_DISABLED;
+               if(mpf_rtp_socket_pair_create(rtp_stream,media) == FALSE) {
+                       media->state = MPF_MEDIA_DISABLED;
                        status = FALSE;
                }
        }
@@ -163,6 +228,9 @@ static apt_bool_t mpf_rtp_stream_local_media_update(mpf_rtp_stream_t *rtp_stream
                                                        rtp_stream->base->termination->codec_manager,
                                                        &media->codec_list,
                                                        rtp_stream->pool);
+               if(capabilities) {
+                       mpf_codec_list_modify(&media->codec_list,&capabilities->codecs);
+               }
        }
 
        rtp_stream->local_media = media;
@@ -172,20 +240,33 @@ static apt_bool_t mpf_rtp_stream_local_media_update(mpf_rtp_stream_t *rtp_stream
 static apt_bool_t mpf_rtp_stream_remote_media_update(mpf_rtp_stream_t *rtp_stream, mpf_rtp_media_descriptor_t *media)
 {
        apt_bool_t status = TRUE;
-       if(!rtp_stream->remote_media || 
-               apt_string_compare(&rtp_stream->remote_media->base.ip,&media->base.ip) == FALSE ||
-               rtp_stream->remote_media->base.port != media->base.port) {
-
-               rtp_stream->remote_sockaddr = NULL;
-               apr_sockaddr_info_get(
-                       &rtp_stream->remote_sockaddr,
-                       media->base.ip.buf,
-                       APR_INET,
-                       media->base.port,
-                       0,
-                       rtp_stream->pool);
-               if(!rtp_stream->remote_sockaddr) {
-                       status = FALSE;
+       if(media->state == MPF_MEDIA_ENABLED) {
+               if(!rtp_stream->remote_media || 
+                       apt_string_compare(&rtp_stream->remote_media->ip,&media->ip) == FALSE ||
+                       rtp_stream->remote_media->port != media->port) {
+
+                       /* update RTP port */
+                       rtp_stream->rtp_r_sockaddr = NULL;
+                       apr_sockaddr_info_get(
+                               &rtp_stream->rtp_r_sockaddr,
+                               media->ip.buf,
+                               APR_INET,
+                               media->port,
+                               0,
+                               rtp_stream->pool);
+                       if(!rtp_stream->rtp_r_sockaddr) {
+                               status = FALSE;
+                       }
+
+                       /* update RTCP port */
+                       rtp_stream->rtcp_r_sockaddr = NULL;
+                       apr_sockaddr_info_get(
+                               &rtp_stream->rtcp_r_sockaddr,
+                               media->ip.buf,
+                               APR_INET,
+                               media->port+1,
+                               0,
+                               rtp_stream->pool);
                }
        }
 
@@ -195,33 +276,112 @@ static apt_bool_t mpf_rtp_stream_remote_media_update(mpf_rtp_stream_t *rtp_strea
 
 static apt_bool_t mpf_rtp_stream_media_negotiate(mpf_rtp_stream_t *rtp_stream)
 {
-       if(!rtp_stream->local_media || !rtp_stream->remote_media) {
+       mpf_rtp_media_descriptor_t *local_media = rtp_stream->local_media;
+       mpf_rtp_media_descriptor_t *remote_media = rtp_stream->remote_media;
+       if(!local_media || !remote_media) {
                return FALSE;
        }
 
-       rtp_stream->local_media->base.id = rtp_stream->remote_media->base.id;
-       rtp_stream->local_media->base.state = rtp_stream->remote_media->base.state;
-
-       rtp_stream->local_media->mid = rtp_stream->remote_media->mid;
-       rtp_stream->local_media->ptime = rtp_stream->remote_media->ptime;
-       rtp_stream->local_media->mode = mpf_stream_mode_negotiate(rtp_stream->remote_media->mode);
+       local_media->id = remote_media->id;
+       local_media->mid = remote_media->mid;
+       local_media->ptime = remote_media->ptime;
+
+       if(rtp_stream->state == MPF_MEDIA_DISABLED && remote_media->state == MPF_MEDIA_ENABLED) {
+               /* enable RTP/RTCP session */
+               rtp_stream->state = MPF_MEDIA_ENABLED;
+               if(rtp_stream->rtp_l_sockaddr) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Enable RTP Session %s:%hu",
+                               rtp_stream->rtp_l_sockaddr->hostname,
+                               rtp_stream->rtp_l_sockaddr->port);
+               }
 
-       if(mpf_codec_list_is_empty(&rtp_stream->remote_media->codec_list) == TRUE) {
-               /* no remote codecs available, initialize them according to the local codecs  */
-               mpf_codec_list_copy(&rtp_stream->remote_media->codec_list,
-                                                       &rtp_stream->local_media->codec_list,
-                                                       rtp_stream->pool);
+               if(rtp_stream->rtcp_tx_timer) {
+                       mpf_timer_set(rtp_stream->rtcp_tx_timer,rtp_stream->config->rtcp_tx_interval);
+               }
+               if(rtp_stream->rtcp_rx_timer) {
+                       mpf_timer_set(rtp_stream->rtcp_rx_timer,rtp_stream->config->rtcp_rx_resolution);
+               }
        }
+       else if(rtp_stream->state == MPF_MEDIA_ENABLED && remote_media->state == MPF_MEDIA_DISABLED) {
+               /* disable RTP/RTCP session */
+               rtp_stream->state = MPF_MEDIA_DISABLED;
+               if(rtp_stream->rtp_l_sockaddr) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Disable RTP Session %s:%hu",
+                               rtp_stream->rtp_l_sockaddr->hostname,
+                               rtp_stream->rtp_l_sockaddr->port);
+               }
 
-       /* intersect local and remote codecs */
-       if(rtp_stream->config->own_preferrence == TRUE) {
-               mpf_codec_list_intersect(&rtp_stream->local_media->codec_list,&rtp_stream->remote_media->codec_list);
+               if(rtp_stream->rtcp_tx_timer) {
+                       mpf_timer_kill(rtp_stream->rtcp_tx_timer);
+               }
+               if(rtp_stream->rtcp_rx_timer) {
+                       mpf_timer_kill(rtp_stream->rtcp_rx_timer);
+               }
+               if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy != RTCP_BYE_DISABLE) {
+                       apt_str_t reason = {RTCP_BYE_SESSION_ENDED, sizeof(RTCP_BYE_SESSION_ENDED)-1};
+                       mpf_rtcp_bye_send(rtp_stream,&reason);
+               }
        }
-       else {
-               mpf_codec_list_intersect(&rtp_stream->remote_media->codec_list,&rtp_stream->local_media->codec_list);
+
+       local_media->state = remote_media->state;
+       local_media->direction = mpf_stream_reverse_direction_get(remote_media->direction);
+       rtp_stream->base->direction = local_media->direction;
+
+       if(remote_media->state == MPF_MEDIA_ENABLED) {
+               if(mpf_codec_list_is_empty(&remote_media->codec_list) == TRUE) {
+                       /* no remote codecs available, initialize them according to the local codecs  */
+                       mpf_codec_list_copy(&remote_media->codec_list,
+                                                               &local_media->codec_list,
+                                                               rtp_stream->pool);
+               }
+
+               /* intersect local and remote codecs */
+               if(rtp_stream->config->own_preferrence == TRUE) {
+                       mpf_codec_lists_intersect(
+                               &local_media->codec_list,
+                               &remote_media->codec_list);
+               }
+               else {
+                       mpf_codec_lists_intersect(
+                               &remote_media->codec_list,
+                               &local_media->codec_list);
+               }
        }
 
-       rtp_stream->base->mode = rtp_stream->local_media->mode;
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_add(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_rtp_stream_remove(mpf_audio_stream_t *stream)
+{
+       mpf_rtp_stream_t *rtp_stream = stream->obj;
+       
+       if(rtp_stream->state == MPF_MEDIA_ENABLED) {
+               /* disable RTP/RTCP session */
+               rtp_stream->state = MPF_MEDIA_DISABLED;
+               if(rtp_stream->rtp_l_sockaddr) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTP Session %s:%hu",
+                               rtp_stream->rtp_l_sockaddr->hostname,
+                               rtp_stream->rtp_l_sockaddr->port);
+               }
+
+               if(rtp_stream->rtcp_tx_timer) {
+                       mpf_timer_kill(rtp_stream->rtcp_tx_timer);
+               }
+               if(rtp_stream->rtcp_rx_timer) {
+                       mpf_timer_kill(rtp_stream->rtcp_rx_timer);
+               }
+               if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy != RTCP_BYE_DISABLE) {
+                       apt_str_t reason = {RTCP_BYE_SESSION_ENDED, sizeof(RTCP_BYE_SESSION_ENDED)-1};
+                       mpf_rtcp_bye_send(rtp_stream,&reason);
+               }
+       }
+       
+       mpf_rtp_socket_pair_close(rtp_stream);
        return TRUE;
 }
 
@@ -235,11 +395,11 @@ MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rt
 
        if(!rtp_stream->local_media) {
                /* create local media */
-               status = mpf_rtp_stream_local_media_create(rtp_stream,descriptor->local,descriptor->remote);
+               status = mpf_rtp_stream_local_media_create(rtp_stream,descriptor->local,descriptor->remote,descriptor->capabilities);
        }
        else if(descriptor->local) {
                /* update local media */
-               status = mpf_rtp_stream_local_media_update(rtp_stream,descriptor->local);
+               status = mpf_rtp_stream_local_media_update(rtp_stream,descriptor->local,descriptor->capabilities);
        }
        
        if(descriptor->remote && status == TRUE) {
@@ -250,21 +410,23 @@ MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rt
                mpf_rtp_stream_media_negotiate(rtp_stream);
        }
 
-       if((rtp_stream->base->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
-               rtp_stream->base->tx_codec = mpf_codec_manager_codec_get(
-                                                               rtp_stream->base->termination->codec_manager,
-                                                               rtp_stream->remote_media->codec_list.preffered,
-                                                               rtp_stream->pool);
-               if(rtp_stream->base->tx_codec) {
+       if((rtp_stream->base->direction & STREAM_DIRECTION_SEND) == STREAM_DIRECTION_SEND) {
+               mpf_codec_list_t *codec_list = &rtp_stream->remote_media->codec_list;
+               rtp_stream->base->tx_descriptor = codec_list->primary_descriptor;
+               if(rtp_stream->base->tx_descriptor) {
                        rtp_stream->transmitter.samples_per_frame = 
-                               (apr_uint32_t)mpf_codec_frame_samples_calculate(rtp_stream->base->tx_codec->descriptor);
+                               (apr_uint32_t)mpf_codec_frame_samples_calculate(rtp_stream->base->tx_descriptor);
+               }
+               if(codec_list->event_descriptor) {
+                       rtp_stream->base->tx_event_descriptor = codec_list->event_descriptor;
                }
        }
-       if((rtp_stream->base->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE) {
-               rtp_stream->base->rx_codec = mpf_codec_manager_codec_get(
-                                                               rtp_stream->base->termination->codec_manager,
-                                                               rtp_stream->local_media->codec_list.preffered,
-                                                               rtp_stream->pool);
+       if((rtp_stream->base->direction & STREAM_DIRECTION_RECEIVE) == STREAM_DIRECTION_RECEIVE) {
+               mpf_codec_list_t *codec_list = &rtp_stream->local_media->codec_list;
+               rtp_stream->base->rx_descriptor = codec_list->primary_descriptor;
+               if(codec_list->event_descriptor) {
+                       rtp_stream->base->rx_event_descriptor = codec_list->event_descriptor;
+               }
        }
 
        if(!descriptor->local) {
@@ -273,35 +435,31 @@ MPF_DECLARE(apt_bool_t) mpf_rtp_stream_modify(mpf_audio_stream_t *stream, mpf_rt
        return status;
 }
 
+
 static apt_bool_t mpf_rtp_stream_destroy(mpf_audio_stream_t *stream)
 {
-       mpf_rtp_stream_t *rtp_stream = stream->obj;
-       if(rtp_stream->socket) {
-               apr_socket_close(rtp_stream->socket);
-               rtp_stream->socket = NULL;
-       }
-       
        return TRUE;
 }
 
-static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_rtp_rx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        mpf_rtp_stream_t *rtp_stream = stream->obj;
        rtp_receiver_t *receiver = &rtp_stream->receiver;
-       if(!rtp_stream->socket || !rtp_stream->local_media) {
+       if(!rtp_stream->rtp_socket || !rtp_stream->rtp_l_sockaddr || !rtp_stream->rtp_r_sockaddr) {
                return FALSE;
        }
 
        receiver->jb = mpf_jitter_buffer_create(
                                                &rtp_stream->config->jb_config,
-                                               stream->rx_codec,
+                                               stream->rx_descriptor,
+                                               codec,
                                                rtp_stream->pool);
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Receive %s:%hu <- %s:%hu playout [%d ms]",
-                       rtp_stream->local_media->base.ip.buf,
-                       rtp_stream->local_media->base.port,
-                       rtp_stream->remote_media->base.ip.buf,
-                       rtp_stream->remote_media->base.port,
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Receiver %s:%hu <- %s:%hu playout [%d ms]",
+                       rtp_stream->rtp_l_sockaddr->hostname,
+                       rtp_stream->rtp_l_sockaddr->port,
+                       rtp_stream->rtp_r_sockaddr->hostname,
+                       rtp_stream->rtp_r_sockaddr->port,
                        rtp_stream->config->jb_config.initial_playout_delay);
        return TRUE;
 }
@@ -310,6 +468,11 @@ static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream)
 {
        mpf_rtp_stream_t *rtp_stream = stream->obj;
        rtp_receiver_t *receiver = &rtp_stream->receiver;
+
+       if(!rtp_stream->rtp_l_sockaddr || !rtp_stream->rtp_r_sockaddr) {
+               return FALSE;
+       }
+
        receiver->stat.lost_packets = 0;
        if(receiver->stat.received_packets) {
                apr_uint32_t expected_packets = receiver->history.seq_cycles + 
@@ -320,14 +483,14 @@ static apt_bool_t mpf_rtp_rx_stream_close(mpf_audio_stream_t *stream)
        }
 
        mpf_jitter_buffer_destroy(receiver->jb);
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Receive %s:%hu <- %s:%hu [r:%lu l:%lu j:%lu]",
-                       rtp_stream->local_media->base.ip.buf,
-                       rtp_stream->local_media->base.port,
-                       rtp_stream->remote_media->base.ip.buf,
-                       rtp_stream->remote_media->base.port,
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Receiver %s:%hu <- %s:%hu [r:%lu l:%lu j:%lu]",
+                       rtp_stream->rtp_l_sockaddr->hostname,
+                       rtp_stream->rtp_l_sockaddr->port,
+                       rtp_stream->rtp_r_sockaddr->hostname,
+                       rtp_stream->rtp_r_sockaddr->port,
                        receiver->stat.received_packets,
                        receiver->stat.lost_packets,
-                       receiver->stat.jitter);
+                       receiver->rr_stat.jitter);
        return TRUE;
 }
 
@@ -341,7 +504,7 @@ static APR_INLINE void rtp_rx_overall_stat_reset(rtp_receiver_t *receiver)
 
 static APR_INLINE void rtp_rx_stat_init(rtp_receiver_t *receiver, rtp_header_t *header, apr_time_t *time)
 {
-       receiver->stat.ssrc = header->ssrc;
+       receiver->rr_stat.ssrc = header->ssrc;
        receiver->history.seq_num_base = receiver->history.seq_num_max = (apr_uint16_t)header->sequence;
        receiver->history.ts_last = header->timestamp;
        receiver->history.time_last = *time;
@@ -385,6 +548,54 @@ static rtp_header_t* rtp_rx_header_skip(void **buffer, apr_size_t *size)
        return header;
 }
 
+static APR_INLINE void rtp_periodic_history_update(rtp_receiver_t *receiver)
+{
+       apr_uint32_t expected_packets;
+       apr_uint32_t expected_interval;
+       apr_uint32_t received_interval;
+       apr_uint32_t lost_interval;
+
+       /* calculate expected packets */
+       expected_packets = receiver->history.seq_cycles + 
+               receiver->history.seq_num_max - receiver->history.seq_num_base + 1;
+
+       /* calculate expected interval */
+       expected_interval = expected_packets - receiver->periodic_history.expected_prior;
+       /* update expected prior */
+       receiver->periodic_history.expected_prior = expected_packets;
+
+       /* calculate received interval */
+       received_interval = receiver->stat.received_packets - receiver->periodic_history.received_prior;
+       /* update received prior */
+       receiver->periodic_history.received_prior = receiver->stat.received_packets;
+       /* calculate lost interval */
+       if(expected_interval > received_interval) {
+               lost_interval = expected_interval - received_interval;
+       }
+       else {
+               lost_interval = 0;
+       }
+
+       /* update lost fraction */
+       if(expected_interval == 0 || lost_interval == 0) {
+               receiver->rr_stat.fraction = 0;
+       }
+       else {
+               receiver->rr_stat.fraction = (lost_interval << 8) / expected_interval;
+       }
+
+       if(expected_packets > receiver->stat.received_packets) {
+               receiver->rr_stat.lost = expected_packets - receiver->stat.received_packets;
+       }
+       else {
+               receiver->rr_stat.lost = 0;
+       }
+
+       receiver->periodic_history.discarded_prior = receiver->stat.discarded_packets;
+       receiver->periodic_history.jitter_min = receiver->rr_stat.jitter;
+       receiver->periodic_history.jitter_max = receiver->rr_stat.jitter;
+}
+
 typedef enum {
        RTP_SSRC_UPDATE,
        RTP_SSRC_PROBATION,
@@ -393,7 +604,7 @@ typedef enum {
 
 static APR_INLINE rtp_ssrc_result_e rtp_rx_ssrc_update(rtp_receiver_t *receiver, apr_uint32_t ssrc)
 {
-       if(receiver->stat.ssrc == ssrc) {
+       if(receiver->rr_stat.ssrc == ssrc) {
                /* known ssrc */
                if(receiver->history.ssrc_probation) {
                        /* reset the probation for new ssrc */
@@ -405,7 +616,7 @@ static APR_INLINE rtp_ssrc_result_e rtp_rx_ssrc_update(rtp_receiver_t *receiver,
                if(receiver->history.ssrc_new == ssrc) {
                        if(--receiver->history.ssrc_probation == 0) {
                                /* restart with new ssrc */
-                               receiver->stat.ssrc = ssrc;
+                               receiver->rr_stat.ssrc = ssrc;
                                return RTP_SSRC_RESTART;
                        }
                        else {
@@ -449,12 +660,6 @@ static APR_INLINE rtp_seq_result_e rtp_rx_seq_update(rtp_receiver_t *receiver, a
        }
        receiver->stat.received_packets++;
 
-       if(receiver->stat.received_packets - receiver->periodic_history.received_prior >= 50) {
-               receiver->periodic_history.received_prior = receiver->stat.received_packets;
-               receiver->periodic_history.discarded_prior = receiver->stat.discarded_packets;
-               receiver->periodic_history.jitter_min = receiver->stat.jitter;
-               receiver->periodic_history.jitter_max = receiver->stat.jitter;
-       }
        return result;
 }
 
@@ -481,18 +686,16 @@ static APR_INLINE rtp_ts_result_e rtp_rx_ts_update(rtp_receiver_t *receiver, mpf
                return RTP_TS_DRIFT;
        }
 
-       receiver->stat.jitter += deviation - ((receiver->stat.jitter + 8) >> 4);
-#if PRINT_RTP_PACKET_STAT
-       printf("jitter=%d deviation=%d\n",receiver->stat.jitter,deviation);
-#endif
+       receiver->rr_stat.jitter += deviation - ((receiver->rr_stat.jitter + 8) >> 4);
+       RTP_TRACE("jitter=%d deviation=%d\n",receiver->rr_stat.jitter,deviation);
        receiver->history.time_last = *time;
        receiver->history.ts_last = ts;
 
-       if(receiver->stat.jitter < receiver->periodic_history.jitter_min) {
-               receiver->periodic_history.jitter_min = receiver->stat.jitter;
+       if(receiver->rr_stat.jitter < receiver->periodic_history.jitter_min) {
+               receiver->periodic_history.jitter_min = receiver->rr_stat.jitter;
        }
-       if(receiver->stat.jitter > receiver->periodic_history.jitter_max) {
-               receiver->periodic_history.jitter_max = receiver->stat.jitter;
+       if(receiver->rr_stat.jitter > receiver->periodic_history.jitter_max) {
+               receiver->periodic_history.jitter_max = receiver->rr_stat.jitter;
        }
        return RTP_TS_UPDATE;
 }
@@ -510,8 +713,10 @@ static APR_INLINE void rtp_rx_failure_threshold_check(rtp_receiver_t *receiver)
        }
 }
 
-static apt_bool_t rtp_rx_packet_receive(rtp_receiver_t *receiver, mpf_codec_t *codec, void *buffer, apr_size_t size)
+static apt_bool_t rtp_rx_packet_receive(mpf_rtp_stream_t *rtp_stream, void *buffer, apr_size_t size)
 {
+       rtp_receiver_t *receiver = &rtp_stream->receiver;
+       mpf_codec_descriptor_t *descriptor = rtp_stream->base->rx_descriptor;
        apr_time_t time;
        rtp_ssrc_result_e ssrc_result;
        rtp_header_t *header = rtp_rx_header_skip(&buffer,&size);
@@ -527,12 +732,10 @@ static apt_bool_t rtp_rx_packet_receive(rtp_receiver_t *receiver, mpf_codec_t *c
 
        time = apr_time_now();
 
-#if PRINT_RTP_PACKET_STAT
-       printf("RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u size=%lu\n",
+       RTP_TRACE("RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u size=%lu\n",
                                        (apr_uint32_t)apr_time_usec(time),
-                                       header->ssrc, header->type, header->marker ? '*' : ' ',
+                                       header->ssrc, header->type, (header->marker == 1) ? '*' : ' ',
                                        header->timestamp, header->sequence, size);
-#endif
        if(!receiver->stat.received_packets) {
                /* initialization */
                rtp_rx_stat_init(receiver,header,&time);
@@ -550,28 +753,29 @@ static apt_bool_t rtp_rx_packet_receive(rtp_receiver_t *receiver, mpf_codec_t *c
 
        rtp_rx_seq_update(receiver,(apr_uint16_t)header->sequence);
        
-       if(rtp_rx_ts_update(receiver,codec->descriptor,&time,header->timestamp) == RTP_TS_DRIFT) {
-               rtp_rx_restart(receiver);
-               return FALSE;
-       }
-       
-       if(header->type == codec->descriptor->payload_type) {
+       if(header->type == descriptor->payload_type) {
                /* codec */
-               if(mpf_jitter_buffer_write(receiver->jb,codec,buffer,size,header->timestamp) != JB_OK) {
+               if(rtp_rx_ts_update(receiver,descriptor,&time,header->timestamp) == RTP_TS_DRIFT) {
+                       rtp_rx_restart(receiver);
+                       return FALSE;
+               }
+       
+               if(mpf_jitter_buffer_write(receiver->jb,buffer,size,header->timestamp) != JB_OK) {
                        receiver->stat.discarded_packets++;
                        rtp_rx_failure_threshold_check(receiver);
                }
        }
-       else if(header->type == receiver->event_pt && receiver->event_pt != 0) {
+       else if(rtp_stream->base->rx_event_descriptor && 
+               header->type == rtp_stream->base->rx_event_descriptor->payload_type) {
                /* named event */
                mpf_named_event_frame_t *named_event = (mpf_named_event_frame_t *)buffer;
-               if(mpf_jitter_buffer_write_named_event(receiver->jb,named_event,header->timestamp) != JB_OK) {
+               named_event->duration = ntohs((apr_uint16_t)named_event->duration);
+               if(mpf_jitter_buffer_event_write(receiver->jb,named_event,header->timestamp,(apr_byte_t)header->marker) != JB_OK) {
                        receiver->stat.discarded_packets++;
-                       rtp_rx_failure_threshold_check(receiver);
                }
        }
-       else if(header->type == 13 || header->type == 19) {
-               /* CN packet*/
+       else if(header->type == RTP_PT_CN) {
+               /* CN packet */
                receiver->stat.ignored_packets++;
        }
        else {
@@ -584,11 +788,11 @@ static apt_bool_t rtp_rx_packet_receive(rtp_receiver_t *receiver, mpf_codec_t *c
 
 static apt_bool_t rtp_rx_process(mpf_rtp_stream_t *rtp_stream)
 {
-       char buffer[1500];
+       char buffer[MAX_RTP_PACKET_SIZE];
        apr_size_t size = sizeof(buffer);
        apr_size_t max_count = 5;
-       while(max_count && apr_socket_recvfrom(rtp_stream->remote_sockaddr,rtp_stream->socket,0,buffer,&size) == APR_SUCCESS) {
-               rtp_rx_packet_receive(&rtp_stream->receiver,rtp_stream->base->rx_codec,buffer,size);
+       while(max_count && apr_socket_recv(rtp_stream->rtp_socket,buffer,&size) == APR_SUCCESS) {
+               rtp_rx_packet_receive(rtp_stream,buffer,size);
 
                size = sizeof(buffer);
                max_count--;
@@ -605,15 +809,17 @@ static apt_bool_t mpf_rtp_stream_receive(mpf_audio_stream_t *stream, mpf_frame_t
 }
 
 
-
-
-
-static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        apr_size_t frame_size;
        mpf_rtp_stream_t *rtp_stream = stream->obj;
        rtp_transmitter_t *transmitter = &rtp_stream->transmitter;
-       if(!rtp_stream->socket || !rtp_stream->remote_media) {
+
+       if(!rtp_stream->rtp_socket || !rtp_stream->rtp_l_sockaddr || !rtp_stream->rtp_r_sockaddr) {
+               return FALSE;
+       }
+
+       if(!codec) {
                return FALSE;
        }
 
@@ -629,59 +835,128 @@ static apt_bool_t mpf_rtp_tx_stream_open(mpf_audio_stream_t *stream)
        transmitter->current_frames = 0;
 
        frame_size = mpf_codec_frame_size_calculate(
-                                                       stream->tx_codec->descriptor,
-                                                       stream->tx_codec->attribs);
+                                                       stream->tx_descriptor,
+                                                       codec->attribs);
        transmitter->packet_data = apr_palloc(
                                                        rtp_stream->pool,
                                                        sizeof(rtp_header_t) + transmitter->packet_frames * frame_size);
        
        transmitter->inactivity = 1;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Transmit %s:%hu -> %s:%hu",
-                       rtp_stream->local_media->base.ip.buf,
-                       rtp_stream->local_media->base.port,
-                       rtp_stream->remote_media->base.ip.buf,
-                       rtp_stream->remote_media->base.port);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open RTP Transmitter %s:%hu -> %s:%hu",
+                       rtp_stream->rtp_l_sockaddr->hostname,
+                       rtp_stream->rtp_l_sockaddr->port,
+                       rtp_stream->rtp_r_sockaddr->hostname,
+                       rtp_stream->rtp_r_sockaddr->port);
        return TRUE;
 }
 
 static apt_bool_t mpf_rtp_tx_stream_close(mpf_audio_stream_t *stream)
 {
        mpf_rtp_stream_t *rtp_stream = stream->obj;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Transmit %s:%hu -> %s:%hu [s:%lu]",
-                       rtp_stream->local_media->base.ip.buf,
-                       rtp_stream->local_media->base.port,
-                       rtp_stream->remote_media->base.ip.buf,
-                       rtp_stream->remote_media->base.port,
-                       rtp_stream->transmitter.stat.sent_packets);
+       if(!rtp_stream->rtp_l_sockaddr || !rtp_stream->rtp_r_sockaddr) {
+               return FALSE;
+       }
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close RTP Transmitter %s:%hu -> %s:%hu [s:%lu o:%lu]",
+                       rtp_stream->rtp_l_sockaddr->hostname,
+                       rtp_stream->rtp_l_sockaddr->port,
+                       rtp_stream->rtp_l_sockaddr->hostname,
+                       rtp_stream->rtp_r_sockaddr->port,
+                       rtp_stream->transmitter.sr_stat.sent_packets,
+                       rtp_stream->transmitter.sr_stat.sent_octets);
        return TRUE;
 }
 
 
-static APR_INLINE void rtp_header_prepare(rtp_transmitter_t *transmitter, apr_byte_t payload_type)
+static APR_INLINE void rtp_header_prepare(
+                                       rtp_transmitter_t *transmitter,
+                                       rtp_header_t *header,
+                                       apr_byte_t payload_type,
+                                       apr_byte_t marker,
+                                       apr_uint32_t timestamp)
 {
-       rtp_header_t *header = (rtp_header_t*)transmitter->packet_data;
-
-#if PRINT_RTP_PACKET_STAT
-       printf("> RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u\n",
-               (apr_uint32_t)apr_time_usec(apr_time_now()),
-               transmitter->ssrc, payload_type, transmitter->inactivity ? '*' : ' ',
-               transmitter->timestamp, transmitter->last_seq_num);
-#endif 
        header->version = RTP_VERSION;
        header->padding = 0;
        header->extension = 0;
        header->count = 0;
-       header->marker = transmitter->inactivity;
+       header->marker = marker;
        header->type = payload_type;
-       header->sequence = htons(++transmitter->last_seq_num);
-       header->timestamp = htonl(transmitter->timestamp);
-       header->ssrc = htonl(transmitter->ssrc);
+       header->timestamp = timestamp;
+       header->ssrc = htonl(transmitter->sr_stat.ssrc);
+}
 
-       if(transmitter->inactivity) {
-               transmitter->inactivity = 0;
+static APR_INLINE apt_bool_t mpf_rtp_data_send(mpf_rtp_stream_t *rtp_stream, rtp_transmitter_t *transmitter, const mpf_frame_t *frame)
+{
+       apt_bool_t status = TRUE;
+       memcpy(
+               transmitter->packet_data + transmitter->packet_size,
+               frame->codec_frame.buffer,
+               frame->codec_frame.size);
+       transmitter->packet_size += frame->codec_frame.size;
+
+       if(++transmitter->current_frames == transmitter->packet_frames) {
+               rtp_header_t *header = (rtp_header_t*)transmitter->packet_data;
+               header->sequence = htons(++transmitter->last_seq_num);
+               RTP_TRACE("> RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u\n",
+                       (apr_uint32_t)apr_time_usec(apr_time_now()),
+                       transmitter->sr_stat.ssrc, header->type, 
+                       (header->marker == 1) ? '*' : ' ',
+                       header->timestamp, transmitter->last_seq_num);
+               header->timestamp = htonl(header->timestamp);
+               if(apr_socket_sendto(
+                                       rtp_stream->rtp_socket,
+                                       rtp_stream->rtp_r_sockaddr,
+                                       0,
+                                       transmitter->packet_data,
+                                       &transmitter->packet_size) == APR_SUCCESS) {
+                       transmitter->sr_stat.sent_packets++;
+                       transmitter->sr_stat.sent_octets += transmitter->packet_size - sizeof(rtp_header_t);
+               }
+               else {
+                       status = FALSE;
+               }
+               transmitter->current_frames = 0;
        }
+       return status;
+}
 
-       transmitter->packet_size = sizeof(rtp_header_t);
+static APR_INLINE apt_bool_t mpf_rtp_event_send(mpf_rtp_stream_t *rtp_stream, rtp_transmitter_t *transmitter, const mpf_frame_t *frame)
+{
+       char packet_data[20];
+       apr_size_t packet_size = sizeof(rtp_header_t) + sizeof(mpf_named_event_frame_t);
+       rtp_header_t *header = (rtp_header_t*) packet_data;
+       mpf_named_event_frame_t *named_event = (mpf_named_event_frame_t*)(header+1);
+       rtp_header_prepare(
+               transmitter,
+               header,
+               rtp_stream->base->tx_event_descriptor->payload_type,
+               (frame->marker == MPF_MARKER_START_OF_EVENT) ? 1 : 0,
+               transmitter->timestamp_base);
+
+       *named_event = frame->event_frame;
+       named_event->edge = (frame->marker == MPF_MARKER_END_OF_EVENT) ? 1 : 0;
+       
+       header->sequence = htons(++transmitter->last_seq_num);
+       RTP_TRACE("> RTP time=%6lu ssrc=%8lx pt=%3u %cts=%9lu seq=%5u event=%2u dur=%3u %c\n",
+               (apr_uint32_t)apr_time_usec(apr_time_now()),
+               transmitter->sr_stat.ssrc, 
+               header->type, (header->marker == 1) ? '*' : ' ',
+               header->timestamp, transmitter->last_seq_num,
+               named_event->event_id, named_event->duration,
+               (named_event->edge == 1) ? '*' : ' ');
+
+       header->timestamp = htonl(header->timestamp);
+       named_event->duration = htons((apr_uint16_t)named_event->duration);
+       if(apr_socket_sendto(
+                               rtp_stream->rtp_socket,
+                               rtp_stream->rtp_r_sockaddr,
+                               0,
+                               packet_data,
+                               &packet_size) != APR_SUCCESS) {
+               return FALSE;
+       }
+       transmitter->sr_stat.sent_packets++;
+       transmitter->sr_stat.sent_octets += sizeof(mpf_named_event_frame_t);
+       return TRUE;
 }
 
 static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
@@ -692,80 +967,433 @@ static apt_bool_t mpf_rtp_stream_transmit(mpf_audio_stream_t *stream, const mpf_
 
        transmitter->timestamp += transmitter->samples_per_frame;
 
-       if(transmitter->current_frames == 0) {
-               if(frame->type == MEDIA_FRAME_TYPE_NONE) {
-                       transmitter->inactivity = 1;
-               }
-               else {
-                       rtp_header_prepare(transmitter,stream->tx_codec->descriptor->payload_type);
+       if(frame->type == MEDIA_FRAME_TYPE_NONE) {
+               if(!transmitter->inactivity) {
+                       if(transmitter->current_frames == 0) {
+                               /* set inactivity (ptime alligned) */
+                               transmitter->inactivity = 1;
+                               if(rtp_stream->config->rtcp == TRUE && rtp_stream->config->rtcp_bye_policy == RTCP_BYE_PER_TALKSPURT) {
+                                       apt_str_t reason = {RTCP_BYE_TALKSPURT_ENDED, sizeof(RTCP_BYE_TALKSPURT_ENDED)-1};
+                                       mpf_rtcp_bye_send(rtp_stream,&reason);
+                               }
+                       }
+                       else {
+                               /* ptime allignment */
+                               status = mpf_rtp_data_send(rtp_stream,transmitter,frame);
+                       }
                }
+               return status;
        }
-       
-       if(!transmitter->inactivity) {
-               memcpy(
-                       transmitter->packet_data + transmitter->packet_size,
-                       frame->codec_frame.buffer,
-                       frame->codec_frame.size);
-               transmitter->packet_size += frame->codec_frame.size;
-
-               if(++transmitter->current_frames == transmitter->packet_frames) {
-                       if(apr_socket_sendto(
-                                                               rtp_stream->socket,
-                                                               rtp_stream->remote_sockaddr,
-                                                               0,
-                                                               transmitter->packet_data,
-                                                               &transmitter->packet_size) == APR_SUCCESS) {
-                               transmitter->stat.sent_packets++;
+
+       if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT){
+               /* transmit event as soon as received */
+               if(stream->tx_event_descriptor) {
+                       if(frame->marker == MPF_MARKER_START_OF_EVENT) {
+                               /* store start time (base) of the event */
+                               transmitter->timestamp_base = transmitter->timestamp;
                        }
-                       else {
-                               status = FALSE;
+                       else if(frame->marker == MPF_MARKER_NEW_SEGMENT) {
+                               /* update base in case of long-lasting events */
+                               transmitter->timestamp_base = transmitter->timestamp;
+                       }
+
+                       status = mpf_rtp_event_send(rtp_stream,transmitter,frame);
+               }
+       }
+
+       if((frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO){
+               if(transmitter->current_frames == 0) {
+                       rtp_header_t *header = (rtp_header_t*)transmitter->packet_data;
+                       rtp_header_prepare(
+                                       transmitter,
+                                       header,
+                                       stream->tx_descriptor->payload_type,
+                                       transmitter->inactivity,
+                                       transmitter->timestamp);
+                       transmitter->packet_size = sizeof(rtp_header_t);
+                       if(transmitter->inactivity) {
+                               transmitter->inactivity = 0;
                        }
-                       transmitter->current_frames = 0;
                }
+               status = mpf_rtp_data_send(rtp_stream,transmitter,frame);
        }
 
        return status;
 }
 
-static apt_bool_t mpf_rtp_socket_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media)
+static apr_socket_t* mpf_socket_create(apr_sockaddr_t **l_sockaddr, const char *ip, apr_port_t port, apr_pool_t *pool)
 {
-       if(stream->socket) {
-               apr_socket_close(stream->socket);
-               stream->socket = NULL;
-       }
-       
-       stream->local_sockaddr = NULL;
+       apr_socket_t *socket = NULL;
+       *l_sockaddr = NULL;
        apr_sockaddr_info_get(
-               &stream->local_sockaddr,
-               local_media->base.ip.buf,
+               l_sockaddr,
+               ip,
                APR_INET,
-               local_media->base.port,
+               port,
                0,
-               stream->pool);
-       if(!stream->local_sockaddr) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Get Sockaddr %s:%hu",
-                               local_media->base.ip.buf,
-                               local_media->base.port);
+               pool);
+       if(!*l_sockaddr) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get Sockaddr %s:%hu",ip,port);
+               return NULL;
+       }
+       if(apr_socket_create(&socket,(*l_sockaddr)->family,SOCK_DGRAM,0,pool) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Socket %s:%hu", ip,port);
+               return NULL;
+       }
+       
+       apr_socket_opt_set(socket,APR_SO_NONBLOCK,1);
+       apr_socket_timeout_set(socket,0);
+       apr_socket_opt_set(socket,APR_SO_REUSEADDR,1);
+
+       if(apr_socket_bind(socket,*l_sockaddr) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Bind Socket to %s:%hu", ip,port);
+               apr_socket_close(socket);
+               return NULL;
+       }
+       return socket;
+}
+
+static apt_bool_t mpf_rtp_socket_pair_create(mpf_rtp_stream_t *stream, mpf_rtp_media_descriptor_t *local_media)
+{
+       stream->rtp_socket = mpf_socket_create(&stream->rtp_l_sockaddr,local_media->ip.buf,local_media->port,stream->pool);
+       if(!stream->rtp_socket) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create RTP Socket");
                return FALSE;
        }
-       if(apr_socket_create(&stream->socket,stream->local_sockaddr->family,SOCK_DGRAM,0,stream->pool) != APR_SUCCESS) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Create Socket %s:%hu",
-                               local_media->base.ip.buf,
-                               local_media->base.port);
+
+       stream->rtcp_socket = mpf_socket_create(&stream->rtcp_l_sockaddr,local_media->ip.buf,local_media->port+1,stream->pool);
+       if(!stream->rtcp_socket) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create RTCP Socket");
+       }
+       return TRUE;
+}
+
+static void mpf_rtp_socket_pair_close(mpf_rtp_stream_t *stream)
+{
+       if(stream->rtp_socket) {
+               apr_socket_close(stream->rtp_socket);
+               stream->rtp_socket = NULL;
+       }
+       if(stream->rtcp_socket) {
+               apr_socket_close(stream->rtcp_socket);
+               stream->rtcp_socket = NULL;
+       }
+}
+
+
+
+static APR_INLINE void rtcp_sr_generate(mpf_rtp_stream_t *rtp_stream, rtcp_sr_stat_t *sr_stat)
+{
+       *sr_stat = rtp_stream->transmitter.sr_stat;
+       apt_ntp_time_get(&sr_stat->ntp_sec, &sr_stat->ntp_frac);
+       sr_stat->rtp_ts = rtp_stream->transmitter.timestamp;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP SR [ssrc:%lu s:%lu o:%lu ts:%lu]",
+                               sr_stat->ssrc,
+                               sr_stat->sent_packets,
+                               sr_stat->sent_octets,
+                               sr_stat->rtp_ts);
+       rtcp_sr_hton(sr_stat);
+}
+
+static APR_INLINE void rtcp_rr_generate(mpf_rtp_stream_t *rtp_stream, rtcp_rr_stat_t *rr_stat)
+{
+       *rr_stat = rtp_stream->receiver.rr_stat;
+       rr_stat->last_seq =     rtp_stream->receiver.history.seq_num_max;
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Generate RTCP RR [ssrc:%lu last_seq:%lu j:%lu lost:%lu frac:%d]",
+                               rr_stat->ssrc,
+                               rr_stat->last_seq,
+                               rr_stat->jitter,
+                               rr_stat->lost,
+                               rr_stat->fraction);
+       rtcp_rr_hton(rr_stat);
+}
+
+/* Generate either RTCP SR or RTCP RR packet */
+static APR_INLINE apr_size_t rtcp_report_generate(mpf_rtp_stream_t *rtp_stream, rtcp_packet_t *rtcp_packet, apr_size_t length)
+{
+       apr_size_t offset = 0;
+       rtcp_header_init(&rtcp_packet->header,RTCP_RR);
+       if(rtp_stream->base->direction & STREAM_DIRECTION_SEND) {
+               rtcp_packet->header.pt = RTCP_SR;
+       }
+       if(rtp_stream->base->direction & STREAM_DIRECTION_RECEIVE) {
+               rtcp_packet->header.count = 1;
+       }
+       offset += sizeof(rtcp_header_t);
+
+       if(rtcp_packet->header.pt == RTCP_SR) {
+               rtcp_sr_generate(rtp_stream,&rtcp_packet->r.sr.sr_stat);
+               offset += sizeof(rtcp_sr_stat_t);
+               if(rtcp_packet->header.count) {
+                       rtcp_rr_generate(rtp_stream,rtcp_packet->r.sr.rr_stat);
+                       offset += sizeof(rtcp_rr_stat_t);
+               }
+       }
+       else if(rtcp_packet->header.pt == RTCP_RR) {
+               rtcp_packet->r.rr.ssrc = htonl(rtp_stream->transmitter.sr_stat.ssrc);
+               rtcp_rr_generate(rtp_stream,rtcp_packet->r.rr.rr_stat);
+               offset += sizeof(rtcp_packet->r.rr);
+       }
+       rtcp_header_length_set(&rtcp_packet->header,offset);
+       return offset;
+}
+
+/* Generate RTCP SDES packet */
+static APR_INLINE apr_size_t rtcp_sdes_generate(mpf_rtp_stream_t *rtp_stream, rtcp_packet_t *rtcp_packet, apr_size_t length)
+{
+       rtcp_sdes_item_t *item;
+       apr_size_t offset = 0;
+       apr_size_t padding;
+       rtcp_header_init(&rtcp_packet->header,RTCP_SDES);
+       offset += sizeof(rtcp_header_t);
+
+       rtcp_packet->header.count ++;
+       rtcp_packet->r.sdes.ssrc = htonl(rtp_stream->transmitter.sr_stat.ssrc);
+       offset += sizeof(apr_uint32_t);
+
+       /* insert SDES CNAME item */
+       item = &rtcp_packet->r.sdes.item[0];
+       item->type = RTCP_SDES_CNAME;
+       item->length = (apr_byte_t)rtp_stream->local_media->ip.length;
+       memcpy(item->data,rtp_stream->local_media->ip.buf,item->length);
+       offset += sizeof(rtcp_sdes_item_t) - 1 + item->length;
+       
+       /* terminate with end marker and pad to next 4-octet boundary */
+       padding = 4 - (offset & 0x3);
+       while(padding--) {
+               item = (rtcp_sdes_item_t*) ((char*)rtcp_packet + offset);
+               item->type = RTCP_SDES_END;
+               offset++;
+       }
+
+       rtcp_header_length_set(&rtcp_packet->header,offset);
+       return offset;
+}
+
+/* Generate RTCP BYE packet */
+static APR_INLINE apr_size_t rtcp_bye_generate(mpf_rtp_stream_t *rtp_stream, rtcp_packet_t *rtcp_packet, apr_size_t length, apt_str_t *reason)
+{
+       apr_size_t offset = 0;
+       rtcp_header_init(&rtcp_packet->header,RTCP_BYE);
+       offset += sizeof(rtcp_header_t);
+
+       rtcp_packet->r.bye.ssrc[0] = htonl(rtp_stream->transmitter.sr_stat.ssrc);
+       rtcp_packet->header.count++;
+       offset += rtcp_packet->header.count * sizeof(apr_uint32_t);
+
+       if(reason->length) {
+               apr_size_t padding;
+
+               memcpy(rtcp_packet->r.bye.data,reason->buf,reason->length);
+               rtcp_packet->r.bye.length = (apr_byte_t)reason->length;
+               offset += rtcp_packet->r.bye.length;
+       
+               /* terminate with end marker and pad to next 4-octet boundary */
+               padding = 4 - (reason->length & 0x3);
+               if(padding) {
+                       char *end = rtcp_packet->r.bye.data + reason->length;
+                       memset(end,0,padding);
+                       offset += padding;
+               }
+       }
+
+       rtcp_header_length_set(&rtcp_packet->header,offset);
+       return offset;
+}
+
+/* Send compound RTCP packet (SR/RR + SDES) */
+static apt_bool_t mpf_rtcp_report_send(mpf_rtp_stream_t *rtp_stream)
+{
+       char buffer[MAX_RTCP_PACKET_SIZE];
+       apr_size_t length = 0;
+       rtcp_packet_t *rtcp_packet;
+
+       if(!rtp_stream->rtcp_socket || !rtp_stream->rtcp_l_sockaddr || !rtp_stream->rtcp_r_sockaddr) {
+               /* session is not initialized */
                return FALSE;
        }
+
+       if(rtp_stream->base->direction != STREAM_DIRECTION_NONE) {
+               /* update periodic (prior) history */
+               rtp_periodic_history_update(&rtp_stream->receiver);
+       }
+
+       rtcp_packet = (rtcp_packet_t*) (buffer + length);
+       length += rtcp_report_generate(rtp_stream,rtcp_packet,sizeof(buffer)-length);
+
+       rtcp_packet = (rtcp_packet_t*) (buffer + length);
+       length += rtcp_sdes_generate(rtp_stream,rtcp_packet,sizeof(buffer)-length);
        
-       apr_socket_opt_set(stream->socket,APR_SO_NONBLOCK,1);
-       apr_socket_timeout_set(stream->socket,0);
-       apr_socket_opt_set(stream->socket,APR_SO_REUSEADDR,1);
-
-       if(apr_socket_bind(stream->socket,stream->local_sockaddr) != APR_SUCCESS) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Failed to Bind Socket to %s:%hu",
-                               local_media->base.ip.buf,
-                               local_media->base.port);
-               apr_socket_close(stream->socket);
-               stream->socket = NULL;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Compound RTCP Packet [%d bytes] %s:%hu -> %s:%hu",
+               length,
+               rtp_stream->rtcp_l_sockaddr->hostname,
+               rtp_stream->rtcp_l_sockaddr->port,
+               rtp_stream->rtcp_r_sockaddr->hostname,
+               rtp_stream->rtcp_r_sockaddr->port);
+       if(apr_socket_sendto(
+                               rtp_stream->rtcp_socket,
+                               rtp_stream->rtcp_r_sockaddr,
+                               0,
+                               buffer,
+                               &length) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send Compound RTCP Packet [%d bytes] %s:%hu -> %s:%hu",
+                       length,
+                       rtp_stream->rtcp_l_sockaddr->hostname,
+                       rtp_stream->rtcp_l_sockaddr->port,
+                       rtp_stream->rtcp_r_sockaddr->hostname,
+                       rtp_stream->rtcp_r_sockaddr->port);
                return FALSE;
        }
        return TRUE;
 }
+
+/* Send compound RTCP packet (SR/RR + SDES + BYE) */
+static apt_bool_t mpf_rtcp_bye_send(mpf_rtp_stream_t *rtp_stream, apt_str_t *reason)
+{
+       char buffer[MAX_RTCP_PACKET_SIZE];
+       apr_size_t length = 0;
+       rtcp_packet_t *rtcp_packet;
+
+       if(!rtp_stream->rtcp_socket || !rtp_stream->rtcp_l_sockaddr || !rtp_stream->rtcp_r_sockaddr) {
+               /* session is not initialized */
+               return FALSE;
+       }
+
+       if(rtp_stream->base->direction != STREAM_DIRECTION_NONE) {
+               /* update periodic (prior) history */
+               rtp_periodic_history_update(&rtp_stream->receiver);
+       }
+
+       rtcp_packet = (rtcp_packet_t*) (buffer + length);
+       length += rtcp_report_generate(rtp_stream,rtcp_packet,sizeof(buffer)-length);
+
+       rtcp_packet = (rtcp_packet_t*) (buffer + length);
+       length += rtcp_sdes_generate(rtp_stream,rtcp_packet,sizeof(buffer)-length);
+
+       rtcp_packet = (rtcp_packet_t*) (buffer + length);
+       length += rtcp_bye_generate(rtp_stream,rtcp_packet,sizeof(buffer)-length,reason);
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Compound RTCP Packet [BYE] [%d bytes] %s:%hu -> %s:%hu",
+               length,
+               rtp_stream->rtcp_l_sockaddr->hostname,
+               rtp_stream->rtcp_l_sockaddr->port,
+               rtp_stream->rtcp_r_sockaddr->hostname,
+               rtp_stream->rtcp_r_sockaddr->port);
+       if(apr_socket_sendto(
+                               rtp_stream->rtcp_socket,
+                               rtp_stream->rtcp_r_sockaddr,
+                               0,
+                               buffer,
+                               &length) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send Compound RTCP Packet [BYE] [%d bytes] %s:%hu -> %s:%hu",
+                       length,
+                       rtp_stream->rtcp_l_sockaddr->hostname,
+                       rtp_stream->rtcp_l_sockaddr->port,
+                       rtp_stream->rtcp_r_sockaddr->hostname,
+                       rtp_stream->rtcp_r_sockaddr->port);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static APR_INLINE void rtcp_sr_get(mpf_rtp_stream_t *rtp_stream, rtcp_sr_stat_t *sr_stat)
+{
+       rtcp_sr_ntoh(sr_stat);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP SR [ssrc:%lu s:%lu o:%lu ts:%lu]",
+                               sr_stat->ssrc,
+                               sr_stat->sent_packets,
+                               sr_stat->sent_octets,
+                               sr_stat->rtp_ts);
+}
+
+static APR_INLINE void rtcp_rr_get(mpf_rtp_stream_t *rtp_stream, rtcp_rr_stat_t *rr_stat)
+{
+       rtcp_rr_ntoh(rr_stat);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Get RTCP RR [ssrc:%lu last_seq:%lu j:%lu lost:%lu frac:%d]",
+                               rr_stat->ssrc,
+                               rr_stat->last_seq,
+                               rr_stat->jitter,
+                               rr_stat->lost,
+                               rr_stat->fraction);
+}
+
+static apt_bool_t mpf_rtcp_compound_packet_receive(mpf_rtp_stream_t *rtp_stream, char *buffer, apr_size_t length)
+{
+       rtcp_packet_t *rtcp_packet = (rtcp_packet_t*) buffer;
+       rtcp_packet_t *rtcp_packet_end;
+
+       rtcp_packet_end = (rtcp_packet_t*)(buffer + length);
+
+       while(rtcp_packet < rtcp_packet_end && rtcp_packet->header.version == RTP_VERSION) {
+               rtcp_packet->header.length = ntohs((apr_uint16_t)rtcp_packet->header.length);
+               
+               if(rtcp_packet->header.pt == RTCP_SR) {
+                       /* RTCP SR */
+                       rtcp_sr_get(rtp_stream,&rtcp_packet->r.sr.sr_stat);
+                       if(rtcp_packet->header.count) {
+                               rtcp_rr_get(rtp_stream,rtcp_packet->r.sr.rr_stat);
+                       }
+               }
+               else if(rtcp_packet->header.pt == RTCP_RR) {
+                       /* RTCP RR */
+                       rtcp_packet->r.rr.ssrc = ntohl(rtcp_packet->r.rr.ssrc);
+                       if(rtcp_packet->header.count) {
+                               rtcp_rr_get(rtp_stream,rtcp_packet->r.rr.rr_stat);
+                       }
+               }
+               else if(rtcp_packet->header.pt == RTCP_SDES) {
+                       /* RTCP SDES */
+               }
+               else if(rtcp_packet->header.pt == RTCP_BYE) {
+                       /* RTCP BYE */
+               }
+               else {
+                       /* unknown RTCP packet */
+               }
+
+               /* get next RTCP packet */
+               rtcp_packet = (rtcp_packet_t*)((apr_uint32_t*)rtcp_packet + rtcp_packet->header.length + 1);
+       }
+
+       if(rtcp_packet != rtcp_packet_end) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Malformed Compound RTCP Packet");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void mpf_rtcp_tx_timer_proc(mpf_timer_t *timer, void *obj)
+{
+       mpf_rtp_stream_t *rtp_stream = obj;
+
+       /* generate and send RTCP compound report (SR/RR + SDES) */
+       mpf_rtcp_report_send(rtp_stream);
+
+       /* re-schedule timer */
+       mpf_timer_set(timer,rtp_stream->config->rtcp_tx_interval);
+}
+
+static void mpf_rtcp_rx_timer_proc(mpf_timer_t *timer, void *obj)
+{
+       mpf_rtp_stream_t *rtp_stream = obj;
+       if(rtp_stream->rtcp_socket && rtp_stream->rtcp_l_sockaddr && rtp_stream->rtcp_r_sockaddr) {
+               char buffer[MAX_RTCP_PACKET_SIZE];
+               apr_size_t length = sizeof(buffer);
+               
+               if(apr_socket_recv(rtp_stream->rtcp_socket,buffer,&length) == APR_SUCCESS) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Compound RTCP Packet [%d bytes] %s:%hu <- %s:%hu",
+                                       length,
+                                       rtp_stream->rtcp_l_sockaddr->hostname,
+                                       rtp_stream->rtcp_l_sockaddr->port,
+                                       rtp_stream->rtcp_r_sockaddr->hostname,
+                                       rtp_stream->rtcp_r_sockaddr->port);
+                       mpf_rtcp_compound_packet_receive(rtp_stream,buffer,length);
+               }
+       }
+
+       /* re-schedule timer */
+       mpf_timer_set(timer,rtp_stream->config->rtcp_rx_resolution);
+}
index 5f5e058f6a635eb0e114fdcbc2d043200b324f2f..0202e2e4988bc23b4e9eb6618a12c60a3cb652ea 100644 (file)
@@ -30,8 +30,9 @@ static apt_bool_t mpf_rtp_termination_destroy(mpf_termination_t *termination)
        return TRUE;
 }
 
-static apt_bool_t mpf_rtp_termination_modify(mpf_termination_t *termination, void *descriptor)
+static apt_bool_t mpf_rtp_termination_add(mpf_termination_t *termination, void *descriptor)
 {
+       apt_bool_t status = TRUE;
        mpf_rtp_termination_descriptor_t *rtp_descriptor = descriptor;
        mpf_audio_stream_t *audio_stream = termination->audio_stream;
        if(!audio_stream) {
@@ -43,12 +44,43 @@ static apt_bool_t mpf_rtp_termination_modify(mpf_termination_t *termination, voi
                termination->audio_stream = audio_stream;
        }
 
-       return mpf_rtp_stream_modify(audio_stream,&rtp_descriptor->audio);
+       status = mpf_rtp_stream_add(audio_stream);
+       if(rtp_descriptor) {
+               status = mpf_rtp_stream_modify(audio_stream,&rtp_descriptor->audio);
+       }
+       return status;
+}
+
+static apt_bool_t mpf_rtp_termination_modify(mpf_termination_t *termination, void *descriptor)
+{
+       apt_bool_t status = TRUE;
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = descriptor;
+       mpf_audio_stream_t *audio_stream = termination->audio_stream;
+       if(!audio_stream) {
+               return FALSE;
+       }
+
+       if(rtp_descriptor) {
+               status = mpf_rtp_stream_modify(audio_stream,&rtp_descriptor->audio);
+       }
+       return status;
+}
+
+static apt_bool_t mpf_rtp_termination_subtract(mpf_termination_t *termination)
+{
+       mpf_audio_stream_t *audio_stream = termination->audio_stream;
+       if(!audio_stream) {
+               return FALSE;
+       }
+       
+       return mpf_rtp_stream_remove(audio_stream);
 }
 
 static const mpf_termination_vtable_t rtp_vtable = {
        mpf_rtp_termination_destroy,
+       mpf_rtp_termination_add,
        mpf_rtp_termination_modify,
+       mpf_rtp_termination_subtract
 };
 
 static mpf_termination_t* mpf_rtp_termination_create(mpf_termination_factory_t *termination_factory, void *obj, apr_pool_t *pool)
diff --git a/libs/unimrcp/libs/mpf/src/mpf_scheduler.c b/libs/unimrcp/libs/mpf/src/mpf_scheduler.c
new file mode 100644 (file)
index 0000000..aefc513
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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 "mpf_scheduler.h"
+
+#ifdef WIN32
+#define ENABLE_MULTIMEDIA_TIMERS
+#endif
+
+#ifdef ENABLE_MULTIMEDIA_TIMERS
+
+#pragma warning(disable:4201)
+#include <mmsystem.h>
+#include <windows.h>
+
+#ifndef TIME_KILL_SYNCHRONOUS
+#define TIME_KILL_SYNCHRONOUS   0x0100
+#endif
+
+#else
+#include <apr_thread_proc.h>
+#endif
+
+
+struct mpf_scheduler_t {
+       apr_pool_t          *pool;
+       unsigned long        resolution; /* scheduler resolution */
+       unsigned long        rate; /* faster than real-time simulation */
+
+       unsigned long        media_resolution;
+       mpf_scheduler_proc_f media_proc;
+       void                *media_obj;
+       
+       unsigned long        timer_resolution;
+       unsigned long        timer_elapsed_time;
+       mpf_scheduler_proc_f timer_proc;
+       void                *timer_obj;
+
+#ifdef ENABLE_MULTIMEDIA_TIMERS
+       unsigned int         timer_id;
+#else
+       apr_thread_t        *thread;
+       apt_bool_t           running;
+#endif
+};
+
+static APR_INLINE void mpf_scheduler_init(mpf_scheduler_t *scheduler);
+
+/** Create scheduler */
+MPF_DECLARE(mpf_scheduler_t*) mpf_scheduler_create(unsigned long rate, apr_pool_t *pool)
+{
+       mpf_scheduler_t *scheduler = apr_palloc(pool,sizeof(mpf_scheduler_t));
+       mpf_scheduler_init(scheduler);
+       scheduler->pool = pool;
+       scheduler->resolution = 0;
+       if(rate == 0 || rate > 10) {
+               /* rate shows how many times scheduler should be faster than real-time,
+               1 is the defualt and probably the only reasonable value, 
+               however, the rates up to 10 times faster should be acceptable */
+               rate = 1;
+       }
+       scheduler->rate = rate;
+
+       scheduler->media_resolution = 0;
+       scheduler->media_obj = NULL;
+       scheduler->media_proc = NULL;
+
+       scheduler->timer_resolution = 0;
+       scheduler->timer_elapsed_time = 0;
+       scheduler->timer_obj = NULL;
+       scheduler->timer_proc = NULL;
+       return scheduler;
+}
+
+/** Destroy scheduler */
+MPF_DECLARE(void) mpf_scheduler_destroy(mpf_scheduler_t *scheduler)
+{
+       /* nothing to destroy */
+}
+
+/** Set media processing clock */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_media_clock_set(
+                                                               mpf_scheduler_t *scheduler,
+                                                               unsigned long resolution,
+                                                               mpf_scheduler_proc_f proc,
+                                                               void *obj)
+{
+       scheduler->media_resolution = resolution / scheduler->rate;
+       scheduler->media_proc = proc;
+       scheduler->media_obj = obj;
+       return TRUE;
+}
+
+/** Set timer clock */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_timer_clock_set(
+                                                               mpf_scheduler_t *scheduler,
+                                                               unsigned long resolution,
+                                                               mpf_scheduler_proc_f proc,
+                                                               void *obj)
+{
+       scheduler->timer_resolution = resolution / scheduler->rate;
+       scheduler->timer_elapsed_time = 0;
+       scheduler->timer_proc = proc;
+       scheduler->timer_obj = obj;
+       return TRUE;
+}
+
+static APR_INLINE void mpf_scheduler_resolution_set(mpf_scheduler_t *scheduler)
+{
+       if(scheduler->media_resolution) {
+               scheduler->resolution = scheduler->media_resolution;
+       }
+       else if(scheduler->timer_resolution) {
+               scheduler->resolution = scheduler->timer_resolution;
+       }
+}
+
+
+
+#ifdef ENABLE_MULTIMEDIA_TIMERS
+
+static APR_INLINE void mpf_scheduler_init(mpf_scheduler_t *scheduler)
+{
+       scheduler->timer_id = 0;
+}
+
+static void CALLBACK mm_timer_proc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+{
+       mpf_scheduler_t *scheduler = (mpf_scheduler_t*) dwUser;
+       if(scheduler->media_proc) {
+               scheduler->media_proc(scheduler,scheduler->media_obj);
+       }
+
+       if(scheduler->timer_proc) {
+               scheduler->timer_elapsed_time += scheduler->resolution;
+               if(scheduler->timer_elapsed_time >= scheduler->timer_resolution) {
+                       scheduler->timer_elapsed_time = 0;
+                       scheduler->timer_proc(scheduler,scheduler->timer_obj);
+               }
+       }
+}
+
+/** Start scheduler */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_start(mpf_scheduler_t *scheduler)
+{
+       mpf_scheduler_resolution_set(scheduler);
+       scheduler->timer_id = timeSetEvent(
+                                       scheduler->resolution, 0, mm_timer_proc, (DWORD_PTR) scheduler, 
+                                       TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS);
+       return scheduler->timer_id ? TRUE : FALSE;
+}
+
+/** Stop scheduler */
+MPF_DECLARE(apt_bool_t) mpf_scheduler_stop(mpf_scheduler_t *scheduler)
+{
+       if(!scheduler) {
+               return FALSE;
+       }
+
+       timeKillEvent(scheduler->timer_id);
+       scheduler->timer_id = 0;
+       return TRUE;
+}
+
+#else
+
+static APR_INLINE void mpf_scheduler_init(mpf_scheduler_t *scheduler)
+{
+       scheduler->thread = NULL;
+       scheduler->running = FALSE;
+}
+
+static void* APR_THREAD_FUNC timer_thread_proc(apr_thread_t *thread, void *data)
+{
+       mpf_scheduler_t *scheduler = data;
+       apr_interval_time_t timeout = scheduler->resolution * 1000;
+       apr_interval_time_t time_drift = 0;
+       apr_time_t time_now, time_last;
+       
+       time_now = apr_time_now();
+       while(scheduler->running == TRUE) {
+               time_last = time_now;
+
+               if(scheduler->media_proc) {
+                       scheduler->media_proc(scheduler,scheduler->media_obj);
+               }
+
+               if(scheduler->timer_proc) {
+                       scheduler->timer_elapsed_time += scheduler->resolution;
+                       if(scheduler->timer_elapsed_time >= scheduler->timer_resolution) {
+                               scheduler->timer_elapsed_time = 0;
+                               scheduler->timer_proc(scheduler,scheduler->timer_obj);
+                       }
+               }
+
+               if(timeout > time_drift) {
+                       apr_sleep(timeout - time_drift);
+               }
+
+               time_now = apr_time_now();
+               time_drift += time_now - time_last - timeout;
+#if 0
+               printf("time_drift=%d\n",time_drift);
+#endif
+       }
+       
+       return NULL;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_scheduler_start(mpf_scheduler_t *scheduler)
+{
+       mpf_scheduler_resolution_set(scheduler);
+       
+       scheduler->running = TRUE;
+       if(apr_thread_create(&scheduler->thread,NULL,timer_thread_proc,scheduler,scheduler->pool) != APR_SUCCESS) {
+               scheduler->running = FALSE;
+               return FALSE;
+       }
+       return TRUE;
+}
+
+MPF_DECLARE(apt_bool_t) mpf_scheduler_stop(mpf_scheduler_t *scheduler)
+{
+       if(!scheduler) {
+               return FALSE;
+       }
+
+       scheduler->running = FALSE;
+       if(scheduler->thread) {
+               apr_status_t s;
+               apr_thread_join(&s,scheduler->thread);
+               scheduler->thread = NULL;
+       }
+       return TRUE;
+}
+
+#endif
diff --git a/libs/unimrcp/libs/mpf/src/mpf_stream.c b/libs/unimrcp/libs/mpf/src/mpf_stream.c
new file mode 100644 (file)
index 0000000..1135e46
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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 "mpf_stream.h"
+
+/** Create stream capabilities */
+MPF_DECLARE(mpf_stream_capabilities_t*) mpf_stream_capabilities_create(mpf_stream_direction_e direction, apr_pool_t *pool)
+{
+       mpf_stream_capabilities_t *capabilities = (mpf_stream_capabilities_t*)apr_palloc(pool,sizeof(mpf_stream_capabilities_t));
+       capabilities->direction = direction;
+       mpf_codec_capabilities_init(&capabilities->codecs,1,pool);
+       return capabilities;
+}
+
+/** Clone stream capabilities */
+MPF_DECLARE(mpf_stream_capabilities_t*) mpf_stream_capabilities_clone(const mpf_stream_capabilities_t *src_capabilities, apr_pool_t *pool)
+{
+       mpf_stream_capabilities_t *capabilities = (mpf_stream_capabilities_t*)apr_palloc(pool,sizeof(mpf_stream_capabilities_t));
+       capabilities->direction = src_capabilities->direction;
+       mpf_codec_capabilities_clone(&capabilities->codecs,&src_capabilities->codecs,pool);
+       return capabilities;
+}
+
+/** Merge stream capabilities */
+MPF_DECLARE(apt_bool_t) mpf_stream_capabilities_merge(mpf_stream_capabilities_t *capabilities, const mpf_stream_capabilities_t *src_capabilities, apr_pool_t *pool)
+{
+       capabilities->direction |= src_capabilities->direction;
+       return mpf_codec_capabilities_merge(&capabilities->codecs,&src_capabilities->codecs,pool);
+}
+
+
+
+/** Create audio stream */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_audio_stream_create(void *obj, const mpf_audio_stream_vtable_t *vtable, const mpf_stream_capabilities_t *capabilities, apr_pool_t *pool)
+{
+       mpf_audio_stream_t *stream;
+       if(!vtable || !capabilities) {
+               return NULL;
+       }
+       
+       /* validate required fields */
+       if(capabilities->direction & STREAM_DIRECTION_SEND) {
+               /* validate sink */
+               if(!vtable->write_frame) {
+                       return NULL;
+               }
+       }
+       if(capabilities->direction & STREAM_DIRECTION_RECEIVE) {
+               /* validate source */
+               if(!vtable->read_frame) {
+                       return NULL;
+               }
+       }
+
+       stream = (mpf_audio_stream_t*)apr_palloc(pool,sizeof(mpf_audio_stream_t));
+       stream->obj = obj;
+       stream->vtable = vtable;
+       stream->termination = NULL;
+       stream->capabilities = capabilities;
+       stream->direction = capabilities->direction;
+       stream->rx_descriptor = NULL;
+       stream->rx_event_descriptor = NULL;
+       stream->tx_descriptor = NULL;
+       stream->tx_event_descriptor = NULL;
+       return stream;
+}
+
+/** Validate audio stream receiver */
+MPF_DECLARE(apt_bool_t) mpf_audio_stream_rx_validate(
+                                                                       mpf_audio_stream_t *stream,
+                                                                       const mpf_codec_descriptor_t *descriptor,
+                                                                       const mpf_codec_descriptor_t *event_descriptor,
+                                                                       apr_pool_t *pool)
+{
+       if(!stream->capabilities) {
+               return FALSE;
+       }
+
+       if(!stream->rx_descriptor) {
+               stream->rx_descriptor = mpf_codec_descriptor_create_by_capabilities(&stream->capabilities->codecs,descriptor,pool);
+       }
+       if(!stream->rx_event_descriptor) {
+               if(stream->capabilities->codecs.allow_named_events == TRUE && event_descriptor) {
+                       stream->rx_event_descriptor = apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+                       *stream->rx_event_descriptor = *event_descriptor;
+               }
+       }
+
+       return stream->rx_descriptor ? TRUE : FALSE;
+}
+
+/** Validate audio stream transmitter */
+MPF_DECLARE(apt_bool_t) mpf_audio_stream_tx_validate(
+                                                                       mpf_audio_stream_t *stream,
+                                                                       const mpf_codec_descriptor_t *descriptor,
+                                                                       const mpf_codec_descriptor_t *event_descriptor,
+                                                                       apr_pool_t *pool)
+{
+       if(!stream->capabilities) {
+               return FALSE;
+       }
+
+       if(!stream->tx_descriptor) {
+               stream->tx_descriptor = mpf_codec_descriptor_create_by_capabilities(&stream->capabilities->codecs,descriptor,pool);
+       }
+       if(!stream->tx_event_descriptor) {
+               if(stream->capabilities->codecs.allow_named_events == TRUE && event_descriptor) {
+                       stream->tx_event_descriptor = apr_palloc(pool,sizeof(mpf_codec_descriptor_t));
+                       *stream->tx_event_descriptor = *event_descriptor;
+               }
+       }
+       return stream->tx_descriptor ? TRUE : FALSE;
+}
+
+/** Trace media path */
+MPF_DECLARE(void) mpf_audio_stream_trace(mpf_audio_stream_t *stream, mpf_stream_direction_e direction, apt_text_stream_t *output)
+{
+       if(stream->vtable->trace) {
+               stream->vtable->trace(stream,direction,output);
+               return;
+       }
+
+       if(direction & STREAM_DIRECTION_SEND) {
+               mpf_codec_descriptor_t *descriptor = stream->tx_descriptor;
+               if(descriptor) {
+                       apr_size_t offset = output->pos - output->text.buf;
+                       output->pos += apr_snprintf(output->pos, output->text.length - offset,
+                               "[%s/%d/%d]->Sink",
+                               descriptor->name.buf,
+                               descriptor->sampling_rate,
+                               descriptor->channel_count);
+               }
+       }
+       if(direction & STREAM_DIRECTION_RECEIVE) {
+               mpf_codec_descriptor_t *descriptor = stream->rx_descriptor;
+               if(descriptor) {
+                       apr_size_t offset = output->pos - output->text.buf;
+                       output->pos += apr_snprintf(output->pos, output->text.length - offset,
+                               "Source->[%s/%d/%d]",
+                               descriptor->name.buf,
+                               descriptor->sampling_rate,
+                               descriptor->channel_count);
+               }
+       }
+}
index 291d92cae3a2b7df9dd79646453714bcd7adde98..05eff5c41912cbeb0c70a275352aa8766c995257 100644 (file)
@@ -32,6 +32,7 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
        termination->event_handler_obj = NULL;
        termination->event_handler = NULL;
        termination->codec_manager = NULL;
+       termination->timer_manager = NULL;
        termination->termination_factory = termination_factory;
        termination->vtable = vtable;
        termination->slot = 0;
@@ -46,19 +47,14 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
        return termination;
 }
 
-MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination)
+MPF_DECLARE(apt_bool_t) mpf_termination_add(mpf_termination_t *termination, void *descriptor)
 {
-       if(termination->vtable && termination->vtable->destroy) {
-               termination->vtable->destroy(termination);
+       if(termination->vtable && termination->vtable->add) {
+               termination->vtable->add(termination,descriptor);
        }
        return TRUE;
 }
 
-MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination)
-{
-       return termination->obj;
-}
-
 MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor)
 {
        if(termination->vtable && termination->vtable->modify) {
@@ -67,54 +63,10 @@ MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, v
        return TRUE;
 }
 
-MPF_DECLARE(apt_bool_t) mpf_termination_validate(mpf_termination_t *termination)
+MPF_DECLARE(apt_bool_t) mpf_termination_subtract(mpf_termination_t *termination)
 {
-       mpf_audio_stream_t *audio_stream;
-       if(!termination) {
-               return FALSE;
-       }
-       audio_stream = termination->audio_stream;
-       if(audio_stream) {
-               if(!audio_stream->vtable) {
-                       return FALSE;
-               }
-               if((audio_stream->mode & STREAM_MODE_RECEIVE) == STREAM_MODE_RECEIVE) {
-                       if(!audio_stream->rx_codec) {
-                               audio_stream->rx_codec = mpf_codec_manager_default_codec_get(
-                                                                                       termination->codec_manager,
-                                                                                       termination->pool);
-                       }
-               }
-               if((audio_stream->mode & STREAM_MODE_SEND) == STREAM_MODE_SEND) {
-                       if(!audio_stream->tx_codec) {
-                               audio_stream->tx_codec = mpf_codec_manager_default_codec_get(
-                                                                                       termination->codec_manager,
-                                                                                       termination->pool);
-                       }
-               }
+       if(termination->vtable && termination->vtable->subtract) {
+               termination->vtable->subtract(termination);
        }
        return TRUE;
 }
-
-
-/** Create MPF termination by termination factory */
-MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
-                                                                               mpf_termination_factory_t *termination_factory,
-                                                                               void *obj,
-                                                                               apr_pool_t *pool)
-{
-       if(termination_factory && termination_factory->create_termination) {
-               return termination_factory->create_termination(termination_factory,obj,pool);
-       }
-       return NULL;
-}
-
-/** Create raw MPF termination. */
-MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
-                                                                               void *obj,
-                                                                               mpf_audio_stream_t *audio_stream,
-                                                                               mpf_video_stream_t *video_stream,
-                                                                               apr_pool_t *pool)
-{
-       return mpf_termination_base_create(NULL,obj,NULL,audio_stream,video_stream,pool);
-}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c b/libs/unimrcp/libs/mpf/src/mpf_termination_factory.c
new file mode 100644 (file)
index 0000000..ba89f51
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 "mpf_termination_factory.h"
+#include "mpf_termination.h"
+
+/** Create MPF termination from termination factory */
+MPF_DECLARE(mpf_termination_t*) mpf_termination_create(
+                                                                               mpf_termination_factory_t *termination_factory,
+                                                                               void *obj,
+                                                                               apr_pool_t *pool)
+{
+       if(termination_factory && termination_factory->create_termination) {
+               return termination_factory->create_termination(termination_factory,obj,pool);
+       }
+       return NULL;
+}
+
+/** Create raw MPF termination. */
+MPF_DECLARE(mpf_termination_t*) mpf_raw_termination_create(
+                                                                               void *obj,
+                                                                               mpf_audio_stream_t *audio_stream,
+                                                                               mpf_video_stream_t *video_stream,
+                                                                               apr_pool_t *pool)
+{
+       return mpf_termination_base_create(NULL,obj,NULL,audio_stream,video_stream,pool);
+}
+
+MPF_DECLARE(apt_bool_t) mpf_termination_destroy(mpf_termination_t *termination)
+{
+       if(termination->vtable && termination->vtable->destroy) {
+               termination->vtable->destroy(termination);
+       }
+       return TRUE;
+}
+
+/** Get associated object. */
+MPF_DECLARE(void*) mpf_termination_object_get(mpf_termination_t *termination)
+{
+       return termination->obj;
+}
+
+/** Get audio stream. */
+MPF_DECLARE(mpf_audio_stream_t*) mpf_termination_audio_stream_get(mpf_termination_t *termination)
+{
+       return termination->audio_stream;
+}
+
+/** Get video stream. */
+MPF_DECLARE(mpf_video_stream_t*) mpf_termination_video_stream_get(mpf_termination_t *termination)
+{
+       return termination->video_stream;
+}
diff --git a/libs/unimrcp/libs/mpf/src/mpf_timer.c b/libs/unimrcp/libs/mpf/src/mpf_timer.c
deleted file mode 100644 (file)
index aaca492..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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 "mpf_timer.h"
-
-#ifdef WIN32
-#define ENABLE_MULTIMEDIA_TIMERS
-#endif
-
-#ifdef ENABLE_MULTIMEDIA_TIMERS
-
-#pragma warning(disable:4201)
-#include <mmsystem.h>
-#include <windows.h>
-
-#ifndef TIME_KILL_SYNCHRONOUS
-#define TIME_KILL_SYNCHRONOUS   0x0100
-#endif
-
-struct mpf_timer_t {
-       unsigned int     timer_id;
-       mpf_timer_proc_f timer_proc;
-       void            *obj;
-};
-
-#define MAX_MEDIA_TIMERS 10
-
-static mpf_timer_t media_timer_set[MAX_MEDIA_TIMERS];
-
-static void CALLBACK mm_timer_proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
-
-MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool)
-{
-       mpf_timer_t *timer = NULL;
-       size_t i;
-       for(i = 0; i<MAX_MEDIA_TIMERS; i++) {
-               if(!media_timer_set[i].timer_id) {
-                       timer = &media_timer_set[i];
-                       break;
-               }
-       }
-               
-       if(timer) {
-               timer->timer_proc = timer_proc;
-               timer->obj = obj;
-               timer->timer_id = timeSetEvent(timeout, 0, mm_timer_proc, i, 
-                       TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS);
-               if(!timer->timer_id) {
-                       timer = NULL;
-               }
-       }
-       return timer;
-}
-
-MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer)
-{
-       if(timer) {
-               timeKillEvent(timer->timer_id);
-               timer->timer_id = 0;
-               timer->timer_proc = NULL;
-               timer->obj = NULL;
-       }
-}
-
-static void CALLBACK mm_timer_proc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
-{
-       mpf_timer_t *timer;
-       if(dwUser >= MAX_MEDIA_TIMERS) {
-               return;
-       }
-       timer = &media_timer_set[dwUser];
-       timer->timer_proc(timer,timer->obj);
-}
-
-#else
-
-#include <apr_thread_proc.h>
-
-struct mpf_timer_t {
-       apr_thread_t    *thread;
-       apr_byte_t       running;
-
-       unsigned long    timeout;
-       mpf_timer_proc_f timer_proc;
-       void            *obj;
-};
-
-static void* APR_THREAD_FUNC timer_thread_proc(apr_thread_t *thread, void *data);
-
-MPF_DECLARE(mpf_timer_t*) mpf_timer_start(unsigned long timeout, mpf_timer_proc_f timer_proc, void *obj, apr_pool_t *pool)
-{
-       mpf_timer_t *timer = apr_palloc(pool,sizeof(mpf_timer_t));
-       timer->timeout = timeout;
-       timer->timer_proc = timer_proc;
-       timer->obj = obj;
-       timer->running = 1;
-       if(apr_thread_create(&timer->thread,NULL,timer_thread_proc,timer,pool) != APR_SUCCESS) {
-               return NULL;
-       }
-       return timer;
-}
-
-MPF_DECLARE(void) mpf_timer_stop(mpf_timer_t *timer)
-{
-       if(timer) {
-               timer->running = 0;
-               if(timer->thread) {
-                       apr_status_t s;
-                       apr_thread_join(&s,timer->thread);
-                       timer->thread = NULL;
-               }
-       }
-}
-
-static void* APR_THREAD_FUNC timer_thread_proc(apr_thread_t *thread, void *data)
-{
-       mpf_timer_t *timer = data;
-       apr_interval_time_t timeout = timer->timeout * 1000;
-       apr_interval_time_t time_drift = 0;
-       apr_time_t time_now, time_last;
-       
-       time_now = apr_time_now();
-       while(timer->running) {
-               time_last = time_now;
-               timer->timer_proc(timer,timer->obj);
-
-               if(timeout > time_drift) {
-                       apr_sleep(timeout - time_drift);
-               }
-
-               time_now = apr_time_now();
-               time_drift += time_now - time_last - timeout;
-#if 0
-               printf("time_drift=%d\n",time_drift);
-#endif
-       }
-       
-       return NULL;
-}
-
-#endif
diff --git a/libs/unimrcp/libs/mpf/src/mpf_timer_manager.c b/libs/unimrcp/libs/mpf/src/mpf_timer_manager.c
new file mode 100644 (file)
index 0000000..4e570ca
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#ifdef WIN32
+#pragma warning(disable: 4127)
+#endif
+#include <apr_ring.h> 
+#include "mpf_timer_manager.h"
+#include "mpf_scheduler.h"
+#include "apt_log.h"
+
+/** MPF timer manager */
+struct mpf_timer_manager_t {
+       /** Ring head */
+       APR_RING_HEAD(mpf_timer_head_t, mpf_timer_t) head;
+
+       /** Clock resolution */
+       apr_uint32_t  resolution;
+       /** Elapsed time */
+       apr_uint32_t  elapsed_time;
+};
+
+/** MPF timer */
+struct mpf_timer_t {
+       /** Ring entry */
+       APR_RING_ENTRY(mpf_timer_t) link;
+
+       /** Back pointer to manager */
+       mpf_timer_manager_t *manager;
+       /** Time next report is scheduled at */
+       apr_uint32_t         scheduled_time;
+
+       /** Timer proc */
+       mpf_timer_proc_f     proc;
+       /** Timer object */
+       void                *obj;
+};
+
+static void mpf_scheduler_proc(mpf_scheduler_t *scheduler, void *obj);
+
+/** Create timer manager */
+MPF_DECLARE(mpf_timer_manager_t*) mpf_timer_manager_create(mpf_scheduler_t *scheduler, apr_pool_t *pool)
+{
+       mpf_timer_manager_t *timer_manager = apr_palloc(pool,sizeof(mpf_timer_manager_t));
+       APR_RING_INIT(&timer_manager->head, mpf_timer_t, link);
+       timer_manager->elapsed_time = 0;
+       timer_manager->resolution = 100; // 100 ms
+
+       mpf_scheduler_timer_clock_set(scheduler,timer_manager->resolution,mpf_scheduler_proc,timer_manager);
+       return timer_manager;
+}
+
+/** Destroy timer manager */
+MPF_DECLARE(void) mpf_timer_manager_destroy(mpf_timer_manager_t *timer_manager)
+{
+}
+
+
+/** Create timer */
+MPF_DECLARE(mpf_timer_t*) mpf_timer_create(mpf_timer_manager_t *timer_manager, mpf_timer_proc_f proc, void *obj, apr_pool_t *pool)
+{
+       mpf_timer_t *timer = apr_palloc(pool,sizeof(mpf_timer_t));
+       timer->manager = timer_manager;
+       timer->scheduled_time = 0;
+       timer->proc = proc;
+       timer->obj = obj;
+       return timer;
+}
+
+static APR_INLINE apt_bool_t mpf_timer_insert(mpf_timer_manager_t *manager, mpf_timer_t *timer)
+{
+       mpf_timer_t *it;
+       for(it = APR_RING_LAST(&manager->head);
+                       it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link);
+                               it = APR_RING_PREV(it, link)) {
+               
+               if(it->scheduled_time <= timer->scheduled_time) {
+                       APR_RING_INSERT_AFTER(it,timer,link);
+                       return TRUE;
+               }
+       }
+       APR_RING_INSERT_HEAD(&manager->head,timer,mpf_timer_t,link);
+       return TRUE;
+}
+
+/** Set one-shot timer */
+MPF_DECLARE(apt_bool_t) mpf_timer_set(mpf_timer_t *timer, apr_uint32_t timeout)
+
+{
+       mpf_timer_manager_t *manager = timer->manager;
+
+       if(timeout <= 0 || !timer->proc) {
+               return FALSE;
+       }
+       
+       /* calculate time to elapse */
+       timer->scheduled_time = manager->elapsed_time + timeout;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Set Timer 0x%x [%d]",timer,timer->scheduled_time);
+
+       if(APR_RING_EMPTY(&timer->manager->head, mpf_timer_t, link)) {
+               APR_RING_INSERT_TAIL(&manager->head,timer,mpf_timer_t,link);
+               return TRUE;
+       }
+
+       /* insert new node (timer) to sorted by scheduled time list */
+       return mpf_timer_insert(manager,timer);
+}
+
+/** Kill timer */
+MPF_DECLARE(apt_bool_t) mpf_timer_kill(mpf_timer_t *timer)
+{
+       if(!timer->scheduled_time) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Kill Timer 0x%x [%d]",timer,timer->scheduled_time);
+       /* remove node (timer) from the list */
+       APR_RING_REMOVE(timer,link);
+       timer->scheduled_time = 0;
+
+       if(APR_RING_EMPTY(&timer->manager->head, mpf_timer_t, link)) {
+               /* reset elapsed time if no timers set */
+               timer->manager->elapsed_time = 0;
+       }
+       return TRUE;
+}
+
+static void mpf_timers_reschedule(mpf_timer_manager_t *manager)
+{
+       mpf_timer_t *it;
+       for(it = APR_RING_LAST(&manager->head);
+                       it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link);
+                               it = APR_RING_PREV(it, link)) {
+               
+               it->scheduled_time -= manager->elapsed_time;
+       }
+       manager->elapsed_time = 0;
+}
+
+static void mpf_scheduler_proc(mpf_scheduler_t *scheduler, void *obj)
+{
+       mpf_timer_manager_t *manager = obj;
+       mpf_timer_t *timer;
+
+       if(APR_RING_EMPTY(&manager->head, mpf_timer_t, link)) {
+               /* just return, nothing to do */
+               return;
+       }
+
+       /* increment elapsed time */
+       manager->elapsed_time += manager->resolution;
+       if(manager->elapsed_time >= 0xFFFF) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Reschedule Timers [%d]",manager->elapsed_time);
+               mpf_timers_reschedule(manager);
+       }
+
+       /* process timers */
+       do {
+               /* get first node (timer) */
+               timer = APR_RING_FIRST(&manager->head);
+
+               if(timer->scheduled_time > manager->elapsed_time) {
+                       /* scheduled time is not elapsed yet */
+                       break;
+               }
+               
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Timer Elapsed 0x%x [%d]",timer,timer->scheduled_time);
+               /* remove the elapsed timer from the list */
+               APR_RING_REMOVE(timer, link);
+               timer->scheduled_time = 0;
+               /* process the elapsed timer */
+               timer->proc(timer,timer->obj);
+       }
+       while(!APR_RING_EMPTY(&manager->head, mpf_timer_t, link));
+}
index fbd4c425ea34e4426eaea994fe8d2e480786b11d..92bea0a3d46c96e6408b43693079837c0b4fb619 100644 (file)
@@ -173,12 +173,31 @@ MRCP_DECLARE(const apt_dir_layout_t*) mrcp_application_dir_layout_get(mrcp_appli
  */
 MRCP_DECLARE(mrcp_session_t*) mrcp_application_session_create(mrcp_application_t *application, const char *profile, void *obj);
 
+/**
+ * Get memory pool the session object is created out of.
+ * @param session the session to get pool from
+ */
+MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(mrcp_session_t *session);
+
+/**
+ * Get session identifier.
+ * @param session the session to get identifier of
+ */
+MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(mrcp_session_t *session);
+
 /**
  * Get external object associated with the session.
  * @param session the session to get object from
  */
 MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session);
 
+/**
+ * Set (associate) external object to the session.
+ * @param session the session to set object for
+ * @param obj the object to set
+ */
+MRCP_DECLARE(void) mrcp_application_session_object_set(mrcp_session_t *session, void *obj);
+
 /** 
  * Send session update request.
  * @param session the session to update
@@ -225,6 +244,18 @@ MRCP_DECLARE(void*) mrcp_application_channel_object_get(mrcp_channel_t *channel)
  */
 MRCP_DECLARE(mpf_rtp_termination_descriptor_t*) mrcp_application_rtp_descriptor_get(mrcp_channel_t *channel);
 
+/**
+ * Get codec descriptor of source stream.
+ * @param channel the channel to get descriptor from
+ */
+MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(mrcp_channel_t *channel);
+
+/**
+ * Get codec descriptor of sink stream.
+ * @param channel the channel to get descriptor from
+ */
+MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(mrcp_channel_t *channel);
+
 /** 
  * Send channel add request.
  * @param session the session to create channel for
@@ -268,23 +299,38 @@ MRCP_DECLARE(apt_bool_t) mrcp_application_resource_discover(mrcp_session_t *sess
  */
 MRCP_DECLARE(apt_bool_t) mrcp_application_message_dispatch(const mrcp_app_message_dispatcher_t *dispatcher, const mrcp_app_message_t *app_message);
 
-
-/** Create source media termination
- * @param session the session to create channel for
+/** 
+ * Create audio termination
+ * @param session the session to create termination for
+ * @param stream_vtable the virtual table of audio stream
+ * @param capabilities the capabilities of the stream
+ * @param obj the external object
+ */
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_audio_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_stream_capabilities_t *capabilities,
+                                                                               void *obj);
+/** 
+ * Create source media termination
+ * @param session the session to create termination for
  * @param stream_vtable the virtual table of audio stream
  * @param codec_descriptor the descriptor of audio stream (NULL by default)
  * @param obj the external object
+ * @deprecated @see mrcp_application_audio_termination_create()
  */
 MRCP_DECLARE(mpf_termination_t*) mrcp_application_source_termination_create(
                                                                                mrcp_session_t *session,
                                                                                const mpf_audio_stream_vtable_t *stream_vtable,
                                                                                mpf_codec_descriptor_t *codec_descriptor,
                                                                                void *obj);
-/** Create sink media termination
- * @param session the session to create channel for
+/** 
+ * Create sink media termination
+ * @param session the session to create termination for
  * @param stream_vtable the virtual table of audio stream
  * @param codec_descriptor the descriptor of audio stream (NULL by default)
  * @param obj the external object
+ * @deprecated @see mrcp_application_audio_termination_create()
  */
 MRCP_DECLARE(mpf_termination_t*) mrcp_application_sink_termination_create(
                                                                                mrcp_session_t *session,
index c12820119d6dae6b1be1032e67a7134dbb41cb2b..40a444a82521e1476fe2d9bb3085f544f5927958 100644 (file)
@@ -25,7 +25,7 @@
 #include "mrcp_client_types.h"
 #include "mrcp_application.h"
 #include "mrcp_session.h"
-#include "mpf_message.h"
+#include "mpf_engine.h"
 #include "apt_task_msg.h"
 #include "apt_obj_list.h"
 
@@ -37,47 +37,59 @@ typedef struct rtp_termination_slot_t rtp_termination_slot_t;
 /** MRCP client session declaration */
 typedef struct mrcp_client_session_t mrcp_client_session_t;
 
+/** Client session states */
+typedef enum {
+       SESSION_STATE_NONE,
+       SESSION_STATE_GENERATING_OFFER,
+       SESSION_STATE_PROCESSING_ANSWER,
+       SESSION_STATE_TERMINATING,
+       SESSION_STATE_DISCOVERING
+} mrcp_client_session_state_e;
+
 /** MRCP client session */
 struct mrcp_client_session_t {
        /** Session base */
-       mrcp_session_t             base;
+       mrcp_session_t              base;
        /** Application session belongs to */
-       mrcp_application_t        *application;
+       mrcp_application_t         *application;
        /** External object associated with session */
-       void                      *app_obj;
+       void                       *app_obj;
        /** Profile to use */
-       mrcp_profile_t            *profile;
+       mrcp_profile_t             *profile;
 
        /** Media context */
-       mpf_context_t             *context;
+       mpf_context_t              *context;
        /** Codec manager */
-       const mpf_codec_manager_t *codec_manager;
+       const mpf_codec_manager_t  *codec_manager;
 
 
        /** RTP termination array (mrcp_termination_slot_t) */
-       apr_array_header_t        *terminations;
+       apr_array_header_t         *terminations;
        /** MRCP control channel array (mrcp_channel_t*) */
-       apr_array_header_t        *channels;
+       apr_array_header_t         *channels;
 
        /** Indicates whether session is already added to session table */
-       apt_bool_t                 registered;
+       apt_bool_t                  registered;
 
        /** In-progress offer */
-       mrcp_session_descriptor_t *offer;
+       mrcp_session_descriptor_t  *offer;
        /** In-progress answer */
-       mrcp_session_descriptor_t *answer;
+       mrcp_session_descriptor_t  *answer;
 
        /** MRCP application active request */
-       const mrcp_app_message_t  *active_request;
+       const mrcp_app_message_t   *active_request;
        /** MRCP application request queue */
-       apt_obj_list_t            *request_queue;
-
-       /** Number of in-progress offer requests (flags) */
-       apr_size_t                 offer_flag_count;
-       /** Number of in-progress answer requests (flags) */
-       apr_size_t                 answer_flag_count;
-       /** Number of in-progress terminate requests (flags) */
-       apr_size_t                 terminate_flag_count;
+       apt_obj_list_t             *request_queue;
+
+       /** MPF task message, which construction is in progress */
+       mpf_task_msg_t             *mpf_task_msg;
+
+       /** Session state */
+       mrcp_client_session_state_e state;
+       /** Status code of the app response to be generated */
+       mrcp_sig_status_code_e      status;
+       /** Number of in-progress sub requests */
+       apr_size_t                  subrequest_count;
 };
 
 /** MRCP channel */
@@ -86,10 +98,6 @@ struct mrcp_channel_t {
        apr_pool_t             *pool;
        /** External object associated with channel */
        void                   *obj;
-       /** MRCP resource identifier */
-       mrcp_resource_id        resource_id;
-       /** MRCP resource name */
-       const apt_str_t        *resource_name;
        /** MRCP resource */
        mrcp_resource_t        *resource;
        /** MRCP session entire channel belongs to */
@@ -115,6 +123,10 @@ struct rtp_termination_slot_t {
        mpf_termination_t                *termination;
        /** RTP termination descriptor */
        mpf_rtp_termination_descriptor_t *descriptor;
+       /** Associated MRCP channel */
+       mrcp_channel_t                   *channel;
+       /** media descriptor id (index of media in session descriptor) */
+       apr_size_t                        id;
 };
 
 
@@ -149,7 +161,7 @@ mrcp_client_session_t* mrcp_client_session_create(mrcp_application_t *applicatio
 /** Create channel */
 mrcp_channel_t* mrcp_client_channel_create(
                                        mrcp_session_t *session, 
-                                       mrcp_resource_id resource_id
+                                       mrcp_resource_t *resource
                                        mpf_termination_t *termination, 
                                        mpf_rtp_termination_descriptor_t *rtp_descriptor, 
                                        void *obj);
@@ -160,13 +172,11 @@ mrcp_app_message_t* mrcp_client_app_signaling_request_create(mrcp_sig_command_e
 mrcp_app_message_t* mrcp_client_app_signaling_event_create(mrcp_sig_event_e event_id, apr_pool_t *pool);
 /** Create control app_message_t */
 mrcp_app_message_t* mrcp_client_app_control_message_create(apr_pool_t *pool);
-/** Create response to app_message_t request */
-mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_message_t *app_request, mrcp_sig_status_code_e status, apr_pool_t *pool);
 
 /** Process application message */
 apt_bool_t mrcp_client_app_message_process(mrcp_app_message_t *app_message);
 /** Process MPF message */
-apt_bool_t mrcp_client_mpf_message_process(mpf_message_t *mpf_message);
+apt_bool_t mrcp_client_mpf_message_process(mpf_message_container_t *mpf_message_container);
 
 /** Process session answer */
 apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor);
@@ -187,6 +197,8 @@ apt_bool_t mrcp_client_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d
 apt_bool_t mrcp_client_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status);
 /** Process message receive event */
 apt_bool_t mrcp_client_on_message_receive(mrcp_channel_t *channel, mrcp_message_t *message);
+/** Process disconnect event */
+apt_bool_t mrcp_client_on_disconnect(mrcp_channel_t *channel);
 
 APT_END_EXTERN_C
 
index e2e303fc1e6a41a9bbd1073bbd275b0421072922..e289b8e62abeb35b9731430608e996e31fa0ea30 100644 (file)
 #include <apr_hash.h>
 #include "mrcp_client.h"
 #include "mrcp_resource_factory.h"
+#include "mrcp_resource.h"
 #include "mrcp_sig_agent.h"
 #include "mrcp_client_session.h"
 #include "mrcp_client_connection.h"
 #include "mrcp_message.h"
 #include "mpf_engine.h"
-#include "mpf_termination.h"
+#include "mpf_termination_factory.h"
 #include "mpf_codec_manager.h"
 #include "apt_pool.h"
 #include "apt_consumer_task.h"
@@ -112,6 +113,7 @@ typedef enum {
        CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
        CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
        CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
+       CONNECTION_AGENT_TASK_MSG_DISCONNECT
 } connection_agent_task_msg_type_e ;
 
 typedef struct connection_agent_task_msg_data_t connection_agent_task_msg_data_t;
@@ -126,12 +128,14 @@ static apt_bool_t mrcp_client_channel_add_signal(mrcp_control_channel_t *channel
 static apt_bool_t mrcp_client_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
 static apt_bool_t mrcp_client_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status);
 static apt_bool_t mrcp_client_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *message);
+static apt_bool_t mrcp_client_disconnect_signal(mrcp_control_channel_t *channel);
 
 static const mrcp_connection_event_vtable_t connection_method_vtable = {
        mrcp_client_channel_add_signal,
        mrcp_client_channel_modify_signal,
        mrcp_client_channel_remove_signal,
-       mrcp_client_message_signal
+       mrcp_client_message_signal,
+       mrcp_client_disconnect_signal
 };
 
 /* Task interface */
@@ -497,6 +501,24 @@ MRCP_DECLARE(mrcp_session_t*) mrcp_application_session_create(mrcp_application_t
        return &session->base;
 }
 
+/** Get memory pool the session object is created out of */
+MRCP_DECLARE(apr_pool_t*) mrcp_application_session_pool_get(mrcp_session_t *session)
+{
+       if(!session) {
+               return NULL;
+       }
+       return session->pool;
+}
+
+/** Get session identifier */
+MRCP_DECLARE(const apt_str_t*) mrcp_application_session_id_get(mrcp_session_t *session)
+{
+       if(!session) {
+               return NULL;
+       }
+       return &session->id;
+}
+
 /** Get external object associated with the session */
 MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session)
 {
@@ -507,6 +529,14 @@ MRCP_DECLARE(void*) mrcp_application_session_object_get(mrcp_session_t *session)
        return client_session->app_obj;
 }
 
+/** Set (associate) external object to the session */
+MRCP_DECLARE(void) mrcp_application_session_object_set(mrcp_session_t *session, void *obj)
+{
+       mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
+       if(client_session) {
+               client_session->app_obj = obj;
+       }
+}
 
 /** Send session update request */
 MRCP_DECLARE(apt_bool_t) mrcp_application_session_update(mrcp_session_t *session)
@@ -546,14 +576,28 @@ MRCP_DECLARE(mrcp_channel_t*) mrcp_application_channel_create(
                                                                        mpf_rtp_termination_descriptor_t *rtp_descriptor, 
                                                                        void *obj)
 {
+       mrcp_resource_t *resource;
+       mrcp_profile_t *profile;
        mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
        if(!client_session || !client_session->profile) {
                /* Invalid params */
                return FALSE;
        }
+       profile = client_session->profile;
+
+       if(!profile->resource_factory) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: invalid profile");
+               return FALSE;
+       }
+       resource = mrcp_resource_get(profile->resource_factory,resource_id);
+       if(!resource) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: no such resource");
+               return FALSE;
+       }
+
        if(termination) {
                /* Media engine and RTP factory must be specified in this case */
-               if(!client_session->profile->media_engine || !client_session->profile->rtp_termination_factory) {
+               if(!profile->media_engine || !profile->rtp_termination_factory) {
                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Channel: invalid profile");
                        return FALSE;
                }
@@ -565,7 +609,8 @@ MRCP_DECLARE(mrcp_channel_t*) mrcp_application_channel_create(
                        return FALSE;
                }
        }
-       return mrcp_client_channel_create(session,resource_id,termination,rtp_descriptor,obj);
+
+       return mrcp_client_channel_create(session,resource,termination,rtp_descriptor,obj);
 }
 
 /** Get external object associated with the channel */
@@ -581,11 +626,40 @@ MRCP_DECLARE(void*) mrcp_application_channel_object_get(mrcp_channel_t *channel)
 MRCP_DECLARE(mpf_rtp_termination_descriptor_t*) mrcp_application_rtp_descriptor_get(mrcp_channel_t *channel)
 {
        if(!channel || !channel->rtp_termination_slot) {
-               return FALSE;
+               return NULL;
        }
        return channel->rtp_termination_slot->descriptor;
 }
 
+/** Get codec descriptor of source stream */
+MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_source_descriptor_get(mrcp_channel_t *channel)
+{
+       mpf_audio_stream_t *audio_stream;
+       if(!channel || !channel->termination) {
+               return NULL;
+       }
+       audio_stream = mpf_termination_audio_stream_get(channel->termination);
+       if(!audio_stream) {
+               return NULL;
+       }
+       return audio_stream->rx_descriptor;
+}
+
+/** Get codec descriptor of sink stream */
+MRCP_DECLARE(const mpf_codec_descriptor_t*) mrcp_application_sink_descriptor_get(mrcp_channel_t *channel)
+{
+       mpf_audio_stream_t *audio_stream;
+       if(!channel || !channel->termination) {
+               return NULL;
+       }
+       audio_stream = mpf_termination_audio_stream_get(channel->termination);
+       if(!audio_stream) {
+               return NULL;
+       }
+       return audio_stream->tx_descriptor;
+}
+
+
 /** Send channel add request */
 MRCP_DECLARE(apt_bool_t) mrcp_application_channel_add(mrcp_session_t *session, mrcp_channel_t *channel)
 {
@@ -619,18 +693,18 @@ MRCP_DECLARE(mrcp_message_t*) mrcp_application_message_create(mrcp_session_t *se
        mrcp_message_t *mrcp_message;
        mrcp_profile_t *profile;
        mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
-       if(!client_session || !channel) {
+       if(!client_session || !channel || !channel->resource) {
                return NULL;
        }
        profile = client_session->profile;
        if(!profile || !profile->resource_factory) {
                return NULL;
        }
-       mrcp_message = mrcp_request_create(channel->resource_id,method_id,session->pool);
-       if(mrcp_message) {
-               mrcp_message->start_line.version = profile->signaling_agent->mrcp_version;
-               mrcp_message_resourcify_by_id(profile->resource_factory,mrcp_message);
-       }
+       mrcp_message = mrcp_request_create(
+                                               channel->resource,
+                                               profile->signaling_agent->mrcp_version,
+                                               method_id,
+                                               session->pool);
        return mrcp_message;
 }
 
@@ -643,6 +717,47 @@ MRCP_DECLARE(apt_bool_t) mrcp_application_message_send(mrcp_session_t *session,
        return mrcp_app_control_task_msg_signal(session,channel,message);
 }
 
+/** 
+ * Create audio termination
+ * @param session the session to create termination for
+ * @param stream_vtable the virtual table of audio stream
+ * @param capabilities the capabilities of the stream
+ * @param obj the external object
+ */
+MRCP_DECLARE(mpf_termination_t*) mrcp_application_audio_termination_create(
+                                                                               mrcp_session_t *session,
+                                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                                               mpf_stream_capabilities_t *capabilities,
+                                                                               void *obj)
+{
+       mpf_audio_stream_t *audio_stream;
+
+       if(!capabilities) {
+               return NULL;
+       }
+
+       if(mpf_codec_capabilities_validate(&capabilities->codecs) == FALSE) {
+               return NULL;
+       }
+
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       obj,                  /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       session->pool);       /* memory pool to allocate memory from */
+       if(!audio_stream) {
+               return NULL;
+       }
+
+       /* create raw termination */
+       return mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       session->pool);       /* memory pool to allocate memory from */
+}
+
 /** Create source media termination */
 MRCP_DECLARE(mpf_termination_t*) mrcp_application_source_termination_create(
                                                                                mrcp_session_t *session,
@@ -650,19 +765,33 @@ MRCP_DECLARE(mpf_termination_t*) mrcp_application_source_termination_create(
                                                                                mpf_codec_descriptor_t *codec_descriptor,
                                                                                void *obj)
 {
+       mpf_stream_capabilities_t *capabilities;
        mpf_audio_stream_t *audio_stream;
+
+       capabilities = mpf_source_stream_capabilities_create(session->pool);
+       if(codec_descriptor) {
+               mpf_codec_capabilities_add(
+                                               &capabilities->codecs,
+                                               mpf_sample_rate_mask_get(codec_descriptor->sampling_rate),
+                                               codec_descriptor->name.buf);
+       }
+       else {
+               mpf_codec_default_capabilities_add(&capabilities->codecs);
+       }
+
        /* create audio stream */
        audio_stream = mpf_audio_stream_create(
                        obj,                  /* object to associate */
                        stream_vtable,        /* virtual methods table of audio stream */
-                       STREAM_MODE_RECEIVE,  /* stream mode/direction */
+                       capabilities,         /* stream capabilities */
                        session->pool);       /* memory pool to allocate memory from */
 
-       if(codec_descriptor) {
-               mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
-               audio_stream->rx_codec = mpf_codec_manager_codec_get(client_session->codec_manager,codec_descriptor,session->pool);
+       if(!audio_stream) {
+               return NULL;
        }
 
+       audio_stream->rx_descriptor = codec_descriptor;
+
        /* create raw termination */
        return mpf_raw_termination_create(
                        NULL,                 /* no object to associate */
@@ -677,19 +806,32 @@ MRCP_DECLARE(mpf_termination_t*) mrcp_application_sink_termination_create(
                                                                                mpf_codec_descriptor_t *codec_descriptor,
                                                                                void *obj)
 {
+       mpf_stream_capabilities_t *capabilities;
        mpf_audio_stream_t *audio_stream;
+
+       capabilities = mpf_sink_stream_capabilities_create(session->pool);
+       if(codec_descriptor) {
+               mpf_codec_capabilities_add(
+                                               &capabilities->codecs,
+                                               mpf_sample_rate_mask_get(codec_descriptor->sampling_rate),
+                                               codec_descriptor->name.buf);
+       }
+       else {
+               mpf_codec_default_capabilities_add(&capabilities->codecs);
+       }
+
        /* create audio stream */
        audio_stream = mpf_audio_stream_create(
                        obj,                  /* object to associate */
                        stream_vtable,        /* virtual methods table of audio stream */
-                       STREAM_MODE_SEND,     /* stream mode/direction */
+                       capabilities,         /* stream capabilities */
                        session->pool);       /* memory pool to allocate memory from */
-
-       if(codec_descriptor) {
-               mrcp_client_session_t *client_session = (mrcp_client_session_t*)session;
-               audio_stream->tx_codec = mpf_codec_manager_codec_get(client_session->codec_manager,codec_descriptor,session->pool);
+       if(!audio_stream) {
+               return NULL;
        }
 
+       audio_stream->tx_descriptor = codec_descriptor;
+
        /* create raw termination */
        return mpf_raw_termination_create(
                        NULL,                 /* no object to associate */
@@ -793,6 +935,9 @@ static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg)
                                case CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE:
                                        mrcp_client_on_message_receive(data->channel,data->message);
                                        break;
+                               case CONNECTION_AGENT_TASK_MSG_DISCONNECT:
+                                       mrcp_client_on_disconnect(data->channel);
+                                       break;
                                default:
                                        break;
                        }
@@ -800,9 +945,9 @@ static apt_bool_t mrcp_client_msg_process(apt_task_t *task, apt_task_msg_t *msg)
                }
                case MRCP_CLIENT_MEDIA_TASK_MSG:
                {
-                       mpf_message_t *mpf_message = (mpf_message_t*) msg->data;
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message [%d]", mpf_message->command_id);
-                       mrcp_client_mpf_message_process(mpf_message);
+                       mpf_message_container_t *container = (mpf_message_container_t*) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message");
+                       mrcp_client_mpf_message_process(container);
                        break;
                }
                case MRCP_CLIENT_APPLICATION_TASK_MSG:
@@ -981,3 +1126,14 @@ static apt_bool_t mrcp_client_message_signal(mrcp_control_channel_t *channel, mr
                                                                mrcp_message,
                                                                TRUE);
 }
+
+static apt_bool_t mrcp_client_disconnect_signal(mrcp_control_channel_t *channel)
+{
+       return mrcp_client_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_DISCONNECT,
+                                                               channel->agent,
+                                                               channel,
+                                                               NULL,
+                                                               NULL,
+                                                               TRUE);
+}
index 0832fc85b9e5b0499d2935e59b2cb86cd9a1350a..845694c5babd47e1344daf87f2cd02d2a5b6ccdc 100644 (file)
  */
 
 #include "mrcp_client_session.h"
-#include "mrcp_resource.h"
 #include "mrcp_resource_factory.h"
+#include "mrcp_resource.h"
 #include "mrcp_sig_agent.h"
 #include "mrcp_client_connection.h"
 #include "mrcp_session.h"
 #include "mrcp_session_descriptor.h"
 #include "mrcp_control_descriptor.h"
 #include "mrcp_message.h"
-#include "mpf_termination.h"
+#include "mpf_termination_factory.h"
 #include "mpf_stream.h"
-#include "mpf_engine.h"
-#include "mpf_user.h"
 #include "apt_consumer_task.h"
 #include "apt_obj_list.h"
 #include "apt_log.h"
@@ -38,7 +36,7 @@ void mrcp_client_session_remove(mrcp_client_t *client, mrcp_client_session_t *se
 static apt_bool_t mrcp_client_session_offer_send(mrcp_client_session_t *session);
 
 static apt_bool_t mrcp_app_session_terminate_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status);
-static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status, apt_bool_t process_pending_requests);
+static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, apt_bool_t process_pending_requests);
 static apt_bool_t mrcp_app_sig_event_raise(mrcp_client_session_t *session, mrcp_channel_t *channel);
 static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *mrcp_message);
 static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, const mrcp_app_message_t *app_message);
@@ -49,12 +47,45 @@ static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *ses
 
 static mrcp_channel_t* mrcp_client_channel_find_by_name(mrcp_client_session_t *session, const apt_str_t *resource_name);
 
-static apt_bool_t mrcp_client_mpf_request_send(
-                                               mpf_engine_t *engine, 
-                                               mpf_command_type_e command_id, 
-                                               mpf_context_t *context, 
-                                               mpf_termination_t *termination, 
-                                               void *descriptor);
+static APR_INLINE mrcp_version_e mrcp_session_version_get(mrcp_client_session_t *session)
+{
+       return session->base.signaling_agent->mrcp_version;
+}
+
+static APR_INLINE void mrcp_client_session_state_set(mrcp_client_session_t *session, mrcp_client_session_state_e state)
+{
+       if(session->subrequest_count != 0) {
+               /* error case */
+               session->subrequest_count = 0;
+       }
+       session->state = state;
+}
+
+static APR_INLINE void mrcp_client_session_subrequest_add(mrcp_client_session_t *session)
+{
+       session->subrequest_count++;
+}
+
+static APR_INLINE apt_bool_t mrcp_client_session_subrequest_remove(mrcp_client_session_t *session)
+{
+       if(!session->subrequest_count) {
+               /* error case */
+               return FALSE;
+       }
+
+       session->subrequest_count--;
+       return (session->subrequest_count ? FALSE : TRUE);
+}
+
+static mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_message_t *app_request, mrcp_sig_status_code_e status, apr_pool_t *pool)
+{
+       mrcp_app_message_t *app_response = apr_palloc(pool,sizeof(mrcp_app_message_t));
+       *app_response = *app_request;
+       app_response->sig_message.message_type = MRCP_SIG_MESSAGE_TYPE_RESPONSE;
+       app_response->sig_message.status = status;
+       return app_response;
+}
+
 
 mrcp_client_session_t* mrcp_client_session_create(mrcp_application_t *application, void *obj)
 {
@@ -73,37 +104,39 @@ mrcp_client_session_t* mrcp_client_session_create(mrcp_application_t *applicatio
        session->answer = NULL;
        session->active_request = NULL;
        session->request_queue = apt_list_create(pool);
-       session->offer_flag_count = 0;
-       session->answer_flag_count = 0;
-       session->terminate_flag_count = 0;
+       session->mpf_task_msg = NULL;
+       session->subrequest_count = 0;
+       session->state = SESSION_STATE_NONE;
+       session->status = MRCP_SIG_STATUS_CODE_SUCCESS;
        return session;
 }
 
 mrcp_channel_t* mrcp_client_channel_create(
-                                       mrcp_session_t *session, 
-                                       mrcp_resource_id resource_id, 
-                                       mpf_termination_t *termination, 
-                                       mpf_rtp_termination_descriptor_t *rtp_descriptor, 
+                                       mrcp_session_t *session,
+                                       mrcp_resource_t *resource,
+                                       mpf_termination_t *termination,
+                                       mpf_rtp_termination_descriptor_t *rtp_descriptor,
                                        void *obj)
 {
        mrcp_channel_t *channel = apr_palloc(session->pool,sizeof(mrcp_channel_t));
        channel->pool = session->pool;
        channel->obj = obj;
        channel->session = session;
-       channel->resource_id = resource_id;
-       channel->resource_name = NULL;
        channel->control_channel = NULL;
        channel->termination = termination;
        channel->rtp_termination_slot = NULL;
-       channel->resource = NULL;
+       channel->resource = resource;
        channel->waiting_for_channel = FALSE;
        channel->waiting_for_termination = FALSE;
 
        if(rtp_descriptor) {
-               channel->rtp_termination_slot = apr_palloc(session->pool,sizeof(rtp_termination_slot_t));
-               channel->rtp_termination_slot->descriptor = rtp_descriptor;
-               channel->rtp_termination_slot->termination = NULL;
-               channel->rtp_termination_slot->waiting = FALSE;
+               rtp_termination_slot_t *termination_slot = apr_palloc(session->pool,sizeof(rtp_termination_slot_t));
+               termination_slot->descriptor = rtp_descriptor;
+               termination_slot->termination = NULL;
+               termination_slot->waiting = FALSE;
+               termination_slot->channel = channel;
+               termination_slot->id = 0;
+               channel->rtp_termination_slot = termination_slot;
        }
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(session));
        return channel;
@@ -111,15 +144,14 @@ mrcp_channel_t* mrcp_client_channel_create(
 
 apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mrcp_session_descriptor_t *descriptor)
 {
-       mrcp_sig_status_code_e status_code = MRCP_SIG_STATUS_CODE_SUCCESS;
        if(!session->offer) {
                return FALSE;
        }
        if(!descriptor) {
                apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Answer "APT_PTRSID_FMT" [null descriptor]", MRCP_SESSION_PTRSID(&session->base));
-               status_code = MRCP_SIG_STATUS_CODE_FAILURE;
+               session->status = MRCP_SIG_STATUS_CODE_FAILURE;
                /* raise app response */
-               return mrcp_app_sig_response_raise(session,status_code,TRUE);
+               return mrcp_app_sig_response_raise(session,TRUE);
        }
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Answer "APT_PTRSID_FMT" [c:%d a:%d v:%d]",
@@ -128,9 +160,20 @@ apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mr
                descriptor->audio_media_arr->nelts,
                descriptor->video_media_arr->nelts);
 
-       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+       mrcp_client_session_state_set(session,SESSION_STATE_PROCESSING_ANSWER);
+       if(session->context) {
+               /* first, reset/destroy existing associations and topology */
+               if(mpf_engine_topology_message_add(
+                                       session->profile->media_engine,
+                                       MPF_RESET_ASSOCIATIONS,session->context,
+                                       &session->mpf_task_msg) == TRUE){
+                       mrcp_client_session_subrequest_add(session);
+               }
+       }
+
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
                if(mrcp_client_resource_answer_process(session,descriptor) != TRUE) {
-                       status_code = MRCP_SIG_STATUS_CODE_FAILURE;
+                       session->status = MRCP_SIG_STATUS_CODE_FAILURE;
                }
        }
        else {
@@ -138,12 +181,24 @@ apt_bool_t mrcp_client_session_answer_process(mrcp_client_session_t *session, mr
                mrcp_client_av_media_answer_process(session,descriptor);
        }
 
+       if(session->context) {
+               /* apply topology based on assigned associations */
+               if(mpf_engine_topology_message_add(
+                                       session->profile->media_engine,
+                                       MPF_APPLY_TOPOLOGY,session->context,
+                                       &session->mpf_task_msg) == TRUE) {
+                       mrcp_client_session_subrequest_add(session);
+               }
+
+               mpf_engine_message_send(session->profile->media_engine,&session->mpf_task_msg);
+       }
+
        /* store received answer */
        session->answer = descriptor;
 
-       if(!session->answer_flag_count) {
+       if(!session->subrequest_count) {
                /* raise app response */
-               mrcp_app_sig_response_raise(session,status_code,TRUE);
+               mrcp_app_sig_response_raise(session,TRUE);
        }
 
        return TRUE;
@@ -153,11 +208,7 @@ apt_bool_t mrcp_client_session_terminate_response_process(mrcp_client_session_t
 {
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Terminate Response "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
 
-       if(session->terminate_flag_count) {
-               session->terminate_flag_count--;
-       }
-
-       if(!session->terminate_flag_count) {
+       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
                mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS);
        }
        return TRUE;
@@ -165,15 +216,33 @@ apt_bool_t mrcp_client_session_terminate_response_process(mrcp_client_session_t
 
 apt_bool_t mrcp_client_session_terminate_event_process(mrcp_client_session_t *session)
 {
+       if(session->state == SESSION_STATE_TERMINATING) {
+               /* session termination request has been sent, still waiting for the response,
+                  all the events must be ignored at this stage */
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unexpected Event! "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               return FALSE;
+       }
+       
        if(session->active_request) {
                /* raise app response */
-               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_TERMINATE,FALSE);
+               session->status = MRCP_SIG_STATUS_CODE_TERMINATE;
+               mrcp_app_sig_response_raise(session,FALSE);
 
-               /* cancel remaing requests (if any) */
+               /* cancel remaing requests, but do process session termination request (if any) */
                do {
                        session->active_request = apt_list_pop_front(session->request_queue);
                        if(session->active_request) {
-                               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_CANCEL,FALSE);
+                               const mrcp_app_message_t *app_message = session->active_request;
+                               if(app_message->message_type == MRCP_APP_MESSAGE_TYPE_SIGNALING &&
+                                       app_message->sig_message.command_id == MRCP_SIG_COMMAND_SESSION_TERMINATE) {
+                                       /* process session termination */
+                                       mrcp_app_request_dispatch(session,app_message);
+                                       break;
+                               }
+
+                               /* cancel pending request */
+                               session->status = MRCP_SIG_STATUS_CODE_CANCEL;
+                               mrcp_app_sig_response_raise(session,FALSE);
                        }
                }
                while(session->active_request);
@@ -203,27 +272,23 @@ apt_bool_t mrcp_client_session_discover_response_process(mrcp_client_session_t *
 
        if(!descriptor) {
                /* raise app response */
-               return mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_FAILURE,TRUE);
+               session->status = MRCP_SIG_STATUS_CODE_FAILURE;
+               return mrcp_app_sig_response_raise(session,TRUE);
        }
 
-       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
                if(descriptor->resource_state == TRUE) {
                        mrcp_control_descriptor_t *control_media;
                        if(!session->answer) {
                                session->answer = descriptor;
                        }
-                       control_media = apr_palloc(session->base.pool,sizeof(mrcp_control_descriptor_t));
-                       mrcp_control_descriptor_init(control_media);
+                       control_media = mrcp_control_descriptor_create(session->base.pool);
                        control_media->id = mrcp_session_control_media_add(session->answer,control_media);
                        control_media->resource_name = descriptor->resource_name;
                }
        }
 
-       if(session->answer_flag_count) {
-               session->answer_flag_count--;
-       }
-
-       if(!session->answer_flag_count) {
+       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
                mrcp_app_message_t *response;
                response = mrcp_client_app_response_create(session->active_request,MRCP_SIG_STATUS_CODE_SUCCESS,session->base.pool);
                response->descriptor = session->answer;
@@ -247,12 +312,9 @@ apt_bool_t mrcp_client_on_channel_add(mrcp_channel_t *channel, mrcp_control_desc
                return FALSE;
        }
        channel->waiting_for_channel = FALSE;
-       if(session->offer_flag_count) {
-               session->offer_flag_count--;
-               if(!session->offer_flag_count) {
-                       /* send offer to server */
-                       mrcp_client_session_offer_send(session);
-               }
+       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+               /* send offer to server */
+               mrcp_client_session_offer_send(session);
        }
        return TRUE;
 }
@@ -265,15 +327,12 @@ apt_bool_t mrcp_client_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d
                return FALSE;
        }
        channel->waiting_for_channel = FALSE;
-       if(session->answer_flag_count) {
-               session->answer_flag_count--;
-               if(!session->answer_flag_count) {
-                       /* raise app response */
-                       mrcp_app_sig_response_raise(
-                               session,
-                               status == TRUE ? MRCP_SIG_STATUS_CODE_SUCCESS : MRCP_SIG_STATUS_CODE_FAILURE,
-                               TRUE);
+       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+               /* raise app response */
+               if(status != TRUE) {
+                       session->status = MRCP_SIG_STATUS_CODE_FAILURE;
                }
+               mrcp_app_sig_response_raise(session,TRUE);
        }
        return TRUE;
 }
@@ -286,13 +345,10 @@ apt_bool_t mrcp_client_on_channel_remove(mrcp_channel_t *channel, apt_bool_t sta
                return FALSE;
        }
        channel->waiting_for_channel = FALSE;
-       if(session->terminate_flag_count) {
-               session->terminate_flag_count--;
-               if(!session->terminate_flag_count) {
+       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
                        mrcp_app_session_terminate_raise(
                                session,
                                status == TRUE ? MRCP_SIG_STATUS_CODE_SUCCESS : MRCP_SIG_STATUS_CODE_FAILURE);
-               }
        }
        return TRUE;
 }
@@ -303,6 +359,12 @@ apt_bool_t mrcp_client_on_message_receive(mrcp_channel_t *channel, mrcp_message_
        return mrcp_app_control_message_raise(session,channel,message);
 }
 
+apt_bool_t mrcp_client_on_disconnect(mrcp_channel_t *channel)
+{
+       mrcp_client_session_t *session = (mrcp_client_session_t*)channel->session;
+       return mrcp_client_session_terminate_event_process(session);
+}
+
 mrcp_app_message_t* mrcp_client_app_signaling_request_create(mrcp_sig_command_e command_id, apr_pool_t *pool)
 {
        mrcp_app_message_t *app_message = apr_palloc(pool,sizeof(mrcp_app_message_t));
@@ -328,15 +390,6 @@ mrcp_app_message_t* mrcp_client_app_control_message_create(apr_pool_t *pool)
        return app_message;
 }
 
-mrcp_app_message_t* mrcp_client_app_response_create(const mrcp_app_message_t *app_request, mrcp_sig_status_code_e status, apr_pool_t *pool)
-{
-       mrcp_app_message_t *app_response = apr_palloc(pool,sizeof(mrcp_app_message_t));
-       *app_response = *app_request;
-       app_response->sig_message.message_type = MRCP_SIG_MESSAGE_TYPE_RESPONSE;
-       app_response->sig_message.status = status;
-       return app_response;
-}
-
 apt_bool_t mrcp_client_app_message_process(mrcp_app_message_t *app_message)
 {
        mrcp_client_session_t *session = (mrcp_client_session_t*)app_message->session;
@@ -376,7 +429,7 @@ static apt_bool_t mrcp_app_session_terminate_raise(mrcp_client_session_t *sessio
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                if(channel->control_channel) {
@@ -387,10 +440,13 @@ static apt_bool_t mrcp_app_session_terminate_raise(mrcp_client_session_t *sessio
 
        mrcp_client_session_remove(session->application->client,session);
        /* raise app response */
-       return mrcp_app_sig_response_raise(session,status,FALSE);
+       if(status != MRCP_SIG_STATUS_CODE_SUCCESS) {
+               session->status = status;
+       }
+       return mrcp_app_sig_response_raise(session,FALSE);
 }
 
-static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, mrcp_sig_status_code_e status, apt_bool_t process_pending_requests)
+static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, apt_bool_t process_pending_requests)
 {
        mrcp_app_message_t *response;
        const mrcp_app_message_t *request = session->active_request;
@@ -398,12 +454,12 @@ static apt_bool_t mrcp_app_sig_response_raise(mrcp_client_session_t *session, mr
                return FALSE;
        }
        session->active_request = NULL;
-       response = mrcp_client_app_response_create(request,status,session->base.pool);
+       response = mrcp_client_app_response_create(request,session->status,session->base.pool);
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Raise App Response "APT_PTRSID_FMT" [%d] %s [%d]", 
                MRCP_SESSION_PTRSID(&session->base),
                response->sig_message.command_id,
-               status == MRCP_SIG_STATUS_CODE_SUCCESS ? "SUCCESS" : "FAILURE",
-               status);
+               session->status == MRCP_SIG_STATUS_CODE_SUCCESS ? "SUCCESS" : "FAILURE",
+               session->status);
        session->application->handler(response);
 
        if(process_pending_requests) {
@@ -468,8 +524,9 @@ static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session,
 static apt_bool_t mrcp_client_channel_find(mrcp_client_session_t *session, mrcp_channel_t *channel, int *index)
 {
        int i;
+       mrcp_channel_t *existing_channel;
        for(i=0; i<session->channels->nelts; i++) {
-               mrcp_channel_t *existing_channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               existing_channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(existing_channel == channel) {
                        if(index) {
                                *index = i;
@@ -485,7 +542,7 @@ static rtp_termination_slot_t* mrcp_client_rtp_termination_find(mrcp_client_sess
        int i;
        rtp_termination_slot_t *slot;
        for(i=0; i<session->terminations->nelts; i++) {
-               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
+               slot = &APR_ARRAY_IDX(session->terminations,i,rtp_termination_slot_t);
                if(slot && slot->termination == termination) {
                        return slot;
                }
@@ -493,25 +550,12 @@ static rtp_termination_slot_t* mrcp_client_rtp_termination_find(mrcp_client_sess
        return NULL;
 }
 
-static int mrcp_client_audio_media_find_by_mid(const mrcp_session_descriptor_t *descriptor, apr_size_t mid)
-{
-       int i;
-       mpf_rtp_media_descriptor_t *media;
-       for(i=0; i<descriptor->audio_media_arr->nelts; i++) {
-               media = ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[i];
-               if(media->mid == mid) {
-                       return i;
-               }
-       }
-       return -1;
-}
-
 static mrcp_channel_t* mrcp_client_channel_termination_find(mrcp_client_session_t *session, mpf_termination_t *termination)
 {
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                if(channel->termination == termination) {
@@ -526,10 +570,10 @@ static mrcp_channel_t* mrcp_client_channel_find_by_name(mrcp_client_session_t *s
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
-               if(!channel) continue;
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
+               if(!channel || !channel->resource) continue;
 
-               if(apt_string_compare(channel->resource_name,resource_name) == TRUE) {
+               if(apt_string_compare(&channel->resource->name,resource_name) == TRUE) {
                        return channel;
                }
        }
@@ -548,9 +592,9 @@ static apt_bool_t mrcp_client_message_send(mrcp_client_session_t *session, mrcp_
 
        message->channel_id.session_id = session->base.id;
        message->start_line.request_id = ++session->base.last_request_id;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCP Request "APT_PTRSIDRES_FMT" [%d]",
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send MRCP Request "APT_PTRSIDRES_FMT" [%"MRCP_REQUEST_ID_FMT"]",
                                        MRCP_SESSION_PTRSID(&session->base),
-                                       channel->resource_name->buf,
+                                       channel->resource->name.buf,
                                        message->start_line.request_id);
 
        if(channel->control_channel) {
@@ -571,48 +615,47 @@ static apt_bool_t mrcp_client_channel_modify(mrcp_client_session_t *session, mrc
        if(!session->offer) {
                return FALSE;
        }
-       if(!channel->resource_name) {
+       if(!channel->resource) {
                return FALSE;
        }
 
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Modify Control Channel "APT_PTRSIDRES_FMT" [%d]",
                                        MRCP_SESSION_PTRSID(&session->base),
-                                       channel->resource_name->buf,
+                                       channel->resource->name.buf,
                                        enable);
        if(mrcp_client_channel_find(session,channel,&index) == TRUE) {
                mrcp_control_descriptor_t *control_media = mrcp_session_control_media_get(session->offer,(apr_size_t)index);
                if(control_media) {
-                       control_media->port = (enable == TRUE) ? 9 : 0;
-                       if(channel->termination && channel->termination->audio_stream) {
-                               int i = mrcp_client_audio_media_find_by_mid(session->offer,control_media->cmid);
-                               if(i >= 0) {
-                                       mpf_stream_mode_e mode = mpf_stream_mode_negotiate(channel->termination->audio_stream->mode);
-                                       mpf_rtp_media_descriptor_t *audio_media = mrcp_session_audio_media_get(session->offer,(apr_size_t)i);
-                                       if(audio_media) {
-                                               if(enable == TRUE) {
-                                                       audio_media->mode |= mode;
-                                               }
-                                               else {
-                                                       audio_media->mode &= ~mode;
-                                               }
-                                               audio_media->base.state = (audio_media->mode != STREAM_MODE_NONE) ? MPF_MEDIA_ENABLED : MPF_MEDIA_DISABLED;
-                                       }
+                       control_media->port = (enable == TRUE) ? TCP_DISCARD_PORT : 0;
+               }
+               if(channel->termination && channel->rtp_termination_slot) {
+                       mpf_audio_stream_t *audio_stream = mpf_termination_audio_stream_get(
+                                                                                                               channel->termination);
+                       mpf_rtp_media_descriptor_t *audio_media = mrcp_session_audio_media_get(
+                                                                                                               session->offer,
+                                                                                                               channel->rtp_termination_slot->id);
+                       if(audio_media && audio_stream) {
+                               mpf_stream_direction_e direction = mpf_stream_reverse_direction_get(audio_stream->direction);
+                               if(enable == TRUE) {
+                                       audio_media->direction |= direction;
+                               }
+                               else {
+                                       audio_media->direction &= ~direction;
                                }
+                               audio_media->state = (audio_media->direction != STREAM_DIRECTION_NONE) ? MPF_MEDIA_ENABLED : MPF_MEDIA_DISABLED;
                        }
                }
        }
 
-       session->offer->resource_name = *channel->resource_name;
+       session->offer->resource_name = channel->resource->name;
        session->offer->resource_state = enable;
        return mrcp_client_session_offer_send(session);
 }
 
 static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_channel_t *channel)
 {
-       mrcp_channel_t **channel_slot;
-       mrcp_control_descriptor_t *control_media;
        mpf_rtp_termination_descriptor_t *rtp_descriptor = NULL;
-       rtp_termination_slot_t *termination_slot;
+       rtp_termination_slot_t *slot;
        apr_pool_t *pool = session->base.pool;
        mrcp_profile_t *profile = session->profile;
        if(mrcp_client_channel_find(session,channel,NULL) == TRUE) {
@@ -622,93 +665,108 @@ static apt_bool_t mrcp_client_channel_add(mrcp_client_session_t *session, mrcp_c
 
        if(!session->offer) {
                session->offer = mrcp_session_descriptor_create(pool);
-               session->context = mpf_context_create(session,5,pool);
-       }
-       if(!channel->resource) {
-               channel->resource = mrcp_resource_get(profile->resource_factory,channel->resource_id);
-               if(!channel->resource) {
-                       return FALSE;
-               }
-               channel->resource_name = mrcp_resource_name_get(profile->resource_factory,channel->resource_id);
-               if(!channel->resource_name) {
-                       return FALSE;
-               }
        }
-       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
-               session->offer->resource_name = *channel->resource_name;
+       
+       mrcp_client_session_state_set(session,SESSION_STATE_GENERATING_OFFER);
+
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
+               session->offer->resource_name = channel->resource->name;
                session->offer->resource_state = TRUE;
        }
        else {
+               mrcp_control_descriptor_t *control_media;
                if(!channel->control_channel) {
                        channel->control_channel = mrcp_client_control_channel_create(profile->connection_agent,channel,pool);
                }
                control_media = mrcp_control_offer_create(pool);
                control_media->id = mrcp_session_control_media_add(session->offer,control_media);
-               control_media->cmid = session->offer->control_media_arr->nelts;
-               control_media->resource_name = *channel->resource_name;
+               mrcp_cmid_add(control_media->cmid_arr,session->offer->control_media_arr->nelts);
+               control_media->resource_name = channel->resource->name;
                if(mrcp_client_control_channel_add(channel->control_channel,control_media) == TRUE) {
                        channel->waiting_for_channel = TRUE;
-                       session->offer_flag_count++;
+                       mrcp_client_session_subrequest_add(session);
                }
        }
 
-       /* add to channel array */
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Add Control Channel "APT_PTRSIDRES_FMT,
                                        MRCP_SESSION_PTRSID(&session->base),
-                                       channel->resource_name->buf);
-       channel_slot = apr_array_push(session->channels);
-       *channel_slot = channel;
+                                       channel->resource->name.buf);
+       /* add control channel */
+       APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel;
+
+       /* add rtp termination slot */
+       slot = apr_array_push(session->terminations);
+       slot->waiting = FALSE;
+       slot->termination = NULL;
+       slot->descriptor = NULL;
+       slot->channel = channel;
+       slot->id = 0;
 
        if(channel->termination) {
-               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_ADD,session->context,channel->termination,NULL) == TRUE) {
-                       channel->waiting_for_termination = TRUE;
-                       session->offer_flag_count++;
-               }
-       }
+               /* media termination mode */
+               mpf_termination_t *termination;
+               mpf_audio_stream_t *audio_stream;
 
-       if(channel->rtp_termination_slot) {
-               rtp_descriptor = channel->rtp_termination_slot->descriptor;
-       }       
-       /* add to rtp termination array */
-       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-       termination_slot = apr_array_push(session->terminations);
-       termination_slot->waiting = FALSE;
-       termination_slot->termination = NULL;
-       termination_slot->descriptor = NULL;
-       if(rtp_descriptor) {
-               if(rtp_descriptor->audio.local) {
-                       session->offer->ip = rtp_descriptor->audio.local->base.ip;
-                       session->offer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
-                       rtp_descriptor->audio.local->base.id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
-                       rtp_descriptor->audio.local->mid = session->offer->audio_media_arr->nelts;
+               if(!session->context) {
+                       /* create media context first */
+                       session->context = mpf_engine_context_create(profile->media_engine,session,5,pool);
+               }
+               if(mpf_engine_termination_message_add(
+                               profile->media_engine,
+                               MPF_ADD_TERMINATION,session->context,channel->termination,NULL,
+                               &session->mpf_task_msg) == TRUE) {
+                       channel->waiting_for_termination = TRUE;
+                       mrcp_client_session_subrequest_add(session);
                }
-       }
-       else {
-               /* create rtp termination */
-               mpf_termination_t *termination = mpf_termination_create(profile->rtp_termination_factory,session,session->base.pool);
-               termination_slot->termination = termination;
 
                /* initialize rtp descriptor */
                rtp_descriptor = apr_palloc(pool,sizeof(mpf_rtp_termination_descriptor_t));
                mpf_rtp_termination_descriptor_init(rtp_descriptor);
-               if(channel->termination && channel->termination->audio_stream) {
+               audio_stream = mpf_termination_audio_stream_get(channel->termination);
+               if(audio_stream) {
                        mpf_rtp_media_descriptor_t *media;
                        media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                        mpf_rtp_media_descriptor_init(media);
-                       media->base.state = MPF_MEDIA_ENABLED;
-                       media->mode = mpf_stream_mode_negotiate(channel->termination->audio_stream->mode);
+                       media->state = MPF_MEDIA_ENABLED;
+                       media->direction = mpf_stream_reverse_direction_get(audio_stream->direction);
                        rtp_descriptor->audio.local = media;
                }
+
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+               /* create rtp termination */
+               termination = mpf_termination_create(profile->rtp_termination_factory,session,pool);
+               slot->termination = termination;
+
                /* send add termination request (add to media context) */
-               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_ADD,session->context,termination,rtp_descriptor) == TRUE) {
-                       termination_slot->waiting = TRUE;
-                       session->offer_flag_count++;
+               if(mpf_engine_termination_message_add(
+                               profile->media_engine,
+                               MPF_ADD_TERMINATION,session->context,termination,rtp_descriptor,
+                               &session->mpf_task_msg) == TRUE) {
+                       slot->waiting = TRUE;
+                       mrcp_client_session_subrequest_add(session);
                }
+               mpf_engine_message_send(profile->media_engine,&session->mpf_task_msg);
+       }
+       else {
+               /* bypass media mode */
+               if(channel->rtp_termination_slot) {
+                       rtp_descriptor = channel->rtp_termination_slot->descriptor;
+                       if(rtp_descriptor) {
+                               if(rtp_descriptor->audio.local) {
+                                       session->offer->ip = rtp_descriptor->audio.local->ip;
+                                       session->offer->ext_ip = rtp_descriptor->audio.local->ext_ip;
+                                       rtp_descriptor->audio.local->id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
+                                       rtp_descriptor->audio.local->mid = session->offer->audio_media_arr->nelts;
+                                       slot->id = session->offer->audio_media_arr->nelts - 1;
+                               }
+                       }
+               }       
        }
-       termination_slot->descriptor = rtp_descriptor;
-       channel->rtp_termination_slot = termination_slot;
 
-       if(!session->offer_flag_count) {
+       slot->descriptor = rtp_descriptor;
+       channel->rtp_termination_slot = slot;
+
+       if(!session->subrequest_count) {
                /* send offer to server */
                mrcp_client_session_offer_send(session);
        }
@@ -733,10 +791,21 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session)
        
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Session "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
        profile = session->profile;
+
+       mrcp_client_session_state_set(session,SESSION_STATE_TERMINATING);
+       if(session->context) {
+               /* first destroy existing topology */
+               if(mpf_engine_topology_message_add(
+                                       session->profile->media_engine,
+                                       MPF_DESTROY_TOPOLOGY,session->context,
+                                       &session->mpf_task_msg) == TRUE){
+                       mrcp_client_session_subrequest_add(session);
+               }
+       }
        /* remove existing control channels */
        for(i=0; i<session->channels->nelts; i++) {
                /* get existing channel */
-               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                if(channel->control_channel) {
@@ -744,37 +813,45 @@ static apt_bool_t mrcp_client_session_terminate(mrcp_client_session_t *session)
                        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
                        if(mrcp_client_control_channel_remove(channel->control_channel) == TRUE) {
                                channel->waiting_for_channel = TRUE;
-                               session->terminate_flag_count++;
+                               mrcp_client_session_subrequest_add(session);
                        }
                }
 
-               if(channel->termination) {              
-                       /* send subtract termination request */
-                       if(channel->termination) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Channel Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-                               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_SUBTRACT,session->context,channel->termination,NULL) == TRUE) {
-                                       channel->waiting_for_termination = TRUE;
-                                       session->terminate_flag_count++;
-                               }
+               /* send subtract termination request */
+               if(channel->termination) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Channel Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                       if(mpf_engine_termination_message_add(
+                                       profile->media_engine,
+                                       MPF_SUBTRACT_TERMINATION,session->context,channel->termination,NULL,
+                                       &session->mpf_task_msg) == TRUE) {
+                               channel->waiting_for_termination = TRUE;
+                               mrcp_client_session_subrequest_add(session);
                        }
                }
        }
 
-       /* subtract existing terminations */
-       for(i=0; i<session->terminations->nelts; i++) {
-               /* get existing termination */
-               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
-               if(!slot || !slot->termination) continue;
+       if(session->context) {
+               /* subtract existing terminations */
+               for(i=0; i<session->terminations->nelts; i++) {
+                       /* get existing termination */
+                       slot = &APR_ARRAY_IDX(session->terminations,i,rtp_termination_slot_t);
+                       if(!slot || !slot->termination) continue;
 
-               /* send subtract termination request */
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-               if(mrcp_client_mpf_request_send(profile->media_engine,MPF_COMMAND_SUBTRACT,session->context,slot->termination,NULL) == TRUE) {
-                       slot->waiting = TRUE;
-                       session->terminate_flag_count++;
+                       /* send subtract termination request */
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                       if(mpf_engine_termination_message_add(
+                                       profile->media_engine,
+                                       MPF_SUBTRACT_TERMINATION,session->context,slot->termination,NULL,
+                                       &session->mpf_task_msg) == TRUE) {
+                               slot->waiting = TRUE;
+                               mrcp_client_session_subrequest_add(session);
+                       }
                }
+
+               mpf_engine_message_send(profile->media_engine,&session->mpf_task_msg);
        }
 
-       session->terminate_flag_count++;
+       mrcp_client_session_subrequest_add(session);
        mrcp_session_terminate_request(&session->base);
        return TRUE;
 }
@@ -785,34 +862,37 @@ static apt_bool_t mrcp_client_resource_discover(mrcp_client_session_t *session)
        
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Resource Discovery Request "APT_PTR_FMT, MRCP_SESSION_PTR(&session->base));
        session->answer = NULL;
-       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
-               const apt_str_t *resource_name;
+       mrcp_client_session_state_set(session,SESSION_STATE_DISCOVERING);
+
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
+               mrcp_resource_t *resource;
                mrcp_resource_id i;
 
                for(i=0; i<MRCP_RESOURCE_TYPE_COUNT; i++) {
-                       resource_name = mrcp_resource_name_get(session->profile->resource_factory,i);
-                       if(!resource_name) continue;
+                       resource = mrcp_resource_get(session->profile->resource_factory,i);
+                       if(!resource) continue;
                
                        descriptor = mrcp_session_descriptor_create(session->base.pool);
-                       apt_string_copy(&descriptor->resource_name,resource_name,session->base.pool);
+                       apt_string_copy(&descriptor->resource_name,&resource->name,session->base.pool);
                        if(mrcp_session_discover_request(&session->base,descriptor) == TRUE) {
-                               session->answer_flag_count++;
+                               mrcp_client_session_subrequest_add(session);
                        }
                }
        }
        else {
                if(mrcp_session_discover_request(&session->base,descriptor) == TRUE) {
-                       session->answer_flag_count++;
+                       mrcp_client_session_subrequest_add(session);
                }
        }
 
-       if(session->answer_flag_count == 0) {
-               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_FAILURE,TRUE);
+       if(session->subrequest_count == 0) {
+               session->status = MRCP_SIG_STATUS_CODE_FAILURE;
+               mrcp_app_sig_response_raise(session,TRUE);
        }
        return TRUE;
 }
 
-static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session, const mpf_message_t *mpf_message)
 {
        rtp_termination_slot_t *termination_slot;
        if(!session) {
@@ -828,17 +908,15 @@ static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session,
                termination_slot->waiting = FALSE;
                rtp_descriptor = mpf_message->descriptor;
                if(rtp_descriptor->audio.local) {
-                       session->offer->ip = rtp_descriptor->audio.local->base.ip;
-                       session->offer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
-                       rtp_descriptor->audio.local->base.id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
+                       session->offer->ip = rtp_descriptor->audio.local->ip;
+                       session->offer->ext_ip = rtp_descriptor->audio.local->ext_ip;
+                       rtp_descriptor->audio.local->id = mrcp_session_audio_media_add(session->offer,rtp_descriptor->audio.local);
                        rtp_descriptor->audio.local->mid = session->offer->audio_media_arr->nelts;
+                       termination_slot->id = session->offer->audio_media_arr->nelts - 1;
                }
-               if(session->offer_flag_count) {
-                       session->offer_flag_count--;
-                       if(!session->offer_flag_count) {
-                               /* send offer to server */
-                               mrcp_client_session_offer_send(session);
-                       }
+               if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                       /* send offer to server */
+                       mrcp_client_session_offer_send(session);
                }
        }
        else {
@@ -846,19 +924,16 @@ static apt_bool_t mrcp_client_on_termination_add(mrcp_client_session_t *session,
                mrcp_channel_t *channel = mrcp_client_channel_termination_find(session,mpf_message->termination);
                if(channel && channel->waiting_for_termination == TRUE) {
                        channel->waiting_for_termination = FALSE;
-                       if(session->offer_flag_count) {
-                               session->offer_flag_count--;
-                               if(!session->offer_flag_count) {
-                                       /* send offer to server */
-                                       mrcp_client_session_offer_send(session);
-                               }
+                       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                               /* send offer to server */
+                               mrcp_client_session_offer_send(session);
                        }
                }
        }
        return TRUE;
 }
 
-static apt_bool_t mrcp_client_on_termination_modify(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+static apt_bool_t mrcp_client_on_termination_modify(mrcp_client_session_t *session, const mpf_message_t *mpf_message)
 {
        rtp_termination_slot_t *termination_slot;
        if(!session) {
@@ -873,25 +948,21 @@ static apt_bool_t mrcp_client_on_termination_modify(mrcp_client_session_t *sessi
                termination_slot->waiting = FALSE;
                termination_slot->descriptor = mpf_message->descriptor;;
 
-               if(session->offer_flag_count) {
-                       session->offer_flag_count--;
-                       if(!session->offer_flag_count) {
+               if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                       if(session->state == SESSION_STATE_GENERATING_OFFER) {
                                /* send offer to server */
                                mrcp_client_session_offer_send(session);
                        }
-               }
-               if(session->answer_flag_count) {
-                       session->answer_flag_count--;
-                       if(!session->answer_flag_count) {
+                       else if(session->state == SESSION_STATE_PROCESSING_ANSWER) {
                                /* raise app response */
-                               mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS,TRUE);
+                               mrcp_app_sig_response_raise(session,TRUE);
                        }
                }
        }
        return TRUE;
 }
 
-static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *session, mpf_message_t *mpf_message)
+static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *session, const mpf_message_t *mpf_message)
 {
        rtp_termination_slot_t *termination_slot;
        if(!session) {
@@ -904,11 +975,8 @@ static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *ses
                        return FALSE;
                }
                termination_slot->waiting = FALSE;
-               if(session->terminate_flag_count) {
-                       session->terminate_flag_count--;
-                       if(!session->terminate_flag_count) {
-                               mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS);
-                       }
+               if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                       mrcp_app_session_terminate_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS);
                }
        }
        else {
@@ -916,47 +984,65 @@ static apt_bool_t mrcp_client_on_termination_subtract(mrcp_client_session_t *ses
                mrcp_channel_t *channel = mrcp_client_channel_termination_find(session,mpf_message->termination);
                if(channel && channel->waiting_for_termination == TRUE) {
                        channel->waiting_for_termination = FALSE;
-                       if(session->terminate_flag_count) {
-                               session->terminate_flag_count--;
-                               if(!session->terminate_flag_count) {
-                                       /* raise app response */
-                                       mrcp_app_sig_response_raise(session,MRCP_SIG_STATUS_CODE_SUCCESS,TRUE);
-                               }
+                       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                               /* raise app response */
+                               mrcp_app_sig_response_raise(session,TRUE);
                        }
                }
        }
        return TRUE;
 }
 
-apt_bool_t mrcp_client_mpf_message_process(mpf_message_t *mpf_message)
+apt_bool_t mrcp_client_mpf_message_process(mpf_message_container_t *mpf_message_container)
 {
-       mrcp_client_session_t *session = NULL;
-       if(mpf_message->context) {
-               session = mpf_context_object_get(mpf_message->context);
-       }
-       if(!session) {
-               return FALSE;
-       }
-       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
-               switch(mpf_message->command_id) {
-                       case MPF_COMMAND_ADD:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-                               mrcp_client_on_termination_add(session,mpf_message);
-                               break;
-                       case MPF_COMMAND_MODIFY:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-                               mrcp_client_on_termination_modify(session,mpf_message);
-                               break;
-                       case MPF_COMMAND_SUBTRACT:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-                               mrcp_client_on_termination_subtract(session,mpf_message);
-                               break;
-                       default:
-                               break;
+       apr_size_t i;
+       mrcp_client_session_t *session;
+       const mpf_message_t *mpf_message;
+       for(i=0; i<mpf_message_container->count; i++) {
+               mpf_message = &mpf_message_container->messages[i];
+               if(mpf_message->context) {
+                       session = mpf_engine_context_object_get(mpf_message->context);
+               }
+               else {
+                       session = NULL;
+               }
+               if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+                       switch(mpf_message->command_id) {
+                               case MPF_ADD_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                                       mrcp_client_on_termination_add(session,mpf_message);
+                                       break;
+                               case MPF_MODIFY_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                                       mrcp_client_on_termination_modify(session,mpf_message);
+                                       break;
+                               case MPF_SUBTRACT_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
+                                       mrcp_client_on_termination_subtract(session,mpf_message);
+                                       break;
+                               case MPF_ADD_ASSOCIATION:
+                               case MPF_REMOVE_ASSOCIATION:
+                               case MPF_RESET_ASSOCIATIONS:
+                               case MPF_APPLY_TOPOLOGY:
+                               case MPF_DESTROY_TOPOLOGY:
+                                       if(mrcp_client_session_subrequest_remove(session) == TRUE) {
+                                               if(session->state == SESSION_STATE_GENERATING_OFFER) {
+                                                       /* send offer to server */
+                                                       mrcp_client_session_offer_send(session);
+                                               }
+                                               else if(session->state == SESSION_STATE_PROCESSING_ANSWER) {
+                                                       /* raise app response */
+                                                       mrcp_app_sig_response_raise(session,TRUE);
+                                               }
+                                       }
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
                }
-       }
-       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
        }
        return TRUE;
 }
@@ -998,7 +1084,7 @@ static apt_bool_t mrcp_client_control_media_answer_process(mrcp_client_session_t
        /* update existing control channels */
        for(i=0; i<count; i++) {
                /* get existing channel */
-               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                /* get control descriptor */
@@ -1007,7 +1093,7 @@ static apt_bool_t mrcp_client_control_media_answer_process(mrcp_client_session_t
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Control Channel "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
                if(mrcp_client_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) {
                        channel->waiting_for_channel = TRUE;
-                       session->answer_flag_count++;
+                       mrcp_client_session_subrequest_add(session);
                }
        }
        return TRUE;
@@ -1029,7 +1115,7 @@ static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *ses
                mpf_rtp_media_descriptor_t *remote_media;
                mpf_rtp_termination_descriptor_t *rtp_descriptor;
                /* get existing termination */
-               slot = &((rtp_termination_slot_t*)session->terminations->elts)[i];
+               slot = &APR_ARRAY_IDX(session->terminations,i,rtp_termination_slot_t);
                if(!slot) continue;
 
                remote_media = mrcp_session_audio_media_get(descriptor,i);
@@ -1045,9 +1131,20 @@ static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *ses
 
                        /* send modify termination request */
                        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Termination "APT_PTRSID_FMT, MRCP_SESSION_PTRSID(&session->base));
-                       if(mrcp_client_mpf_request_send(session->profile->media_engine,MPF_COMMAND_MODIFY,session->context,slot->termination,rtp_descriptor) == TRUE) {
+                       if(mpf_engine_termination_message_add(
+                                       session->profile->media_engine,
+                                       MPF_MODIFY_TERMINATION,session->context,slot->termination,rtp_descriptor,
+                                       &session->mpf_task_msg) == TRUE) {
                                slot->waiting = TRUE;
-                               session->answer_flag_count++;
+                               mrcp_client_session_subrequest_add(session);
+                       }
+                       if(slot->channel && slot->channel->termination) {
+                               if(mpf_engine_assoc_message_add(
+                                               session->profile->media_engine,
+                                               MPF_ADD_ASSOCIATION,session->context,slot->termination,slot->channel->termination,
+                                               &session->mpf_task_msg) == TRUE) {
+                                       mrcp_client_session_subrequest_add(session);
+                               }
                        }
                }
        }
@@ -1056,6 +1153,15 @@ static apt_bool_t mrcp_client_av_media_answer_process(mrcp_client_session_t *ses
 
 static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, const mrcp_app_message_t *app_message)
 {
+       if(session->state == SESSION_STATE_TERMINATING) {
+               /* no more requests are allowed, as session is being terminated!
+                  just return, it is horribly wrong and can crash anytime here */
+               apt_log(APT_LOG_MARK,APT_PRIO_ERROR,"Inappropriate Application Request "APT_PTRSID_FMT" [%d]",
+                       MRCP_SESSION_PTRSID(&session->base),
+                       app_message->sig_message.command_id);
+               return FALSE;
+       }
+       
        if(session->registered == FALSE) {
                session->base.signaling_agent = session->profile->signaling_agent;
                session->base.signaling_agent->create_client_session(&session->base);
@@ -1063,6 +1169,7 @@ static apt_bool_t mrcp_app_request_dispatch(mrcp_client_session_t *session, cons
                mrcp_client_session_add(session->application->client,session);
                session->registered = TRUE;
        }
+       session->status = MRCP_SIG_STATUS_CODE_SUCCESS;
        switch(app_message->message_type) {
                case MRCP_APP_MESSAGE_TYPE_SIGNALING:
                {
@@ -1192,29 +1299,3 @@ MRCP_DECLARE(apt_bool_t) mrcp_application_message_dispatch(const mrcp_app_messag
        }
        return status;
 }
-
-static apt_bool_t mrcp_client_mpf_request_send(
-                                               mpf_engine_t *engine, 
-                                               mpf_command_type_e command_id,
-                                               mpf_context_t *context, 
-                                               mpf_termination_t *termination, 
-                                               void *descriptor)
-{
-       apt_task_t *media_task;
-       apt_task_msg_t *msg;
-       mpf_message_t *mpf_message;
-       if(!engine) {
-               return FALSE;
-       }
-       media_task = mpf_task_get(engine);
-       msg = apt_task_msg_get(media_task);
-       msg->type = TASK_MSG_USER;
-       mpf_message = (mpf_message_t*) msg->data;
-
-       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
-       mpf_message->command_id = command_id;
-       mpf_message->context = context;
-       mpf_message->termination = termination;
-       mpf_message->descriptor = descriptor;
-       return apt_task_msg_signal(media_task,msg);
-}
index 3dfab1b17799b90696d7b0d347f0001a65afcdca..74bac2d06bc39e5320a18744e3f9cf147d32c479 100644 (file)
@@ -11,7 +11,25 @@ INCLUDES                    = -I$(top_srcdir)/libs/mrcp-engine/include \
 
 noinst_LTLIBRARIES          = libmrcpengine.la
 
-include_HEADERS             = include/mrcp_resource_plugin.h \
-                              include/mrcp_resource_engine.h
+include_HEADERS             = include/mrcp_engine_types.h \
+                              include/mrcp_engine_plugin.h \
+                              include/mrcp_engine_iface.h \
+                              include/mrcp_engine_impl.h \
+                              include/mrcp_synth_engine.h \
+                              include/mrcp_recog_engine.h \
+                              include/mrcp_recorder_engine.h \
+                              include/mrcp_resource_engine.h \
+                              include/mrcp_engine_factory.h \
+                              include/mrcp_engine_loader.h \
+                              include/mrcp_state_machine.h \
+                              include/mrcp_synth_state_machine.h \
+                              include/mrcp_recog_state_machine.h \
+                              include/mrcp_recorder_state_machine.h
 
-libmrcpengine_la_SOURCES    = src/mrcp_resource_engine.c
+libmrcpengine_la_SOURCES    = src/mrcp_engine_iface.c \
+                              src/mrcp_engine_impl.c \
+                              src/mrcp_engine_factory.c \
+                              src/mrcp_engine_loader.c \
+                              src/mrcp_synth_state_machine.c \
+                              src/mrcp_recog_state_machine.c \
+                              src/mrcp_recorder_state_machine.c
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_factory.h
new file mode 100644 (file)
index 0000000..ac8ccd7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 __MRCP_ENGINE_FACTORY_H__
+#define __MRCP_ENGINE_FACTORY_H__
+
+/**
+ * @file mrcp_engine_factory.h
+ * @brief Factory of MRCP Engines
+ */ 
+
+#include "mrcp_engine_iface.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque engine factory declaration */
+typedef struct mrcp_engine_factory_t mrcp_engine_factory_t;
+
+/** Create engine factory */
+MRCP_DECLARE(mrcp_engine_factory_t*) mrcp_engine_factory_create(apr_pool_t *pool);
+
+/** Destroy registered engines and the factory */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_destroy(mrcp_engine_factory_t *factory);
+
+/** Open registered engines */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_open(mrcp_engine_factory_t *factory);
+
+/** Close registered engines */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_close(mrcp_engine_factory_t *factory);
+
+
+/** Register engine */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine, const char *name);
+
+/** Get engine by name */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(mrcp_engine_factory_t *factory, const char *name);
+
+/** Find engine by resource identifier */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(mrcp_engine_factory_t *factory, mrcp_resource_id resource_id);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_ENGINE_FACTORY_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_iface.h
new file mode 100644 (file)
index 0000000..ee123fe
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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 __MRCP_ENGINE_IFACE_H__
+#define __MRCP_ENGINE_IFACE_H__
+
+/**
+ * @file mrcp_engine_iface.h
+ * @brief MRCP Engine User Interface (typically user is an MRCP server)
+ */ 
+
+#include "mrcp_engine_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Destroy engine */
+static APR_INLINE apt_bool_t mrcp_engine_virtual_destroy(mrcp_engine_t *engine)
+{
+       return engine->method_vtable->destroy(engine);
+}
+
+/** Open engine */
+static APR_INLINE apt_bool_t mrcp_engine_virtual_open(mrcp_engine_t *engine)
+{
+       if(engine->is_open == FALSE) {
+               engine->is_open = engine->method_vtable->open(engine);
+               return engine->is_open;
+       }
+       return FALSE;
+}
+
+/** Close engine */
+static APR_INLINE apt_bool_t mrcp_engine_virtual_close(mrcp_engine_t *engine)
+{
+       if(engine->is_open == TRUE) {
+               engine->is_open = FALSE;
+               return engine->method_vtable->close(engine);
+       }
+       return FALSE;
+}
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_virtual_create(mrcp_engine_t *engine, mrcp_version_e mrcp_version, apr_pool_t *pool);
+
+/** Destroy engine channel */
+apt_bool_t mrcp_engine_channel_virtual_destroy(mrcp_engine_channel_t *channel);
+
+/** Open engine channel */
+static APR_INLINE apt_bool_t mrcp_engine_channel_virtual_open(mrcp_engine_channel_t *channel)
+{
+       if(channel->is_open == FALSE) {
+               channel->is_open = channel->method_vtable->open(channel);
+               return channel->is_open;
+       }
+       return FALSE;
+}
+
+/** Close engine channel */
+static APR_INLINE apt_bool_t mrcp_engine_channel_virtual_close(mrcp_engine_channel_t *channel)
+{
+       if(channel->is_open == TRUE) {
+               channel->is_open = FALSE;
+               return channel->method_vtable->close(channel);
+       }
+       return FALSE;
+}
+
+/** Process request */
+static APR_INLINE apt_bool_t mrcp_engine_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+{
+       return channel->method_vtable->process_request(channel,message);
+}
+
+/** Allocate engine config */
+mrcp_engine_config_t* mrcp_engine_config_alloc(apr_pool_t *pool);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_ENGINE_IFACE_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_impl.h
new file mode 100644 (file)
index 0000000..32de2ad
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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 __MRCP_ENGINE_IMPL_H__
+#define __MRCP_ENGINE_IMPL_H__
+
+/**
+ * @file mrcp_engine_impl.h
+ * @brief MRCP Engine Realization Interface (typically should be implemented in plugins)
+ */ 
+
+#include "mrcp_engine_types.h"
+#include "mpf_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Create engine */
+mrcp_engine_t* mrcp_engine_create(
+                                       mrcp_resource_id resource_id,
+                                       void *obj, 
+                                       const mrcp_engine_method_vtable_t *vtable,
+                                       apr_pool_t *pool);
+
+
+/** Get engine config */
+const mrcp_engine_config_t* mrcp_engine_config_get(const mrcp_engine_t *engine);
+
+/** Get engine param by name */
+const char* mrcp_engine_param_get(const mrcp_engine_t *engine, const char *name);
+
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_create(
+                                       mrcp_engine_t *engine,
+                                       const mrcp_engine_channel_method_vtable_t *method_vtable,
+                                       void *method_obj,
+                                       mpf_termination_t *termination,
+                                       apr_pool_t *pool);
+
+/** Create audio termination */
+mpf_termination_t* mrcp_engine_audio_termination_create(
+                                                               void *obj,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               mpf_stream_capabilities_t *capabilities,
+                                                               apr_pool_t *pool);
+
+/** Create engine channel and source media termination 
+ * @deprecated @see mrcp_engine_channel_create() and mrcp_engine_audio_termination_create()
+ */
+mrcp_engine_channel_t* mrcp_engine_source_channel_create(
+                                                               mrcp_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool);
+
+/** Create engine channel and sink media termination 
+ * @deprecated @see mrcp_engine_channel_create() and mrcp_engine_audio_termination_create()
+ */
+mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
+                                                               mrcp_engine_t *engine,
+                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               void *method_obj,
+                                                               mpf_codec_descriptor_t *codec_descriptor,
+                                                               apr_pool_t *pool);
+
+/** Send channel open response */
+static APR_INLINE apt_bool_t mrcp_engine_channel_open_respond(mrcp_engine_channel_t *channel, apt_bool_t status)
+{
+       return channel->event_vtable->on_open(channel,status);
+}
+
+/** Send channel close response */
+static APR_INLINE apt_bool_t mrcp_engine_channel_close_respond(mrcp_engine_channel_t *channel)
+{
+       return channel->event_vtable->on_close(channel);
+}
+
+/** Send response/event message */
+static APR_INLINE apt_bool_t mrcp_engine_channel_message_send(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+{
+       return channel->event_vtable->on_message(channel,message);
+}
+
+/** Get channel identifier */
+static APR_INLINE const char* mrcp_engine_channel_id_get(mrcp_engine_channel_t *channel)
+{
+       return channel->id.buf;
+}
+
+/** Get MRCP version channel is created in the scope of */
+static APR_INLINE mrcp_version_e mrcp_engine_channel_version_get(mrcp_engine_channel_t *channel)
+{
+       return channel->mrcp_version;
+}
+
+/** Get codec descriptor of the audio source stream */
+const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel);
+
+/** Get codec descriptor of the audio sink stream */
+const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_ENGINE_IMPL_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_loader.h
new file mode 100644 (file)
index 0000000..a4fc9d2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 __MRCP_ENGINE_LOADER_H__
+#define __MRCP_ENGINE_LOADER_H__
+
+/**
+ * @file mrcp_engine_loader.h
+ * @brief Loader of plugins for MRCP engines
+ */ 
+
+#include "mrcp_engine_iface.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque engine loader declaration */
+typedef struct mrcp_engine_loader_t mrcp_engine_loader_t;
+
+/** Create engine loader */
+MRCP_DECLARE(mrcp_engine_loader_t*) mrcp_engine_loader_create(apr_pool_t *pool);
+
+/** Destroy engine loader */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_loader_destroy(mrcp_engine_loader_t *loader);
+
+/** Unload loaded plugins */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_loader_plugins_unload(mrcp_engine_loader_t *loader);
+
+
+/** Load engine plugin */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t *loader, const char *path, const char *name);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_ENGINE_LOADER_H__*/
similarity index 76%
rename from libs/unimrcp/libs/mrcp-engine/include/mrcp_resource_plugin.h
rename to libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_plugin.h
index 4dcc3be1824c76d243f558da5e17faa01a32399b..103944eb1f9704047c645895acfa9aa6aa2efc59 100644 (file)
  * limitations under the License.
  */
 
-#ifndef __MRCP_RESOURCE_PLUGIN_H__
-#define __MRCP_RESOURCE_PLUGIN_H__
+#ifndef __MRCP_ENGINE_PLUGIN_H__
+#define __MRCP_ENGINE_PLUGIN_H__
 
 /**
- * @file mrcp_resource_plugin.h
- * @brief MRCP Resource Engine Plugin
+ * @file mrcp_engine_plugin.h
+ * @brief MRCP Engine Plugin
  */ 
 
 #include "apr_version.h"
 #include "apt_log.h"
+#include "mrcp_engine_types.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -34,17 +35,17 @@ APT_BEGIN_EXTERN_C
 #define MRCP_PLUGIN_DECLARE(type) type
 #endif
 
-/** Symbol name of the main entry point in plugin DSO */
+/** [REQUIRED] Symbol name of the main entry point in plugin DSO */
 #define MRCP_PLUGIN_ENGINE_SYM_NAME "mrcp_plugin_create"
-/** Symbol name of the log accessor entry point in plugin DSO */
+/** [REQUIRED] Symbol name of the vesrion number entry point in plugin DSO */
+#define MRCP_PLUGIN_VERSION_SYM_NAME "mrcp_plugin_version"
+/** [IMPLIED] Symbol name of the log accessor entry point in plugin DSO */
 #define MRCP_PLUGIN_LOGGER_SYM_NAME "mrcp_plugin_logger_set"
 
-/** MRCP resource engine declaration */
-typedef struct mrcp_resource_engine_t mrcp_resource_engine_t;
-/** Prototype of resource engine creator (entry point of plugin DSO) */
-typedef mrcp_resource_engine_t* (*mrcp_plugin_creator_f)(apr_pool_t *pool);
+/** Prototype of engine creator (entry point of plugin DSO) */
+typedef mrcp_engine_t* (*mrcp_plugin_creator_f)(apr_pool_t *pool);
 
-/** Prototype of resource engine creator (entry point of plugin DSO) */
+/** Prototype of log accessor (entry point of plugin DSO) */
 typedef apt_bool_t (*mrcp_plugin_log_accessor_f)(apt_logger_t *logger);
 
 /** Declare this macro in plugins to use log routine of the server */
@@ -52,6 +53,11 @@ typedef apt_bool_t (*mrcp_plugin_log_accessor_f)(apt_logger_t *logger);
        MRCP_PLUGIN_DECLARE(apt_bool_t) mrcp_plugin_logger_set(apt_logger_t *logger) \
                { return apt_log_instance_set(logger); }
 
+/** Declare this macro in plugins to set plugin version */
+#define MRCP_PLUGIN_VERSION_DECLARE \
+       MRCP_PLUGIN_DECLARE(mrcp_plugin_version_t) mrcp_plugin_version =  \
+               {PLUGIN_MAJOR_VERSION, PLUGIN_MINOR_VERSION, PLUGIN_PATCH_VERSION};
+
 
 /** major version 
  * Major API changes that could cause compatibility problems for older
@@ -64,7 +70,7 @@ typedef apt_bool_t (*mrcp_plugin_log_accessor_f)(apt_logger_t *logger);
  * Minor API changes that do not cause binary compatibility problems.
  * Reset to 0 when upgrading PLUGIN_MAJOR_VERSION
  */
-#define PLUGIN_MINOR_VERSION   4
+#define PLUGIN_MINOR_VERSION   5
 
 /** patch level 
  * The Patch Level never includes API changes, simply bug fixes.
@@ -107,4 +113,4 @@ static APR_INLINE int mrcp_plugin_version_check(mrcp_plugin_version_t *version)
 
 APT_END_EXTERN_C
 
-#endif /*__MRCP_RESOURCE_PLUGIN_H__*/
+#endif /*__MRCP_ENGINE_PLUGIN_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_engine_types.h
new file mode 100644 (file)
index 0000000..eec9ec8
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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 __MRCP_ENGINE_TYPES_H__
+#define __MRCP_ENGINE_TYPES_H__
+
+/**
+ * @file mrcp_engine_types.h
+ * @brief MRCP Engine Types
+ */ 
+
+#include <apr_tables.h>
+#include "mrcp_state_machine.h"
+#include "mpf_types.h"
+#include "apt_string.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP engine declaration */
+typedef struct mrcp_engine_t mrcp_engine_t;
+/** MRCP engine config declaration */
+typedef struct mrcp_engine_config_t mrcp_engine_config_t;
+/** MRCP engine vtable declaration */
+typedef struct mrcp_engine_method_vtable_t mrcp_engine_method_vtable_t;
+/** MRCP engine channel declaration */
+typedef struct mrcp_engine_channel_t mrcp_engine_channel_t;
+/** MRCP engine channel virtual method table declaration */
+typedef struct mrcp_engine_channel_method_vtable_t mrcp_engine_channel_method_vtable_t;
+/** MRCP engine channel virtual event table declaration */
+typedef struct mrcp_engine_channel_event_vtable_t mrcp_engine_channel_event_vtable_t;
+
+/** Table of channel virtual methods */
+struct mrcp_engine_channel_method_vtable_t {
+       /** Virtual destroy */
+       apt_bool_t (*destroy)(mrcp_engine_channel_t *channel);
+       /** Virtual open */
+       apt_bool_t (*open)(mrcp_engine_channel_t *channel);
+       /** Virtual close */
+       apt_bool_t (*close)(mrcp_engine_channel_t *channel);
+       /** Virtual process_request */
+       apt_bool_t (*process_request)(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+};
+
+/** Table of channel virtual event handlers */
+struct mrcp_engine_channel_event_vtable_t {
+       /** Open event handler */
+       apt_bool_t (*on_open)(mrcp_engine_channel_t *channel, apt_bool_t status);
+       /** Close event handler */
+       apt_bool_t (*on_close)(mrcp_engine_channel_t *channel);
+       /** Message event handler */
+       apt_bool_t (*on_message)(mrcp_engine_channel_t *channel, mrcp_message_t *message);
+};
+
+/** MRCP engine channel declaration */
+struct mrcp_engine_channel_t {
+       /** Table of virtual methods */
+       const mrcp_engine_channel_method_vtable_t *method_vtable;
+       /** External object used with virtual methods */
+       void                                      *method_obj;
+       /** Table of virtual event handlers */
+       const mrcp_engine_channel_event_vtable_t  *event_vtable;
+       /** External object used with event handlers */
+       void                                      *event_obj;
+       /** Media termination */
+       mpf_termination_t                         *termination;
+       /** Back pointer to engine */
+       mrcp_engine_t                             *engine;
+       /** Unique identifier to be used in traces */
+       apt_str_t                                  id;
+       /** MRCP version */
+       mrcp_version_e                             mrcp_version;
+       /** Is channel successfully opened */
+       apt_bool_t                                is_open;
+       /** Pool to allocate memory from */
+       apr_pool_t                                *pool;
+};
+
+/** Table of MRCP engine virtual methods */
+struct mrcp_engine_method_vtable_t {
+       /** Virtual destroy */
+       apt_bool_t (*destroy)(mrcp_engine_t *engine);
+       /** Virtual open */
+       apt_bool_t (*open)(mrcp_engine_t *engine);
+       /** Virtual close */
+       apt_bool_t (*close)(mrcp_engine_t *engine);
+       /** Virtual channel create */
+       mrcp_engine_channel_t* (*create_channel)(mrcp_engine_t *engine, apr_pool_t *pool);
+};
+
+/** MRCP engine */
+struct mrcp_engine_t {
+       /** Resource identifier */
+       mrcp_resource_id                   resource_id;
+       /** External object associated with engine */
+       void                              *obj;
+       /** Table of virtual methods */
+       const mrcp_engine_method_vtable_t *method_vtable;
+       /** Codec manager */
+       const mpf_codec_manager_t         *codec_manager;
+       /** Dir layout structure */
+       const apt_dir_layout_t            *dir_layout;
+       /** Config of engine */
+       mrcp_engine_config_t              *config;
+       /** Number of simultaneous channels currently in use */
+       apr_size_t                         cur_channel_count;
+       /** Is engine successfully opened */
+       apt_bool_t                         is_open;
+       /** Pool to allocate memory from */
+       apr_pool_t                        *pool;
+
+
+       /** Create state machine */
+       mrcp_state_machine_t* (*create_state_machine)(void *obj, mrcp_version_e version, apr_pool_t *pool);
+};
+
+/** MRCP engine config */
+struct mrcp_engine_config_t {
+       /** Name of the engine */
+       const char  *name;
+       /** Max number of simultaneous channels */
+       apr_size_t   max_channel_count;
+       /** Table of name/value string params */
+       apr_table_t *params;
+};
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_ENGINE_TYPES_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_engine.h
new file mode 100644 (file)
index 0000000..2e58c06
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 __MRCP_RECOG_ENGINE_H__
+#define __MRCP_RECOG_ENGINE_H__
+
+/**
+ * @file mrcp_recog_engine.h
+ * @brief Recognizer Engine Includes
+ */ 
+
+#include "mrcp_engine_plugin.h"
+#include "mrcp_engine_impl.h"
+
+#include "mrcp_recog_resource.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+
+#endif /*__MRCP_RECOG_ENGINE_H__*/
similarity index 72%
rename from libs/unimrcp/libs/mrcp/resources/include/mrcp_recog_state_machine.h
rename to libs/unimrcp/libs/mrcp-engine/include/mrcp_recog_state_machine.h
index ee04601c22fff69fd5b8aa6fbee1b4bffe60100a..32d5482593bd167b83ae781c400e907ea2c6e807 100644 (file)
 
 APT_BEGIN_EXTERN_C
 
-/** Create MRCP recognizer server state machine */
-mrcp_state_machine_t* mrcp_recog_server_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
-
-/** Create MRCP recognizer client state machine */
-mrcp_state_machine_t* mrcp_recog_client_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
+/** Create MRCP recognizer state machine */
+mrcp_state_machine_t* mrcp_recog_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
 
 APT_END_EXTERN_C
 
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_engine.h
new file mode 100644 (file)
index 0000000..3e4e818
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 __MRCP_RECORDER_ENGINE_H__
+#define __MRCP_RECORDER_ENGINE_H__
+
+/**
+ * @file mrcp_recorder_engine.h
+ * @brief Recorder Engine Includes
+ */ 
+
+#include "mrcp_engine_plugin.h"
+#include "mrcp_engine_impl.h"
+
+#include "mrcp_recorder_resource.h"
+#include "mrcp_recorder_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+
+#endif /*__MRCP_RECORDER_ENGINE_H__*/
similarity index 62%
rename from libs/unimrcp/libs/mrcp/resources/include/mrcp_default_factory.h
rename to libs/unimrcp/libs/mrcp-engine/include/mrcp_recorder_state_machine.h
index 7820aae47b4e4e14f629ccd5716e5d376b4b079a..ccd6096d95e0278a20a19595b9e5a20d6cc6c9ec 100644 (file)
  * limitations under the License.
  */
 
-#ifndef __MRCP_DEFAULT_FACTORY_H__
-#define __MRCP_DEFAULT_FACTORY_H__
+#ifndef __MRCP_RECORDER_STATE_MACHINE_H__
+#define __MRCP_RECORDER_STATE_MACHINE_H__
 
 /**
- * @file mrcp_default_factory.h
- * @brief Default MRCP Resource Factory
+ * @file mrcp_recorder_state_machine.h
+ * @brief MRCP Recorder State Machine
  */ 
 
-#include "mrcp_resource_factory.h"
+#include "mrcp_state_machine.h"
 
 APT_BEGIN_EXTERN_C
 
-/** Create default MRCP resource factory */
-MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_default_factory_create(apr_pool_t *pool);
-
+/** Create MRCP recorder state machine */
+mrcp_state_machine_t* mrcp_recorder_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
 
 APT_END_EXTERN_C
 
-#endif /*__MRCP_DEFAULT_FACTORY_H__*/
+#endif /*__MRCP_RECORDER_STATE_MACHINE_H__*/
index 4432a64b51320b615148eb0e941b0294d7cf9320..c69e5d0b933bc1a50c69dea2daabaaf40a60a9ad 100644 (file)
 
 /**
  * @file mrcp_resource_engine.h
- * @brief MRCP Resource Engine Interface
+ * @brief Legacy MRCP Resource Engine
+ * @deprecated @see mrcp_engine_plugin.h and mrcp_engine_impl.h
  */ 
 
-#include "mrcp_types.h"
-#include "mpf_termination.h"
-#include "mpf_stream.h"
-#include "mrcp_resource_plugin.h"
+#include "mrcp_engine_plugin.h"
+#include "mrcp_engine_impl.h"
 
 APT_BEGIN_EXTERN_C
 
-/** MRCP resource engine vtable declaration */
-typedef struct mrcp_engine_method_vtable_t mrcp_engine_method_vtable_t;
-/** MRCP engine channel declaration */
-typedef struct mrcp_engine_channel_t mrcp_engine_channel_t;
-/** MRCP engine channel virtual method table declaration */
-typedef struct mrcp_engine_channel_method_vtable_t mrcp_engine_channel_method_vtable_t;
-/** MRCP engine channel virtual event table declaration */
-typedef struct mrcp_engine_channel_event_vtable_t mrcp_engine_channel_event_vtable_t;
+/** Termorary define legacy mrcp_resource_engine_t as mrcp_engine_t */
+typedef mrcp_engine_t mrcp_resource_engine_t;
 
-/** Table of channel virtual methods */
-struct mrcp_engine_channel_method_vtable_t {
-       /** Virtual destroy */
-       apt_bool_t (*destroy)(mrcp_engine_channel_t *channel);
-       /** Virtual open */
-       apt_bool_t (*open)(mrcp_engine_channel_t *channel);
-       /** Virtual close */
-       apt_bool_t (*close)(mrcp_engine_channel_t *channel);
-       /** Virtual process_request */
-       apt_bool_t (*process_request)(mrcp_engine_channel_t *channel, mrcp_message_t *request);
-};
-
-/** Table of channel virtual event handlers */
-struct mrcp_engine_channel_event_vtable_t {
-       /** Open event handler */
-       apt_bool_t (*on_open)(mrcp_engine_channel_t *channel, apt_bool_t status);
-       /** Close event handler */
-       apt_bool_t (*on_close)(mrcp_engine_channel_t *channel);
-       /** Message event handler */
-       apt_bool_t (*on_message)(mrcp_engine_channel_t *channel, mrcp_message_t *message);
-};
-
-/** MRCP engine channel declaration */
-struct mrcp_engine_channel_t {
-       /** Table of virtual methods */
-       const mrcp_engine_channel_method_vtable_t *method_vtable;
-       /** External object used with virtual methods */
-       void                                      *method_obj;
-       /** Table of virtual event handlers */
-       const mrcp_engine_channel_event_vtable_t  *event_vtable;
-       /** External object used with event handlers */
-       void                                      *event_obj;
-       /** Media termination */
-       mpf_termination_t                         *termination;
-       /** Back pointer to resource engine */
-       mrcp_resource_engine_t                    *engine;
-       /** Unique identifier (useful for traces) */
-       apt_str_t                                  id;
-       /** Pool to allocate memory from */
-       apr_pool_t                                *pool;
-};
-
-/** Table of MRCP engine virtual methods */
-struct mrcp_engine_method_vtable_t {
-       /** Virtual destroy */
-       apt_bool_t (*destroy)(mrcp_resource_engine_t *engine);
-       /** Virtual open */
-       apt_bool_t (*open)(mrcp_resource_engine_t *engine);
-       /** Virtual close */
-       apt_bool_t (*close)(mrcp_resource_engine_t *engine);
-       /** Virtual channel create */
-       mrcp_engine_channel_t* (*create_channel)(mrcp_resource_engine_t *engine, apr_pool_t *pool);
-};
-
-/** MRCP resource engine */
-struct mrcp_resource_engine_t {
-       /** Plugin version */
-       mrcp_plugin_version_t              plugin_version;
-       /** Resource identifier */
-       mrcp_resource_id                   resource_id;
-       /** External object associated with engine */
-       void                              *obj;
-       /** Table of virtual methods */
-       const mrcp_engine_method_vtable_t *method_vtable;
-       /** Codec manager */
-       const mpf_codec_manager_t         *codec_manager;
-       /** Dir layout structure */
-       const apt_dir_layout_t            *dir_layout;
-       /** Pool to allocate memory from */
-       apr_pool_t                        *pool;
-};
-
-/** Create resource engine */
-mrcp_resource_engine_t* mrcp_resource_engine_create(
-                                                               mrcp_resource_id resource_id,
-                                                               void *obj, 
-                                                               const mrcp_engine_method_vtable_t *vtable,
-                                                               apr_pool_t *pool);
-
-/** Destroy resource engine */
-static APR_INLINE apt_bool_t mrcp_resource_engine_destroy(mrcp_resource_engine_t *engine)
-{
-       return engine->method_vtable->destroy(engine);
-}
-
-/** Open resource engine */
-static APR_INLINE apt_bool_t mrcp_resource_engine_open(mrcp_resource_engine_t *engine)
-{
-       return engine->method_vtable->open(engine);
-}
-
-/** Close resource engine */
-static APR_INLINE apt_bool_t mrcp_resource_engine_close(mrcp_resource_engine_t *engine)
-{
-       return engine->method_vtable->close(engine);
-}
-
-/** Create engine channel */
-mrcp_engine_channel_t* mrcp_engine_channel_create(
-                                                               mrcp_resource_engine_t *engine,
-                                                               const mrcp_engine_channel_method_vtable_t *method_vtable,
-                                                               void *method_obj,
-                                                               mpf_termination_t *termination,
-                                                               apr_pool_t *pool);
-
-/** Create engine channel and source media termination */
-mrcp_engine_channel_t* mrcp_engine_source_channel_create(
-                                                               mrcp_resource_engine_t *engine,
-                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
-                                                               const mpf_audio_stream_vtable_t *stream_vtable,
-                                                               void *method_obj,
-                                                               mpf_codec_descriptor_t *codec_descriptor,
-                                                               apr_pool_t *pool);
-
-/** Create engine channel and sink media termination */
-mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
-                                                               mrcp_resource_engine_t *engine,
-                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
-                                                               const mpf_audio_stream_vtable_t *stream_vtable,
-                                                               void *method_obj,
-                                                               mpf_codec_descriptor_t *codec_descriptor,
-                                                               apr_pool_t *pool);
-
-/** Destroy engine channel */
-static APR_INLINE apt_bool_t mrcp_engine_channel_destroy(mrcp_engine_channel_t *channel)
-{
-       return channel->method_vtable->destroy(channel);
-}
-
-/** Open engine channel */
-static APR_INLINE apt_bool_t mrcp_engine_channel_open(mrcp_engine_channel_t *channel)
-{
-       return channel->method_vtable->open(channel);
-}
-
-/** Close engine channel */
-static APR_INLINE apt_bool_t mrcp_engine_channel_close(mrcp_engine_channel_t *channel)
-{
-       return channel->method_vtable->close(channel);
-}
-
-/** Process request */
-static APR_INLINE apt_bool_t mrcp_engine_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *message)
-{
-       return channel->method_vtable->process_request(channel,message);
-}
-
-/** Send channel open response */
-static APR_INLINE apt_bool_t mrcp_engine_channel_open_respond(mrcp_engine_channel_t *channel, apt_bool_t status)
-{
-       return channel->event_vtable->on_open(channel,status);
-}
-
-/** Send channel close response */
-static APR_INLINE apt_bool_t mrcp_engine_channel_close_respond(mrcp_engine_channel_t *channel)
-{
-       return channel->event_vtable->on_close(channel);
-}
-
-/** Send response/event message */
-static APR_INLINE apt_bool_t mrcp_engine_channel_message_send(mrcp_engine_channel_t *channel, mrcp_message_t *message)
+/** 
+ * Create resource engine
+ * @deprecated @see mrcp_engine_create
+ */
+static APR_INLINE mrcp_engine_t* mrcp_resource_engine_create(
+                                       mrcp_resource_id resource_id,
+                                       void *obj, 
+                                       const mrcp_engine_method_vtable_t *vtable,
+                                       apr_pool_t *pool)
 {
-       return channel->event_vtable->on_message(channel,message);
+       return mrcp_engine_create(resource_id,obj,vtable,pool);
 }
 
-/** Get codec of the audio source stream */
-mpf_codec_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel);
-
-/** Get codec of the audio sink stream */
-mpf_codec_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel);
-
-
 APT_END_EXTERN_C
 
 #endif /*__MRCP_RESOURCE_ENGINE_H__*/
diff --git a/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h b/libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_engine.h
new file mode 100644 (file)
index 0000000..305f7ea
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 __MRCP_SYNTH_ENGINE_H__
+#define __MRCP_SYNTH_ENGINE_H__
+
+/**
+ * @file mrcp_synth_engine.h
+ * @brief Synthesizer Engine Includes
+ */ 
+
+#include "mrcp_engine_plugin.h"
+#include "mrcp_engine_impl.h"
+
+#include "mrcp_synth_resource.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_message.h"
+
+#endif /*__MRCP_SYNTH_ENGINE_H__*/
similarity index 72%
rename from libs/unimrcp/libs/mrcp/resources/include/mrcp_synth_state_machine.h
rename to libs/unimrcp/libs/mrcp-engine/include/mrcp_synth_state_machine.h
index eed266e2a4fdc11558f85ee0f70f6ad5e85552ef..efe26dcc73a801f8870520434dca784fa2255084 100644 (file)
 
 APT_BEGIN_EXTERN_C
 
-/** Create MRCP synthesizer server state machine */
-mrcp_state_machine_t* mrcp_synth_server_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
-
-/** Create MRCP synthesizer client state machine */
-mrcp_state_machine_t* mrcp_synth_client_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
+/** Create MRCP synthesizer state machine */
+mrcp_state_machine_t* mrcp_synth_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool);
 
 APT_END_EXTERN_C
 
index b5fa4aba9e13421e50b82cfc84ee51815934c84c..ed21f76c04deadd8243e49e3ee5b228d17421923 100644 (file)
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
                        >
+                       <File
+                               RelativePath=".\include\mrcp_engine_factory.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_engine_iface.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_engine_impl.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_engine_loader.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_engine_plugin.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_engine_types.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_recog_engine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_recog_state_machine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_recorder_engine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_recorder_state_machine.h"
+                               >
+                       </File>
                        <File
                                RelativePath=".\include\mrcp_resource_engine.h"
                                >
                        </File>
                        <File
-                               RelativePath=".\include\mrcp_resource_plugin.h"
+                               RelativePath=".\include\mrcp_state_machine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_synth_engine.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\mrcp_synth_state_machine.h"
                                >
                        </File>
                </Filter>
                        Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
                        >
                        <File
-                               RelativePath=".\src\mrcp_resource_engine.c"
+                               RelativePath=".\src\mrcp_engine_factory.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_engine_iface.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_engine_impl.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_engine_loader.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_recog_state_machine.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_recorder_state_machine.c"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\mrcp_synth_state_machine.c"
                                >
                        </File>
                </Filter>
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_factory.c
new file mode 100644 (file)
index 0000000..2faaabf
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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_hash.h>
+#include "mrcp_engine_factory.h"
+#include "mrcp_synth_state_machine.h"
+#include "mrcp_recog_state_machine.h"
+#include "mrcp_recorder_state_machine.h"
+#include "apt_log.h"
+
+/** Engine factory declaration */
+struct mrcp_engine_factory_t {
+       apr_hash_t *engines;
+       apr_pool_t *pool;
+};
+
+
+MRCP_DECLARE(mrcp_engine_factory_t*) mrcp_engine_factory_create(apr_pool_t *pool)
+{
+       mrcp_engine_factory_t *factory = apr_palloc(pool,sizeof(mrcp_engine_factory_t));
+       factory->pool = pool;
+       factory->engines = apr_hash_make(pool);
+       return factory;
+}
+
+/** Destroy registered engines and the factory */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_destroy(mrcp_engine_factory_t *factory)
+{
+       mrcp_engine_t *engine;
+       apr_hash_index_t *it;
+       void *val;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Destroy MRCP Engines");
+       it=apr_hash_first(factory->pool,factory->engines);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               engine = val;
+               if(engine) {
+                       mrcp_engine_virtual_destroy(engine);
+               }
+       }
+       apr_hash_clear(factory->engines);
+       return TRUE;
+}
+
+/** Open registered engines */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_open(mrcp_engine_factory_t *factory)
+{
+       mrcp_engine_t *engine;
+       apr_hash_index_t *it;
+       void *val;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open MRCP Engines");
+       it = apr_hash_first(factory->pool,factory->engines);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               engine = val;
+               if(engine) {
+                       mrcp_engine_virtual_open(engine);
+               }
+       }
+       return TRUE;
+}
+
+/** Close registered engines */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_close(mrcp_engine_factory_t *factory)
+{
+       mrcp_engine_t *engine;
+       apr_hash_index_t *it;
+       void *val;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close MRCP Engines");
+       it=apr_hash_first(factory->pool,factory->engines);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               engine = val;
+               if(engine) {
+                       mrcp_engine_virtual_close(engine);
+               }
+       }
+       return TRUE;
+}
+
+/** Register new engine */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_factory_engine_register(mrcp_engine_factory_t *factory, mrcp_engine_t *engine, const char *name)
+{
+       if(!engine || !name) {
+               return FALSE;
+       }
+
+       switch(engine->resource_id) {
+               case MRCP_SYNTHESIZER_RESOURCE:
+                       engine->create_state_machine = mrcp_synth_state_machine_create;
+                       break;
+               case MRCP_RECOGNIZER_RESOURCE:
+                       engine->create_state_machine = mrcp_recog_state_machine_create;
+                       break;
+               case MRCP_RECORDER_RESOURCE:
+                       engine->create_state_machine = mrcp_recorder_state_machine_create;
+                       break;
+               default:
+                       break;
+       }
+
+       if(!engine->create_state_machine) {
+               return FALSE;
+       }
+
+       apr_hash_set(factory->engines,name,APR_HASH_KEY_STRING,engine);
+       return TRUE;
+}
+
+/** Get engine by name */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_get(mrcp_engine_factory_t *factory, const char *name)
+{
+       if(!name) {
+               return NULL;
+       }
+       return apr_hash_get(factory->engines,name,APR_HASH_KEY_STRING);
+}
+
+/** Find engine by resource identifier */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_factory_engine_find(mrcp_engine_factory_t *factory, mrcp_resource_id resource_id)
+{
+       mrcp_engine_t *engine;
+       void *val;
+       apr_hash_index_t *it = apr_hash_first(factory->pool,factory->engines);
+       /* walk through the engines */
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               engine = val;
+               if(engine && engine->resource_id == resource_id) {
+                       return engine;
+               }
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_iface.c
new file mode 100644 (file)
index 0000000..137af17
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 "mrcp_engine_iface.h"
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_virtual_create(mrcp_engine_t *engine, mrcp_version_e mrcp_version, apr_pool_t *pool)
+{
+       mrcp_engine_channel_t *channel;
+       if(engine->is_open != TRUE) {
+               return NULL;
+       }
+       if(engine->config->max_channel_count && engine->cur_channel_count >= engine->config->max_channel_count) {
+               return NULL;
+       }
+       channel = engine->method_vtable->create_channel(engine,pool);
+       if(channel) {
+               channel->mrcp_version = mrcp_version;
+               engine->cur_channel_count++;
+       }
+       return channel;
+}
+
+/** Destroy engine channel */
+apt_bool_t mrcp_engine_channel_virtual_destroy(mrcp_engine_channel_t *channel)
+{
+       mrcp_engine_t *engine = channel->engine;
+       if(engine->cur_channel_count) {
+               engine->cur_channel_count--;
+       }
+       return channel->method_vtable->destroy(channel);
+}
+
+/** Allocate engine config */
+mrcp_engine_config_t* mrcp_engine_config_alloc(apr_pool_t *pool)
+{
+       mrcp_engine_config_t *config = apr_palloc(pool,sizeof(mrcp_engine_config_t));
+       config->name = NULL;
+       config->max_channel_count = 0;
+       config->params = NULL;
+       return config;
+}
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_impl.c
new file mode 100644 (file)
index 0000000..e2c7a24
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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 "mrcp_engine_impl.h"
+#include "mpf_termination_factory.h"
+
+/** Create engine */
+mrcp_engine_t* mrcp_engine_create(
+                                       mrcp_resource_id resource_id,
+                                       void *obj, 
+                                       const mrcp_engine_method_vtable_t *vtable,
+                                       apr_pool_t *pool)
+{
+       mrcp_engine_t *engine = apr_palloc(pool,sizeof(mrcp_engine_t));
+       engine->resource_id = resource_id;
+       engine->obj = obj;
+       engine->method_vtable =vtable;
+       engine->config = NULL;
+       engine->codec_manager = NULL;
+       engine->dir_layout = NULL;
+       engine->cur_channel_count = 0;
+       engine->is_open = FALSE;
+       engine->pool = pool;
+       engine->create_state_machine = NULL;
+       return engine;
+}
+
+/** Get engine config */
+const mrcp_engine_config_t* mrcp_engine_config_get(const mrcp_engine_t *engine)
+{
+       return engine->config;
+}
+
+/** Get engine param by name */
+const char* mrcp_engine_param_get(const mrcp_engine_t *engine, const char *name)
+{
+       if(!engine->config || !engine->config->params) {
+               return NULL;
+       }
+       return apr_table_get(engine->config->params,name);
+}
+
+/** Create engine channel */
+mrcp_engine_channel_t* mrcp_engine_channel_create(
+                                                       mrcp_engine_t *engine, 
+                                                       const mrcp_engine_channel_method_vtable_t *method_vtable,
+                                                       void *method_obj,
+                                                       mpf_termination_t *termination,
+                                                       apr_pool_t *pool)
+{
+       mrcp_engine_channel_t *channel = apr_palloc(pool,sizeof(mrcp_engine_channel_t));
+       channel->method_vtable = method_vtable;
+       channel->method_obj = method_obj;
+       channel->event_vtable = NULL;
+       channel->event_obj = NULL;
+       channel->termination = termination;
+       channel->engine = engine;
+       channel->is_open = FALSE;
+       channel->pool = pool;
+       apt_string_reset(&channel->id);
+       return channel;
+}
+
+/** Create audio termination */
+mpf_termination_t* mrcp_engine_audio_termination_create(
+                                                               void *obj,
+                                                               const mpf_audio_stream_vtable_t *stream_vtable,
+                                                               mpf_stream_capabilities_t *capabilities,
+                                                               apr_pool_t *pool)
+{
+       mpf_audio_stream_t *audio_stream;
+       if(!capabilities) {
+               return NULL;
+       }
+
+       if(mpf_codec_capabilities_validate(&capabilities->codecs) == FALSE) {
+               return NULL;
+       }
+
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       obj,                  /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
+       if(!audio_stream) {
+               return NULL;
+       }
+
+       /* create media termination */
+       return mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       pool);                /* pool to allocate memory from */
+}
+
+
+/** Create engine channel and source media termination */
+mrcp_engine_channel_t* mrcp_engine_source_channel_create(
+                                                       mrcp_engine_t *engine,
+                                                       const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                       const mpf_audio_stream_vtable_t *stream_vtable,
+                                                       void *method_obj,
+                                                       mpf_codec_descriptor_t *codec_descriptor,
+                                                       apr_pool_t *pool)
+{
+       mpf_stream_capabilities_t *capabilities;
+       mpf_audio_stream_t *audio_stream;
+       mpf_termination_t *termination;
+
+       capabilities = mpf_source_stream_capabilities_create(pool);
+       if(codec_descriptor) {
+               mpf_codec_capabilities_add(
+                                               &capabilities->codecs,
+                                               mpf_sample_rate_mask_get(codec_descriptor->sampling_rate),
+                                               codec_descriptor->name.buf);
+       }
+       else {
+               mpf_codec_default_capabilities_add(&capabilities->codecs);
+       }
+
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       method_obj,           /* object to associate */
+                       stream_vtable,        /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
+       if(!audio_stream) {
+               return NULL;
+       }
+
+       audio_stream->rx_descriptor = codec_descriptor;
+       
+       /* create media termination */
+       termination = mpf_raw_termination_create(
+                       NULL,                 /* no object to associate */
+                       audio_stream,         /* audio stream */
+                       NULL,                 /* no video stream */
+                       pool);                /* pool to allocate memory from */
+
+       /* create engine channel base */
+       return mrcp_engine_channel_create(
+                       engine,          /* engine */
+                       channel_vtable,  /* virtual methods table of engine channel */
+                       method_obj,      /* object to associate */
+                       termination,     /* media termination, used to terminate audio stream */
+                       pool);           /* pool to allocate memory from */
+}
+
+/** Create engine channel and sink media termination */
+mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
+                                                       mrcp_engine_t *engine,
+                                                       const mrcp_engine_channel_method_vtable_t *channel_vtable,
+                                                       const mpf_audio_stream_vtable_t *stream_vtable,
+                                                       void *method_obj,
+                                                       mpf_codec_descriptor_t *codec_descriptor,
+                                                       apr_pool_t *pool)
+{
+       mpf_stream_capabilities_t *capabilities;
+       mpf_audio_stream_t *audio_stream;
+       mpf_termination_t *termination;
+
+       capabilities = mpf_sink_stream_capabilities_create(pool);
+       if(codec_descriptor) {
+               mpf_codec_capabilities_add(
+                                               &capabilities->codecs,
+                                               mpf_sample_rate_mask_get(codec_descriptor->sampling_rate),
+                                               codec_descriptor->name.buf);
+       }
+       else {
+               mpf_codec_default_capabilities_add(&capabilities->codecs);
+       }
+
+       /* create audio stream */
+       audio_stream = mpf_audio_stream_create(
+                       method_obj,             /* object to associate */
+                       stream_vtable,          /* virtual methods table of audio stream */
+                       capabilities,           /* stream capabilities */
+                       pool);                  /* pool to allocate memory from */
+
+       if(!audio_stream) {
+               return NULL;
+       }
+
+       audio_stream->tx_descriptor = codec_descriptor;
+       
+       /* create media termination */
+       termination = mpf_raw_termination_create(
+                       NULL,            /* no object to associate */
+                       audio_stream,    /* audio stream */
+                       NULL,            /* no video stream */
+                       pool);           /* pool to allocate memory from */
+
+       /* create engine channel base */
+       return mrcp_engine_channel_create(
+                       engine,          /* engine */
+                       channel_vtable,  /* virtual methods table of engine channel */
+                       method_obj,      /* object to associate */
+                       termination,     /* media termination, used to terminate audio stream */
+                       pool);           /* pool to allocate memory from */
+}
+
+/** Get codec descriptor of the audio source stream */
+const mpf_codec_descriptor_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel)
+{
+       if(channel && channel->termination) {
+               mpf_audio_stream_t *audio_stream = mpf_termination_audio_stream_get(channel->termination);
+               if(audio_stream) {
+                       return audio_stream->rx_descriptor;
+               }
+       }
+       return NULL;
+}
+
+/** Get codec descriptor of the audio sink stream */
+const mpf_codec_descriptor_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel)
+{
+       if(channel && channel->termination) {
+               mpf_audio_stream_t *audio_stream = mpf_termination_audio_stream_get(channel->termination);
+               if(audio_stream) {
+                       return audio_stream->tx_descriptor;
+               }
+       }
+       return NULL;
+}
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_engine_loader.c
new file mode 100644 (file)
index 0000000..dfa5bd6
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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_dso.h>
+#include <apr_hash.h>
+#include "mrcp_engine_loader.h"
+#include "mrcp_engine_plugin.h"
+#include "apt_log.h"
+
+/** Engine loader declaration */
+struct mrcp_engine_loader_t {
+       /** Table of plugins (apr_dso_handle_t*) */
+       apr_hash_t *plugins;
+       apr_pool_t *pool;
+};
+
+
+/** Create engine loader */
+MRCP_DECLARE(mrcp_engine_loader_t*) mrcp_engine_loader_create(apr_pool_t *pool)
+{
+       mrcp_engine_loader_t *loader = apr_palloc(pool,sizeof(mrcp_engine_loader_t));
+       loader->pool = pool;
+       loader->plugins = apr_hash_make(pool);
+       return loader;
+}
+
+/** Destroy engine loader */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_loader_destroy(mrcp_engine_loader_t *loader)
+{
+       return mrcp_engine_loader_plugins_unload(loader);
+}
+
+/** Unload loaded plugins */
+MRCP_DECLARE(apt_bool_t) mrcp_engine_loader_plugins_unload(mrcp_engine_loader_t *loader)
+{
+       apr_hash_index_t *it;
+       void *val;
+       apr_dso_handle_t *plugin;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unload Plugins");
+       it=apr_hash_first(loader->pool,loader->plugins);
+       for(; it; it = apr_hash_next(it)) {
+               apr_hash_this(it,NULL,NULL,&val);
+               plugin = val;
+               if(plugin) {
+                       apr_dso_unload(plugin);
+               }
+       }
+       apr_hash_clear(loader->plugins);
+       return TRUE;
+}
+
+static apt_bool_t plugin_version_load(apr_dso_handle_t *plugin)
+{
+       apr_dso_handle_sym_t version_handle = NULL;
+       if(apr_dso_sym(&version_handle,plugin,MRCP_PLUGIN_VERSION_SYM_NAME) != APR_SUCCESS) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Version Info Found: %s", MRCP_PLUGIN_VERSION_SYM_NAME);
+               return FALSE;
+       }
+       
+       if(version_handle) {
+               mrcp_plugin_version_t *version = (mrcp_plugin_version_t*)version_handle;
+               if(mrcp_plugin_version_check(version)) {
+                       return TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Incompatible Plugin Version Found [%d.%d.%d] < ["PLUGIN_VERSION_STRING"]",
+                               version->major,
+                               version->minor,
+                               version->patch);
+               }
+       }
+       return FALSE;
+}
+
+static mrcp_plugin_creator_f plugin_creator_load(apr_dso_handle_t *plugin)
+{
+       apr_dso_handle_sym_t func_handle = NULL;
+       mrcp_plugin_creator_f plugin_creator = NULL;
+       
+       if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_ENGINE_SYM_NAME) == APR_SUCCESS) {
+               if(func_handle) {
+                       plugin_creator = (mrcp_plugin_creator_f)(intptr_t)func_handle;
+               }
+       }
+       else {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO Symbol: "MRCP_PLUGIN_ENGINE_SYM_NAME);
+               return NULL;
+       }
+
+       return plugin_creator;
+}
+
+static apt_bool_t plugin_logger_load(apr_dso_handle_t *plugin)
+{
+       apr_dso_handle_sym_t func_handle = NULL;
+       if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_LOGGER_SYM_NAME) != APR_SUCCESS) {
+               return FALSE;
+       }
+
+       if(func_handle) {
+               apt_logger_t *logger = apt_log_instance_get();
+               mrcp_plugin_log_accessor_f log_accessor;
+               log_accessor = (mrcp_plugin_log_accessor_f)(intptr_t)func_handle;
+               log_accessor(logger);
+       }
+       return TRUE;
+}
+
+
+/** Load engine plugin */
+MRCP_DECLARE(mrcp_engine_t*) mrcp_engine_loader_plugin_load(mrcp_engine_loader_t *loader, const char *path, const char *name)
+{
+       apr_dso_handle_t *plugin = NULL;
+       mrcp_plugin_creator_f plugin_creator = NULL;
+       mrcp_engine_t *engine = NULL;
+       if(!path || !name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load Plugin: invalid params");
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Load Plugin [%s] [%s]",path,name);
+       if(apr_dso_load(&plugin,path,loader->pool) != APR_SUCCESS) {
+               char derr[512] = "";
+               apr_dso_error(plugin,derr,sizeof(derr));
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO: %s", derr);
+               return NULL;
+       }
+
+       if(plugin_version_load(plugin) != TRUE) {
+               apr_dso_unload(plugin);
+               return NULL;
+       }
+
+       plugin_creator = plugin_creator_load(plugin);
+       if(!plugin_creator) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Entry Point Found for Plugin");
+               apr_dso_unload(plugin);
+               return NULL;
+       }
+
+       plugin_logger_load(plugin);
+
+       apr_hash_set(loader->plugins,name,APR_HASH_KEY_STRING,plugin);
+
+       engine = plugin_creator(loader->pool);
+       if(!engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create MRCP Engine");
+       }
+
+       return engine;
+}
similarity index 92%
rename from libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_server_state_machine.c
rename to libs/unimrcp/libs/mrcp-engine/src/mrcp_recog_state_machine.c
index 206512967aa12d977deb23720d5229f83c1b9140..1965192d965ad2df6a5b82627fe65a61ae1e5458 100644 (file)
@@ -95,26 +95,30 @@ static APR_INLINE void recog_state_change(mrcp_recog_state_machine_t *state_mach
 
 static apt_bool_t recog_request_set_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        mrcp_message_header_set(&state_machine->properties,&message->header,message->pool);
        return recog_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t recog_response_set_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_response_dispatch(state_machine,message);
 }
 
 static apt_bool_t recog_request_get_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t recog_response_get_params(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        mrcp_message_header_set(&message->header,&state_machine->active_request->header,message->pool);
        mrcp_message_header_get(&message->header,&state_machine->properties,message->pool);
        return recog_response_dispatch(state_machine,message);
@@ -131,13 +135,15 @@ static apt_bool_t recog_request_define_grammar(mrcp_recog_state_machine_t *state
                recog_state_change(state_machine,RECOGNIZER_STATE_IDLE);
        }
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t recog_response_define_grammar(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-GRAMMAR Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(mrcp_resource_header_property_check(message,RECOGNIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
                mrcp_recog_header_t *recog_header = mrcp_resource_header_prepare(message);
                recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_SUCCESS;
@@ -151,7 +157,8 @@ static apt_bool_t recog_request_recognize(mrcp_recog_state_machine_t *state_mach
        mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool);
        if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
                mrcp_message_t *response;
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up RECOGNIZE Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up RECOGNIZE Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                message->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
                apt_list_push_back(state_machine->queue,message,message->pool);
                
@@ -160,13 +167,15 @@ static apt_bool_t recog_request_recognize(mrcp_recog_state_machine_t *state_mach
                return recog_response_dispatch(state_machine,response);
        }
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t recog_response_recognize(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNIZE Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
                state_machine->recog = state_machine->active_request;
                recog_state_change(state_machine,RECOGNIZER_STATE_RECOGNIZING);
@@ -184,7 +193,8 @@ static apt_bool_t recog_request_get_result(mrcp_recog_state_machine_t *state_mac
        mrcp_message_t *response_message;
        if(state_machine->state == RECOGNIZER_STATE_RECOGNIZED) {
                /* found recognized request */
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return recog_request_dispatch(state_machine,message);
        }
 
@@ -196,7 +206,8 @@ static apt_bool_t recog_request_get_result(mrcp_recog_state_machine_t *state_mac
 
 static apt_bool_t recog_response_get_result(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-RESULT Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_response_dispatch(state_machine,message);
 }
 
@@ -205,7 +216,8 @@ static apt_bool_t recog_request_recognition_start_timers(mrcp_recog_state_machin
        mrcp_message_t *response_message;
        if(state_machine->state == RECOGNIZER_STATE_RECOGNIZING) {
                /* found in-progress request */
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return recog_request_dispatch(state_machine,message);
        }
 
@@ -217,7 +229,8 @@ static apt_bool_t recog_request_recognition_start_timers(mrcp_recog_state_machin
 
 static apt_bool_t recog_response_recognition_start_timers(mrcp_recog_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_response_dispatch(state_machine,message);
 }
 
@@ -270,7 +283,8 @@ static apt_bool_t recog_request_stop(mrcp_recog_state_machine_t *state_machine,
 
                if(!request_id_list || active_request_id_list_find(generic_header,state_machine->recog->start_line.request_id) == TRUE) {
                        /* found in-progress RECOGNIZE request, stop it */
-                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%d]",message->start_line.request_id);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+                               message->start_line.request_id);
                        return recog_request_dispatch(state_machine,message);
                }
        }
@@ -288,7 +302,8 @@ static apt_bool_t recog_response_stop(mrcp_recog_state_machine_t *state_machine,
 {
        mrcp_message_t *pending_request;
        mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        /* append active id list */
        active_request_id_list_append(generic_header,state_machine->recog->start_line.request_id);
        mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
@@ -318,7 +333,8 @@ static apt_bool_t recog_event_start_of_input(mrcp_recog_state_machine_t *state_m
                return FALSE;
        }
        
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
        return recog_event_dispatch(state_machine,message);
 }
@@ -327,12 +343,14 @@ static apt_bool_t recog_event_recognition_complete(mrcp_recog_state_machine_t *s
 {
        mrcp_message_t *pending_request;
        if(!state_machine->recog) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return FALSE;
        }
 
        if(state_machine->recog->start_line.request_id != message->start_line.request_id) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECOGNITION-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return FALSE;
        }
 
@@ -341,7 +359,8 @@ static apt_bool_t recog_event_recognition_complete(mrcp_recog_state_machine_t *s
                return FALSE;
        }
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNITION-COMPLETE Event [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECOGNITION-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(mrcp_resource_header_property_check(message,RECOGNIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
                mrcp_recog_header_t *recog_header = mrcp_resource_header_prepare(message);
                recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_SUCCESS;
@@ -478,19 +497,21 @@ static apt_bool_t recog_state_deactivate(mrcp_state_machine_t *base)
 
        /* create internal STOP request */
        message = mrcp_request_create(
-                                               source->channel_id.resource_id,
+                                               source->resource,
+                                               source->start_line.version,
                                                RECOGNIZER_STOP,
                                                source->pool);
        message->channel_id = source->channel_id;
        message->start_line.request_id = source->start_line.request_id + 1;
        apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */
        message->header = source->header;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return recog_request_dispatch(state_machine,message);
 }
 
-/** Create MRCP recognizer server state machine */
-mrcp_state_machine_t* mrcp_recog_server_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
+/** Create MRCP recognizer state machine */
+mrcp_state_machine_t* mrcp_recog_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
 {
        mrcp_message_header_t *properties;
        mrcp_recog_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_recog_state_machine_t));
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_recorder_state_machine.c
new file mode 100644 (file)
index 0000000..9692d33
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * 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 "apt_obj_list.h"
+#include "apt_log.h"
+#include "mrcp_recorder_state_machine.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recorder_header.h"
+#include "mrcp_recorder_resource.h"
+#include "mrcp_message.h"
+
+/** MRCP recorder states */
+typedef enum {
+       RECORDER_STATE_IDLE,
+       RECORDER_STATE_RECORDING,
+
+       RECORDER_STATE_COUNT
+} mrcp_recorder_state_e;
+
+static const char * state_names[RECORDER_STATE_COUNT] = {
+       "IDLE",
+       "RECORDING",
+};
+
+typedef struct mrcp_recorder_state_machine_t mrcp_recorder_state_machine_t;
+
+struct mrcp_recorder_state_machine_t {
+       /** state machine base */
+       mrcp_state_machine_t  base;
+       /** recorder state */
+       mrcp_recorder_state_e state;
+       /** request sent to recorder engine and waiting for the response to be received */
+       mrcp_message_t       *active_request;
+       /** in-progress record request */
+       mrcp_message_t       *record;
+       /** properties used in set/get params */
+       mrcp_message_header_t properties;
+};
+
+typedef apt_bool_t (*recorder_method_f)(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message);
+
+static APR_INLINE apt_bool_t recorder_request_dispatch(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = message;
+       return state_machine->base.on_dispatch(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t recorder_response_dispatch(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       state_machine->active_request = NULL;
+       if(state_machine->base.active == FALSE) {
+               /* this is the response to deactivation (STOP) request */
+               return state_machine->base.on_deactivate(&state_machine->base);
+       }
+       return state_machine->base.on_dispatch(&state_machine->base,message);
+}
+
+static APR_INLINE apt_bool_t recorder_event_dispatch(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(state_machine->base.active == FALSE) {
+               /* do nothing, state machine has already been deactivated */
+               return FALSE;
+       }
+       return state_machine->base.on_dispatch(&state_machine->base,message);
+}
+
+static APR_INLINE void recorder_state_change(mrcp_recorder_state_machine_t *state_machine, mrcp_recorder_state_e state)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"State Transition %s -> %s",state_names[state_machine->state],state_names[state]);
+       state_machine->state = state;
+       if(state == RECORDER_STATE_IDLE) {
+               state_machine->record = NULL;
+       }
+}
+
+
+static apt_bool_t recorder_request_set_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       mrcp_message_header_set(&state_machine->properties,&message->header,message->pool);
+       return recorder_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_response_set_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       return recorder_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_request_get_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       return recorder_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_response_get_params(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       mrcp_message_header_set(&message->header,&state_machine->active_request->header,message->pool);
+       mrcp_message_header_get(&message->header,&state_machine->properties,message->pool);
+       return recorder_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_request_record(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool);
+       if(state_machine->state == RECORDER_STATE_RECORDING) {
+               mrcp_message_t *response;
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Reject RECORD Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
+               
+               /* there is in-progress request, reject this one */
+               response = mrcp_response_create(message,message->pool);
+               response->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+               return recorder_response_dispatch(state_machine,response);
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       return recorder_request_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_response_record(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
+               state_machine->record = state_machine->active_request;
+               recorder_state_change(state_machine,RECORDER_STATE_RECORDING);
+       }
+       return recorder_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_request_stop(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response;
+       if(state_machine->state == RECORDER_STATE_RECORDING) {
+               /* found in-progress RECORDER request, stop it */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
+               return recorder_request_dispatch(state_machine,message);
+       }
+
+       /* found no in-progress RECORDER request, sending immediate response */
+       response = mrcp_response_create(message,message->pool);
+       return recorder_response_dispatch(state_machine,response);
+}
+
+static apt_bool_t recorder_response_stop(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       /* append active id list */
+       active_request_id_list_append(generic_header,state_machine->record->start_line.request_id);
+       mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
+       recorder_state_change(state_machine,RECORDER_STATE_IDLE);
+       return recorder_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_request_start_timers(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       mrcp_message_t *response;
+       if(state_machine->state == RECORDER_STATE_RECORDING) {
+               /* found in-progress request */
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
+               return recorder_request_dispatch(state_machine,message);
+       }
+
+       /* found no in-progress request */
+       response = mrcp_response_create(message,message->pool);
+       response->start_line.status_code = MRCP_STATUS_CODE_METHOD_NOT_VALID;
+       return recorder_response_dispatch(state_machine,response);
+}
+
+static apt_bool_t recorder_response_start_timers(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-INPUT-TIMERS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       return recorder_response_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_event_start_of_input(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(!state_machine->record) {
+               /* unexpected event, no in-progress record request */
+               return FALSE;
+       }
+
+       if(state_machine->record->start_line.request_id != message->start_line.request_id) {
+               /* unexpected event */
+               return FALSE;
+       }
+       
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process START-OF-INPUT Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       return recorder_event_dispatch(state_machine,message);
+}
+
+static apt_bool_t recorder_event_record_complete(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       if(!state_machine->record) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->record->start_line.request_id != message->start_line.request_id) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
+               return FALSE;
+       }
+
+       if(state_machine->active_request && state_machine->active_request->start_line.method_id == RECORDER_STOP) {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Ignore RECORD-COMPLETE Event [%d]: waiting for STOP response",message->start_line.request_id);
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RECORD-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       if(mrcp_resource_header_property_check(message,RECORDER_HEADER_COMPLETION_CAUSE) != TRUE) {
+               mrcp_recorder_header_t *recorder_header = mrcp_resource_header_prepare(message);
+               recorder_header->completion_cause = RECORDER_COMPLETION_CAUSE_SUCCESS_SILENCE;
+               mrcp_resource_header_property_add(message,RECORDER_HEADER_COMPLETION_CAUSE);
+       }
+       recorder_state_change(state_machine,RECORDER_STATE_IDLE);
+       return recorder_event_dispatch(state_machine,message);
+}
+
+static recorder_method_f recorder_request_method_array[RECORDER_METHOD_COUNT] = {
+       recorder_request_set_params,
+       recorder_request_get_params,
+       recorder_request_record,
+       recorder_request_stop,
+       recorder_request_start_timers
+};
+
+static recorder_method_f recorder_response_method_array[RECORDER_METHOD_COUNT] = {
+       recorder_response_set_params,
+       recorder_response_get_params,
+       recorder_response_record,
+       recorder_response_stop,
+       recorder_response_start_timers
+};
+
+static recorder_method_f recorder_event_method_array[RECORDER_EVENT_COUNT] = {
+       recorder_event_start_of_input,
+       recorder_event_record_complete
+};
+
+/** Update state according to received incoming request from MRCP client */
+static apt_bool_t recorder_request_state_update(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recorder_method_f method;
+       if(message->start_line.method_id >= RECORDER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = recorder_request_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recorder_request_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing response from recorder engine */
+static apt_bool_t recorder_response_state_update(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recorder_method_f method;
+       if(!state_machine->active_request) {
+               /* unexpected response, no active request waiting for response */
+               return FALSE;
+       }
+       if(state_machine->active_request->start_line.request_id != message->start_line.request_id) {
+               /* unexpected response, request id doesn't match */
+               return FALSE;
+       }
+
+       if(message->start_line.method_id >= RECORDER_METHOD_COUNT) {
+               return FALSE;
+       }
+       
+       method = recorder_response_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recorder_response_dispatch(state_machine,message);
+}
+
+/** Update state according to received outgoing event from recorder engine */
+static apt_bool_t recorder_event_state_update(mrcp_recorder_state_machine_t *state_machine, mrcp_message_t *message)
+{
+       recorder_method_f method;
+       if(message->start_line.method_id >= RECORDER_EVENT_COUNT) {
+               return FALSE;
+       }
+       
+       method = recorder_event_method_array[message->start_line.method_id];
+       if(method) {
+               return method(state_machine,message);
+       }
+       return recorder_event_dispatch(state_machine,message);
+}
+
+/** Update state according to request received from MRCP client or response/event received from recorder engine */
+static apt_bool_t recorder_state_update(mrcp_state_machine_t *base, mrcp_message_t *message)
+{
+       mrcp_recorder_state_machine_t *state_machine = (mrcp_recorder_state_machine_t*)base;
+       apt_bool_t status = TRUE;
+       switch(message->start_line.message_type) {
+               case MRCP_MESSAGE_TYPE_REQUEST:
+                       status = recorder_request_state_update(state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_RESPONSE:
+                       status = recorder_response_state_update(state_machine,message);
+                       break;
+               case MRCP_MESSAGE_TYPE_EVENT:
+                       status = recorder_event_state_update(state_machine,message);
+                       break;
+               default:
+                       status = FALSE;
+                       break;
+       }
+       return status;
+}
+
+/** Deactivate state machine */
+static apt_bool_t recorder_state_deactivate(mrcp_state_machine_t *base)
+{
+       mrcp_recorder_state_machine_t *state_machine = (mrcp_recorder_state_machine_t*)base;
+       mrcp_message_t *message;
+       mrcp_message_t *source;
+       if(state_machine->state != RECORDER_STATE_RECORDING) {
+               /* no in-progress RECORD request to deactivate */
+               return FALSE;
+       }
+       source = state_machine->record;
+       if(!source) {
+               return FALSE;
+       }
+
+       /* create internal STOP request */
+       message = mrcp_request_create(
+                                               source->resource,
+                                               source->start_line.version,
+                                               RECORDER_STOP,
+                                               source->pool);
+       message->channel_id = source->channel_id;
+       message->start_line.request_id = source->start_line.request_id + 1;
+       apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */
+       message->header = source->header;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
+       return recorder_request_dispatch(state_machine,message);
+}
+
+/** Create MRCP recorder state machine */
+mrcp_state_machine_t* mrcp_recorder_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
+{
+       mrcp_message_header_t *properties;
+       mrcp_recorder_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_recorder_state_machine_t));
+       mrcp_state_machine_init(&state_machine->base,obj);
+       state_machine->base.update = recorder_state_update;
+       state_machine->base.deactivate = recorder_state_deactivate;
+       state_machine->state = RECORDER_STATE_IDLE;
+       state_machine->active_request = NULL;
+       state_machine->record = NULL;
+       properties = &state_machine->properties;
+       mrcp_message_header_init(properties);
+       properties->generic_header_accessor.vtable = mrcp_generic_header_vtable_get(version);
+       properties->resource_header_accessor.vtable = mrcp_recorder_header_vtable_get(version);
+       return &state_machine->base;
+}
diff --git a/libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c b/libs/unimrcp/libs/mrcp-engine/src/mrcp_resource_engine.c
deleted file mode 100644 (file)
index 54939d9..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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 "mrcp_resource_engine.h"
-#include "mpf_codec_manager.h"
-
-/** Create resource engine */
-mrcp_resource_engine_t* mrcp_resource_engine_create(
-                                                               mrcp_resource_id resource_id,
-                                                               void *obj, 
-                                                               const mrcp_engine_method_vtable_t *vtable,
-                                                               apr_pool_t *pool)
-{
-       mrcp_resource_engine_t *engine = apr_palloc(pool,sizeof(mrcp_resource_engine_t));
-       mrcp_plugin_version_get(&engine->plugin_version);
-       engine->resource_id = resource_id;
-       engine->obj = obj;
-       engine->method_vtable =vtable;
-       engine->codec_manager = NULL;
-       engine->dir_layout = NULL;
-       engine->pool = pool;
-       return engine;
-}
-
-/** Create engine channel */
-mrcp_engine_channel_t* mrcp_engine_channel_create(
-                                                               mrcp_resource_engine_t *engine, 
-                                                               const mrcp_engine_channel_method_vtable_t *method_vtable,
-                                                               void *method_obj,
-                                                               mpf_termination_t *termination,
-                                                               apr_pool_t *pool)
-{
-       mrcp_engine_channel_t *channel = apr_palloc(pool,sizeof(mrcp_engine_channel_t));
-       channel->method_vtable = method_vtable;
-       channel->method_obj = method_obj;
-       channel->event_vtable = NULL;
-       channel->event_obj = NULL;
-       channel->termination = termination;
-       channel->engine = engine;
-       channel->pool = pool;
-       apt_string_reset(&channel->id);
-       return channel;
-}
-
-/** Create engine channel and source media termination */
-mrcp_engine_channel_t* mrcp_engine_source_channel_create(
-                                                               mrcp_resource_engine_t *engine,
-                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
-                                                               const mpf_audio_stream_vtable_t *stream_vtable,
-                                                               void *method_obj,
-                                                               mpf_codec_descriptor_t *codec_descriptor,
-                                                               apr_pool_t *pool)
-{
-       mpf_audio_stream_t *audio_stream;
-       mpf_termination_t *termination;
-       /* create audio stream */
-       audio_stream = mpf_audio_stream_create(
-                       method_obj,           /* object to associate */
-                       stream_vtable,        /* virtual methods table of audio stream */
-                       STREAM_MODE_RECEIVE,  /* stream mode/direction */
-                       pool);                /* pool to allocate memory from */
-
-       if(engine->codec_manager) {
-               audio_stream->rx_codec = mpf_codec_manager_codec_get(engine->codec_manager,codec_descriptor,pool);
-       }
-       
-       /* create media termination */
-       termination = mpf_raw_termination_create(
-                       NULL,                 /* no object to associate */
-                       audio_stream,         /* audio stream */
-                       NULL,                 /* no video stream */
-                       pool);                /* pool to allocate memory from */
-
-       /* create engine channel base */
-       return mrcp_engine_channel_create(
-                       engine,          /* resource engine */
-                       channel_vtable,  /* virtual methods table of engine channel */
-                       method_obj,      /* object to associate */
-                       termination,     /* media termination, used to terminate audio stream */
-                       pool);           /* pool to allocate memory from */
-}
-
-/** Create engine channel and sink media termination */
-mrcp_engine_channel_t* mrcp_engine_sink_channel_create(
-                                                               mrcp_resource_engine_t *engine,
-                                                               const mrcp_engine_channel_method_vtable_t *channel_vtable,
-                                                               const mpf_audio_stream_vtable_t *stream_vtable,
-                                                               void *method_obj,
-                                                               mpf_codec_descriptor_t *codec_descriptor,
-                                                               apr_pool_t *pool)
-{
-       mpf_audio_stream_t *audio_stream;
-       mpf_termination_t *termination;
-
-       /* create audio stream */
-       audio_stream = mpf_audio_stream_create(
-                       method_obj,             /* object to associate */
-                       stream_vtable,          /* virtual methods table of audio stream */
-                       STREAM_MODE_SEND,       /* stream mode/direction */
-                       pool);                  /* pool to allocate memory from */
-       
-       if(engine->codec_manager) {
-               audio_stream->tx_codec = mpf_codec_manager_codec_get(engine->codec_manager,codec_descriptor,pool);
-       }
-       
-       /* create media termination */
-       termination = mpf_raw_termination_create(
-                       NULL,            /* no object to associate */
-                       audio_stream,    /* audio stream */
-                       NULL,            /* no video stream */
-                       pool);           /* pool to allocate memory from */
-
-       /* create engine channel base */
-       return mrcp_engine_channel_create(
-                       engine,          /* resource engine */
-                       channel_vtable,  /* virtual methods table of engine channel */
-                       method_obj,      /* object to associate */
-                       termination,     /* media termination, used to terminate audio stream */
-                       pool);           /* pool to allocate memory from */
-}
-
-/** Get codec of the audio source stream */
-mpf_codec_t* mrcp_engine_source_stream_codec_get(mrcp_engine_channel_t *channel)
-{
-       if(channel && channel->termination && channel->termination->audio_stream) {
-               return channel->termination->audio_stream->rx_codec;
-       }
-       return NULL;
-}
-
-/** Get codec of the audio sink stream */
-mpf_codec_t* mrcp_engine_sink_stream_codec_get(mrcp_engine_channel_t *channel)
-{
-       if(channel && channel->termination && channel->termination->audio_stream) {
-               return channel->termination->audio_stream->tx_codec;
-       }
-       return NULL;
-}
similarity index 91%
rename from libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_server_state_machine.c
rename to libs/unimrcp/libs/mrcp-engine/src/mrcp_synth_state_machine.c
index 73ed63e953d4ac5391889a53b97599ebef6adf3d..01ff0af30f4b11b26a30af61894d4fc643b1507f 100644 (file)
@@ -95,26 +95,30 @@ static APR_INLINE void synth_state_change(mrcp_synth_state_machine_t *state_mach
 
 static apt_bool_t synth_request_set_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        mrcp_message_header_set(&state_machine->properties,&message->header,message->pool);
        return synth_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t synth_response_set_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return synth_response_dispatch(state_machine,message);
 }
 
 static apt_bool_t synth_request_get_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return synth_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t synth_response_get_params(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process GET-PARAMS Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        mrcp_message_header_set(&message->header,&state_machine->active_request->header,message->pool);
        mrcp_message_header_get(&message->header,&state_machine->properties,message->pool);
        return synth_response_dispatch(state_machine,message);
@@ -125,7 +129,8 @@ static apt_bool_t synth_request_speak(mrcp_synth_state_machine_t *state_machine,
        mrcp_message_header_inherit(&message->header,&state_machine->properties,message->pool);
        if(state_machine->speaker) {
                mrcp_message_t *response;
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up SPEAK Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Queue Up SPEAK Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                message->start_line.request_state = MRCP_REQUEST_STATE_PENDING;
                apt_list_push_back(state_machine->queue,message,message->pool);
                
@@ -134,13 +139,15 @@ static apt_bool_t synth_request_speak(mrcp_synth_state_machine_t *state_machine,
                return synth_response_dispatch(state_machine,response);
        }
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return synth_request_dispatch(state_machine,message);
 }
 
 static apt_bool_t synth_response_speak(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
                state_machine->speaker = state_machine->active_request;
                synth_state_change(state_machine,SYNTHESIZER_STATE_SPEAKING);
@@ -207,7 +214,8 @@ static apt_bool_t synth_request_stop(mrcp_synth_state_machine_t *state_machine,
 
                if(!request_id_list || active_request_id_list_find(generic_header,state_machine->speaker->start_line.request_id) == TRUE) {
                        /* found in-progress SPEAK request, stop it */
-                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%d]",message->start_line.request_id);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+                               message->start_line.request_id);
                        return synth_request_dispatch(state_machine,message);
                }
        }
@@ -222,7 +230,8 @@ static apt_bool_t synth_response_stop(mrcp_synth_state_machine_t *state_machine,
 {
        mrcp_message_t *pending_request;
        mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process STOP Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        /* append active id list */
        active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
        mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
@@ -265,7 +274,8 @@ static apt_bool_t synth_request_pause(mrcp_synth_state_machine_t *state_machine,
 
 static apt_bool_t synth_response_pause(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process PAUSE Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process PAUSE Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(message->start_line.status_code == MRCP_STATUS_CODE_SUCCESS) {
                mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
                /* append active id list */
@@ -302,7 +312,8 @@ static apt_bool_t synth_request_resume(mrcp_synth_state_machine_t *state_machine
 
 static apt_bool_t synth_response_resume(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RESUME Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process RESUME Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(message->start_line.status_code == MRCP_STATUS_CODE_SUCCESS) {
                mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
                /* append active id list */
@@ -327,7 +338,8 @@ static apt_bool_t synth_request_barge_in_occurred(mrcp_synth_state_machine_t *st
                }
        
                if(kill_on_barge_in == TRUE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Request [%d]",message->start_line.request_id);
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Request [%"MRCP_REQUEST_ID_FMT"]",
+                               message->start_line.request_id);
                        return synth_request_dispatch(state_machine,message);
                }
        }
@@ -340,7 +352,8 @@ static apt_bool_t synth_request_barge_in_occurred(mrcp_synth_state_machine_t *st
 static apt_bool_t synth_response_barge_in_occurred(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
        mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process BARGE-IN Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        /* append active id list */
        active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
        mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
@@ -353,7 +366,8 @@ static apt_bool_t synth_request_control(mrcp_synth_state_machine_t *state_machin
 {
        mrcp_message_t *response_message;
        if(state_machine->state == SYNTHESIZER_STATE_SPEAKING) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return synth_request_dispatch(state_machine,message);
        }
 
@@ -365,7 +379,8 @@ static apt_bool_t synth_request_control(mrcp_synth_state_machine_t *state_machin
 static apt_bool_t synth_response_control(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
        mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process CONTROL Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        /* append active id list */
        active_request_id_list_append(generic_header,state_machine->speaker->start_line.request_id);
        mrcp_generic_header_property_add(message,GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST);
@@ -376,7 +391,8 @@ static apt_bool_t synth_request_define_lexicon(mrcp_synth_state_machine_t *state
 {
        mrcp_message_t *response_message;
        if(state_machine->state == SYNTHESIZER_STATE_IDLE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Request [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Request [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return synth_request_dispatch(state_machine,message);
        }
 
@@ -388,7 +404,8 @@ static apt_bool_t synth_request_define_lexicon(mrcp_synth_state_machine_t *state
 
 static apt_bool_t synth_response_define_lexicon(mrcp_synth_state_machine_t *state_machine, mrcp_message_t *message)
 {
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Response [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process DEFINE-LEXICON Response [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return synth_response_dispatch(state_machine,message);
 }
 
@@ -404,7 +421,8 @@ static apt_bool_t synth_event_speech_marker(mrcp_synth_state_machine_t *state_ma
                return FALSE;
        }
        
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEECH-MARKER Event [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEECH-MARKER Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
        return synth_event_dispatch(state_machine,message);
 }
@@ -413,12 +431,14 @@ static apt_bool_t synth_event_speak_complete(mrcp_synth_state_machine_t *state_m
 {
        mrcp_message_t *pending_request;
        if(!state_machine->speaker) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return FALSE;
        }
 
        if(state_machine->speaker->start_line.request_id != message->start_line.request_id) {
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unexpected SPEAK-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+                       message->start_line.request_id);
                return FALSE;
        }
 
@@ -427,7 +447,8 @@ static apt_bool_t synth_event_speak_complete(mrcp_synth_state_machine_t *state_m
                return FALSE;
        }
 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK-COMPLETE Event [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Process SPEAK-COMPLETE Event [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        if(mrcp_resource_header_property_check(message,SYNTHESIZER_HEADER_COMPLETION_CAUSE) != TRUE) {
                mrcp_synth_header_t *synth_header = mrcp_resource_header_prepare(message);
                synth_header->completion_cause = SYNTHESIZER_COMPLETION_CAUSE_NORMAL;
@@ -565,19 +586,21 @@ static apt_bool_t synth_state_deactivate(mrcp_state_machine_t *base)
 
        /* create internal STOP request */
        message = mrcp_request_create(
-                                               source->channel_id.resource_id,
+                                               source->resource,
+                                               source->start_line.version,
                                                SYNTHESIZER_STOP,
                                                source->pool);
        message->channel_id = source->channel_id;
        message->start_line.request_id = source->start_line.request_id + 1;
        apt_string_set(&message->start_line.method_name,"DEACTIVATE"); /* informative only */
        message->header = source->header;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%d]",message->start_line.request_id);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create and Process STOP Request [%"MRCP_REQUEST_ID_FMT"]",
+               message->start_line.request_id);
        return synth_request_dispatch(state_machine,message);
 }
 
-/** Create MRCP synthesizer server state machine */
-mrcp_state_machine_t* mrcp_synth_server_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
+/** Create MRCP synthesizer state machine */
+mrcp_state_machine_t* mrcp_synth_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
 {
        mrcp_message_header_t *properties;
        mrcp_synth_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_synth_state_machine_t));
index e4946364b166684ee74295273d94274a114a2def..59a33db05906d7677514bfb350ed0aa8b8caab83 100644 (file)
@@ -23,7 +23,7 @@
  */ 
 
 #include "mrcp_server_types.h"
-#include "mrcp_resource_engine.h"
+#include "mrcp_engine_iface.h"
 #include "apt_task.h"
 
 APT_BEGIN_EXTERN_C
@@ -62,12 +62,12 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_destroy(mrcp_server_t *server);
 MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register(mrcp_server_t *server, mrcp_resource_factory_t *resource_factory);
 
 /**
- * Register MRCP resource engine.
+ * Register MRCP engine.
  * @param server the MRCP server to set engine for
- * @param engine the resource engine to set
- * @param name the name of the resource engine
+ * @param engine the engine to set
+ * @param config the config of the engine
  */
-MRCP_DECLARE(apt_bool_t) mrcp_server_resource_engine_register(mrcp_server_t *server, mrcp_resource_engine_t *engine, const char *name);
+MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register(mrcp_server_t *server, mrcp_engine_t *engine, mrcp_engine_config_t *config);
 
 /**
  * Register codec manager.
@@ -127,7 +127,7 @@ MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_create(
  * Register MRCP profile.
  * @param server the MRCP server to set profile for
  * @param profile the profile to set
- * @param plugin_map the map of resource engines (plugins)
+ * @param plugin_map the map of engines (plugins)
  * @param name the name of the profile
  */
 MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register(
@@ -137,12 +137,12 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register(
                                                                        const char *name);
 
 /**
- * Register resource engine plugin.
+ * Register MRCP engine plugin.
  * @param server the MRCP server to set engine for
  * @param path the path to plugin
- * @param name the name of the plugin
+ * @param config the config of the plugin
  */
-MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, const char *name);
+MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, mrcp_engine_config_t *config);
 
 /**
  * Get memory pool.
@@ -150,13 +150,6 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, cons
  */
 MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(mrcp_server_t *server);
 
-/**
- * Get resource engine by name.
- * @param server the MRCP server to get resource engine from
- * @param name the name of the resource engine to lookup
- */
-MRCP_DECLARE(mrcp_resource_engine_t*) mrcp_server_resource_engine_get(mrcp_server_t *server, const char *name);
-
 /**
  * Get media engine by name.
  * @param server the MRCP server to get media engine from
index 7af9884e5de98f8d82f2aaf5dd653c509835289f..4cd88f6b3e8c22d8be3b57a975b5d18804619906 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <apr_hash.h>
 #include "mrcp_session.h"
-#include "mpf_message.h"
+#include "mpf_engine.h"
 #include "apt_task.h"
 #include "apt_obj_list.h"
 
@@ -61,45 +61,55 @@ struct mrcp_signaling_message_t {
        mrcp_message_t               *message;
 };
 
+/** Server session states */
+typedef enum {
+       SESSION_STATE_NONE,              /**< initial state */
+       SESSION_STATE_GENERATING_ANSWER, /**< received offer, generating answer now */
+       SESSION_STATE_INITIALIZING,      /**< answer is ready, finally initializing channels now */
+       SESSION_STATE_DEACTIVATING,      /**< received session termination request, deinitializing channels now */
+       SESSION_STATE_TERMINATING        /**< finally terminating session */
+} mrcp_server_session_state_e;
+
 
 /** MRCP server session */
 struct mrcp_server_session_t {
        /** Session base */
-       mrcp_session_t             base;
+       mrcp_session_t              base;
        /** MRCP server */
-       mrcp_server_t             *server;
+       mrcp_server_t              *server;
        /** MRCP profile */
-       mrcp_profile_t            *profile;
+       mrcp_profile_t             *profile;
 
        /** Media context */
-       mpf_context_t             *context;
+       mpf_context_t              *context;
 
        /** Media termination array */
-       apr_array_header_t        *terminations;
+       apr_array_header_t         *terminations;
        /** MRCP control channel array */
-       apr_array_header_t        *channels;
+       apr_array_header_t         *channels;
 
        /** In-progress signaling request */
-       mrcp_signaling_message_t  *active_request;
+       mrcp_signaling_message_t   *active_request;
        /** Signaling request queue */
-       apt_obj_list_t            *request_queue;
+       apt_obj_list_t             *request_queue;
 
        /** In-progress offer */
-       mrcp_session_descriptor_t *offer;
+       mrcp_session_descriptor_t  *offer;
        /** In-progres answer */
-       mrcp_session_descriptor_t *answer;
-
-       /** Number of in-progress answer requests (flags) */
-       apr_size_t                 answer_flag_count;
-       /** Number of in-progress terminate requests (flags) */
-       apr_size_t                 terminate_flag_count;
-       /** Number of in-progress deactivare requests (flags) */
-       apr_size_t                 deactivate_flag_count;
+       mrcp_session_descriptor_t  *answer;
+
+       /** MPF task message, which construction is in progress */
+       mpf_task_msg_t             *mpf_task_msg;
+
+       /** Session state */
+       mrcp_server_session_state_e state;
+       /** Number of in-progress sub requests */
+       apr_size_t                  subrequest_count;
 };
 
 /** MRCP profile */
 struct mrcp_profile_t {
-       /** Table of resource engines (mrcp_resource_engine_t*) */
+       /** Table of engines (mrcp_engine_t*) */
        apr_hash_t                *engine_table;
        /** MRCP resource factory */
        mrcp_resource_factory_t   *resource_factory;
@@ -114,12 +124,12 @@ struct mrcp_profile_t {
 };
 
 /** Create server session */
-mrcp_server_session_t* mrcp_server_session_create();
+mrcp_server_session_t* mrcp_server_session_create(void);
 
 /** Process signaling message */
 apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signaling_message);
 /** Process MPF message */
-apt_bool_t mrcp_server_mpf_message_process(mpf_message_t *mpf_message);
+apt_bool_t mrcp_server_mpf_message_process(mpf_message_container_t *mpf_message_container);
 
 /** Process channel modify event */
 apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *answer, apt_bool_t status);
@@ -127,6 +137,8 @@ apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d
 apt_bool_t mrcp_server_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status);
 /** Process channel message receive */
 apt_bool_t mrcp_server_on_channel_message(mrcp_channel_t *channel, mrcp_message_t *message);
+/** Process connection disconnect event */
+apt_bool_t mrcp_server_on_disconnect(mrcp_channel_t *channel);
 
 /** Process channel open event */
 apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_t status);
index 01d03c8d877df4e9c3d3b07a30be4c1e39aceb41..0c8d2a8a07920b85b72f939adff920ec6da527b8 100644 (file)
  * limitations under the License.
  */
 
-#include <apr_dso.h>
 #include "mrcp_server.h"
 #include "mrcp_server_session.h"
 #include "mrcp_message.h"
 #include "mrcp_resource_factory.h"
+#include "mrcp_resource.h"
+#include "mrcp_engine_factory.h"
+#include "mrcp_engine_loader.h"
 #include "mrcp_sig_agent.h"
 #include "mrcp_server_connection.h"
 #include "mpf_engine.h"
@@ -36,10 +38,13 @@ struct mrcp_server_t {
 
        /** MRCP resource factory */
        mrcp_resource_factory_t *resource_factory;
+       /** MRCP engine factory */
+       mrcp_engine_factory_t   *engine_factory;
+       /** Loader of plugins for MRCP engines */
+       mrcp_engine_loader_t    *engine_loader;
+
        /** Codec manager */
        mpf_codec_manager_t     *codec_manager;
-       /** Table of resource engines (mrcp_resource_engine_t*) */
-       apr_hash_t              *resource_engine_table;
        /** Table of media processing engines (mpf_engine_t*) */
        apr_hash_t              *media_engine_table;
        /** Table of RTP termination factories (mpf_termination_factory_t*) */
@@ -50,16 +55,14 @@ struct mrcp_server_t {
        apr_hash_t              *cnt_agent_table;
        /** Table of profiles (mrcp_profile_t*) */
        apr_hash_t              *profile_table;
-       /** Table of plugins (apr_dso_handle_t*) */
-       apr_hash_t              *plugin_table;
 
        /** Table of sessions */
        apr_hash_t              *session_table;
 
        /** Connection task message pool */
        apt_task_msg_pool_t     *connection_msg_pool;
-       /** Resource engine task message pool */
-       apt_task_msg_pool_t     *resource_engine_msg_pool;
+       /** Engine task message pool */
+       apt_task_msg_pool_t     *engine_msg_pool;
 
        /** Dir layout structure */
        apt_dir_layout_t        *dir_layout;
@@ -73,7 +76,7 @@ struct mrcp_server_t {
 typedef enum {
        MRCP_SERVER_SIGNALING_TASK_MSG = TASK_MSG_USER,
        MRCP_SERVER_CONNECTION_TASK_MSG,
-       MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG,
+       MRCP_SERVER_ENGINE_TASK_MSG,
        MRCP_SERVER_MEDIA_TASK_MSG
 } mrcp_server_task_msg_type_e;
 
@@ -95,7 +98,7 @@ typedef enum {
        CONNECTION_AGENT_TASK_MSG_MODIFY_CHANNEL,
        CONNECTION_AGENT_TASK_MSG_REMOVE_CHANNEL,
        CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,
-       CONNECTION_AGENT_TASK_MSG_TERMINATE
+       CONNECTION_AGENT_TASK_MSG_DISCONNECT
 } connection_agent_task_msg_type_e;
 
 typedef struct connection_agent_task_msg_data_t connection_agent_task_msg_data_t;
@@ -110,24 +113,26 @@ static apt_bool_t mrcp_server_channel_add_signal(mrcp_control_channel_t *channel
 static apt_bool_t mrcp_server_channel_modify_signal(mrcp_control_channel_t *channel, mrcp_control_descriptor_t *descriptor, apt_bool_t status);
 static apt_bool_t mrcp_server_channel_remove_signal(mrcp_control_channel_t *channel, apt_bool_t status);
 static apt_bool_t mrcp_server_message_signal(mrcp_control_channel_t *channel, mrcp_message_t *message);
+static apt_bool_t mrcp_server_disconnect_signal(mrcp_control_channel_t *channel);
 
 static const mrcp_connection_event_vtable_t connection_method_vtable = {
        mrcp_server_channel_add_signal,
        mrcp_server_channel_modify_signal,
        mrcp_server_channel_remove_signal,
-       mrcp_server_message_signal
+       mrcp_server_message_signal,
+       mrcp_server_disconnect_signal
 };
 
 
-/* Resource engine interface */
+/* MRCP engine interface */
 typedef enum {
-       RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL,
-       RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL,
-       RESOURCE_ENGINE_TASK_MSG_MESSAGE
-} resource_engine_task_msg_type_e;
+       ENGINE_TASK_MSG_OPEN_CHANNEL,
+       ENGINE_TASK_MSG_CLOSE_CHANNEL,
+       ENGINE_TASK_MSG_MESSAGE
+} engine_task_msg_type_e;
 
-typedef struct resource_engine_task_msg_data_t resource_engine_task_msg_data_t;
-struct resource_engine_task_msg_data_t {
+typedef struct engine_task_msg_data_t engine_task_msg_data_t;
+struct engine_task_msg_data_t {
        mrcp_channel_t *channel;
        apt_bool_t      status;
        mrcp_message_t *mrcp_message;
@@ -170,16 +175,16 @@ MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout)
        server->pool = pool;
        server->dir_layout = dir_layout;
        server->resource_factory = NULL;
-       server->resource_engine_table = NULL;
+       server->engine_factory = NULL;
+       server->engine_loader = NULL;
        server->media_engine_table = NULL;
        server->rtp_factory_table = NULL;
        server->sig_agent_table = NULL;
        server->cnt_agent_table = NULL;
        server->profile_table = NULL;
-       server->plugin_table = NULL;
        server->session_table = NULL;
        server->connection_msg_pool = NULL;
-       server->resource_engine_msg_pool = NULL;
+       server->engine_msg_pool = NULL;
 
        msg_pool = apt_task_msg_pool_create_dynamic(0,pool);
 
@@ -197,14 +202,15 @@ MRCP_DECLARE(mrcp_server_t*) mrcp_server_create(apt_dir_layout_t *dir_layout)
                vtable->on_terminate_complete = mrcp_server_on_terminate_complete;
        }
 
-       server->resource_engine_table = apr_hash_make(server->pool);
+       server->engine_factory = mrcp_engine_factory_create(server->pool);
+       server->engine_loader = mrcp_engine_loader_create(server->pool);
+
        server->media_engine_table = apr_hash_make(server->pool);
        server->rtp_factory_table = apr_hash_make(server->pool);
        server->sig_agent_table = apr_hash_make(server->pool);
        server->cnt_agent_table = apr_hash_make(server->pool);
 
        server->profile_table = apr_hash_make(server->pool);
-       server->plugin_table = apr_hash_make(server->pool);
        
        server->session_table = apr_hash_make(server->pool);
        return server;
@@ -255,6 +261,10 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_destroy(mrcp_server_t *server)
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Server");
                return FALSE;
        }
+
+       mrcp_engine_factory_destroy(server->engine_factory);
+       mrcp_engine_loader_destroy(server->engine_loader);
+
        task = apt_consumer_task_base_get(server->task);
        apt_task_destroy(task);
 
@@ -273,26 +283,20 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_resource_factory_register(mrcp_server_t *se
        return TRUE;
 }
 
-/** Register MRCP resource engine */
-MRCP_DECLARE(apt_bool_t) mrcp_server_resource_engine_register(mrcp_server_t *server, mrcp_resource_engine_t *engine, const char *name)
+/** Register MRCP engine */
+MRCP_DECLARE(apt_bool_t) mrcp_server_engine_register(mrcp_server_t *server, mrcp_engine_t *engine, mrcp_engine_config_t *config)
 {
-       if(!engine || !name) {
+       if(!engine || !config || !config->name) {
                return FALSE;
        }
-       if(!server->resource_engine_msg_pool) {
-               server->resource_engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(resource_engine_task_msg_data_t),server->pool);
+       if(!server->engine_msg_pool) {
+               server->engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(engine_task_msg_data_t),server->pool);
        }
+       engine->config = config;
        engine->codec_manager = server->codec_manager;
        engine->dir_layout = server->dir_layout;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Resource Engine [%s]",name);
-       apr_hash_set(server->resource_engine_table,name,APR_HASH_KEY_STRING,engine);
-       return TRUE;
-}
-
-/** Get resource engine by name */
-MRCP_DECLARE(mrcp_resource_engine_t*) mrcp_server_resource_engine_get(mrcp_server_t *server, const char *name)
-{
-       return apr_hash_get(server->resource_engine_table,name,APR_HASH_KEY_STRING);
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register MRCP Engine [%s]",config->name);
+       return mrcp_engine_factory_engine_register(server->engine_factory,engine,config->name);
 }
 
 /** Register codec manager */
@@ -424,48 +428,37 @@ MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_create(
 static apt_bool_t mrcp_server_engine_table_make(mrcp_server_t *server, mrcp_profile_t *profile, apr_table_t *plugin_map)
 {
        int i;
-       const apt_str_t *resource_name;
+       mrcp_resource_t *resource;
        const char *plugin_name = NULL;
-       mrcp_resource_engine_t *resource_engine;
+       mrcp_engine_t *engine;
 
        profile->engine_table = apr_hash_make(server->pool);
        for(i=0; i<MRCP_RESOURCE_TYPE_COUNT; i++) {
-               resource_name = mrcp_resource_name_get(server->resource_factory,i);
-               if(!resource_name) continue;
+               resource = mrcp_resource_get(server->resource_factory,i);
+               if(!resource) continue;
                
-               resource_engine = NULL;
+               engine = NULL;
                /* first, try to find engine by name specified in plugin map (if available) */
                if(plugin_map) {
-                       plugin_name = apr_table_get(plugin_map,resource_name->buf);
+                       plugin_name = apr_table_get(plugin_map,resource->name.buf);
                        if(plugin_name) {
-                               resource_engine = mrcp_server_resource_engine_get(server,plugin_name);
+                               engine = mrcp_engine_factory_engine_get(server->engine_factory,plugin_name);
                        }
                }
 
-               /* next, if no engine found, try to find the first available engine */
-               if(!resource_engine) {
-                       mrcp_resource_engine_t *cur_engine;
-                       void *val;
-                       apr_hash_index_t *it = apr_hash_first(server->pool,server->resource_engine_table);
-                       /* walk through the list of engines */
-                       for(; it; it = apr_hash_next(it)) {
-                               apr_hash_this(it,(void*)&plugin_name,NULL,&val);
-                               cur_engine = val;
-                               if(cur_engine && cur_engine->resource_id == (mrcp_resource_id)i) {
-                                       resource_engine = cur_engine;
-                                       break;
-                               }
-                       }
+               /* next, if no engine found or specified, try to find the first available one */
+               if(!engine) {
+                       engine = mrcp_engine_factory_engine_find(server->engine_factory,i);
                }
                
-               if(resource_engine) {
-                       if(plugin_name) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Assign Resource Engine [%s] [%s]",resource_name->buf,plugin_name);
+               if(engine) {
+                       if(engine->config->name) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Assign MRCP Engine [%s] [%s]",resource->name.buf,engine->config->name);
                        }
-                       apr_hash_set(profile->engine_table,resource_name->buf,resource_name->length,resource_engine);
+                       apr_hash_set(profile->engine_table,resource->name.buf,resource->name.length,engine);
                }
                else {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Resource Engine Available [%s]",resource_name->buf);
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No MRCP Engine Available [%s]",resource->name.buf);
                }
        }
 
@@ -484,6 +477,10 @@ MRCP_DECLARE(apt_bool_t) mrcp_server_profile_register(
                return FALSE;
        }
        if(!profile->resource_factory) {
+               if(!server->resource_factory) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Profile: no resources");
+                       return FALSE;
+               }
                profile->resource_factory = server->resource_factory;
        }
        mrcp_server_engine_table_make(server,profile,plugin_map);
@@ -517,74 +514,27 @@ MRCP_DECLARE(mrcp_profile_t*) mrcp_server_profile_get(mrcp_server_t *server, con
        return apr_hash_get(server->profile_table,name,APR_HASH_KEY_STRING);
 }
 
-/** Register resource engine plugin */
-MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, const char *name)
+/** Register MRCP engine plugin */
+MRCP_DECLARE(apt_bool_t) mrcp_server_plugin_register(mrcp_server_t *server, const char *path, mrcp_engine_config_t *config)
 {
-       apt_bool_t status = FALSE;
-       apr_dso_handle_t *plugin = NULL;
-       apr_dso_handle_sym_t func_handle = NULL;
-       mrcp_plugin_creator_f plugin_creator = NULL;
-       if(!path || !name) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Register Plugin: no name");
+       mrcp_engine_t *engine;
+       if(!config) {
                return FALSE;
        }
-
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register Plugin [%s] [%s]",path,name);
-       if(apr_dso_load(&plugin,path,server->pool) == APR_SUCCESS) {
-               if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_ENGINE_SYM_NAME) == APR_SUCCESS) {
-                       if(func_handle) {
-                               plugin_creator = (mrcp_plugin_creator_f)(intptr_t)func_handle;
-                       }
-               }
-               else {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO Symbol: "MRCP_PLUGIN_ENGINE_SYM_NAME);
-                       apr_dso_unload(plugin);
-                       return FALSE;
-               }
-               
-               if(apr_dso_sym(&func_handle,plugin,MRCP_PLUGIN_LOGGER_SYM_NAME) == APR_SUCCESS) {
-                       if(func_handle) {
-                               apt_logger_t *logger = apt_log_instance_get();
-                               mrcp_plugin_log_accessor_f log_accessor;
-                               log_accessor = (mrcp_plugin_log_accessor_f)(intptr_t)func_handle;
-                               log_accessor(logger);
-                       }
-               }
-       }
-       else {
-               char derr[512] = "";
-               apr_dso_error(plugin,derr,sizeof(derr));
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load DSO: %s", derr);
+       
+       engine = mrcp_engine_loader_plugin_load(server->engine_loader,path,config->name);
+       if(!engine) {
                return FALSE;
        }
 
-       if(plugin_creator) {
-               mrcp_resource_engine_t *engine = plugin_creator(server->pool);
-               if(engine) {
-                       if(mrcp_plugin_version_check(&engine->plugin_version)) {
-                               status = TRUE;
-                               mrcp_server_resource_engine_register(server,engine,name);
-                               apr_hash_set(server->plugin_table,name,APR_HASH_KEY_STRING,plugin);
-                       }
-                       else {
-                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Incompatible Plugin Version [%d.%d.%d] < ["PLUGIN_VERSION_STRING"]",
-                                       engine->plugin_version.major,
-                                       engine->plugin_version.minor,
-                                       engine->plugin_version.patch);
-                       }
-               }
-               else {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine");
-               }
+       if(!server->engine_msg_pool) {
+               server->engine_msg_pool = apt_task_msg_pool_create_dynamic(sizeof(engine_task_msg_data_t),server->pool);
        }
-       else {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Entry Point Found for Plugin");
-       }
-
-       if(status == FALSE) {
-               apr_dso_unload(plugin);
-       }
-       return status;
+       engine->config = config;
+       engine->codec_manager = server->codec_manager;
+       engine->dir_layout = server->dir_layout;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Register MRCP Engine [%s]",config->name);
+       return mrcp_engine_factory_engine_register(server->engine_factory,engine,config->name);
 }
 
 MRCP_DECLARE(apr_pool_t*) mrcp_server_memory_pool_get(mrcp_server_t *server)
@@ -613,22 +563,13 @@ static APR_INLINE mrcp_server_session_t* mrcp_server_session_find(mrcp_server_t
        return apr_hash_get(server->session_table,session_id->buf,session_id->length);
 }
 
+
 static void mrcp_server_on_start_complete(apt_task_t *task)
 {
        apt_consumer_task_t *consumer_task = apt_task_object_get(task);
        mrcp_server_t *server = apt_consumer_task_object_get(consumer_task);
-       mrcp_resource_engine_t *resource_engine;
-       apr_hash_index_t *it;
-       void *val;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Resource Engines");
-       it = apr_hash_first(server->pool,server->resource_engine_table);
-       for(; it; it = apr_hash_next(it)) {
-               apr_hash_this(it,NULL,NULL,&val);
-               resource_engine = val;
-               if(resource_engine) {
-                       mrcp_resource_engine_open(resource_engine);
-               }
-       }
+
+       mrcp_engine_factory_open(server->engine_factory);
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Started");
 }
 
@@ -636,28 +577,8 @@ static void mrcp_server_on_terminate_complete(apt_task_t *task)
 {
        apt_consumer_task_t *consumer_task = apt_task_object_get(task);
        mrcp_server_t *server = apt_consumer_task_object_get(consumer_task);
-       mrcp_resource_engine_t *resource_engine;
-       apr_dso_handle_t *plugin;
-       apr_hash_index_t *it;
-       void *val;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Resource Engines");
-       it=apr_hash_first(server->pool,server->resource_engine_table);
-       for(; it; it = apr_hash_next(it)) {
-               apr_hash_this(it,NULL,NULL,&val);
-               resource_engine = val;
-               if(resource_engine) {
-                       mrcp_resource_engine_close(resource_engine);
-               }
-       }
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Unload Plugins");
-       it=apr_hash_first(server->pool,server->plugin_table);
-       for(; it; it = apr_hash_next(it)) {
-               apr_hash_this(it,NULL,NULL,&val);
-               plugin = val;
-               if(plugin) {
-                       apr_dso_unload(plugin);
-               }
-       }
+
+       mrcp_engine_factory_close(server->engine_factory);
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,SERVER_TASK_NAME" Terminated");
 }
 
@@ -696,23 +617,28 @@ static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg)
                                        mrcp_server_on_channel_message(connection_message->channel, connection_message->message);
                                        break;
                                }
+                               case CONNECTION_AGENT_TASK_MSG_DISCONNECT:
+                               {
+                                       mrcp_server_on_channel_message(connection_message->channel, connection_message->message);
+                                       break;
+                               }
                                default:
                                        break;
                        }
                        break;
                }
-               case MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG:
+               case MRCP_SERVER_ENGINE_TASK_MSG:
                {
-                       resource_engine_task_msg_data_t *data = (resource_engine_task_msg_data_t*)msg->data;
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Resource Engine Task Message [%d]", msg->sub_type);
+                       engine_task_msg_data_t *data = (engine_task_msg_data_t*)msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Engine Task Message [%d]", msg->sub_type);
                        switch(msg->sub_type) {
-                               case RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL:
+                               case ENGINE_TASK_MSG_OPEN_CHANNEL:
                                        mrcp_server_on_engine_channel_open(data->channel,data->status);
                                        break;
-                               case RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL:
+                               case ENGINE_TASK_MSG_CLOSE_CHANNEL:
                                        mrcp_server_on_engine_channel_close(data->channel);
                                        break;
-                               case RESOURCE_ENGINE_TASK_MSG_MESSAGE:
+                               case ENGINE_TASK_MSG_MESSAGE:
                                        mrcp_server_on_engine_channel_message(data->channel,data->mrcp_message);
                                        break;
                                default:
@@ -722,9 +648,9 @@ static apt_bool_t mrcp_server_msg_process(apt_task_t *task, apt_task_msg_t *msg)
                }
                case MRCP_SERVER_MEDIA_TASK_MSG:
                {
-                       mpf_message_t *mpf_message = (mpf_message_t*) msg->data;
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message [%d]", mpf_message->command_id);
-                       mrcp_server_mpf_message_process(mpf_message);
+                       mpf_message_container_t *mpf_message_container = (mpf_message_container_t*) msg->data;
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Receive Media Task Message");
+                       mrcp_server_mpf_message_process(mpf_message_container);
                        break;
                }
                default:
@@ -781,7 +707,7 @@ static apt_bool_t mrcp_server_connection_task_msg_signal(
 }
 
 static apt_bool_t mrcp_server_engine_task_msg_signal(
-                                                       resource_engine_task_msg_type_e  type,
+                                                       engine_task_msg_type_e  type,
                                                        mrcp_engine_channel_t           *engine_channel,
                                                        apt_bool_t                       status,
                                                        mrcp_message_t                  *message)
@@ -790,16 +716,16 @@ static apt_bool_t mrcp_server_engine_task_msg_signal(
        mrcp_session_t *session = mrcp_server_channel_session_get(channel);
        mrcp_server_t *server = session->signaling_agent->parent;
        apt_task_t *task = apt_consumer_task_base_get(server->task);
-       resource_engine_task_msg_data_t *data;
-       apt_task_msg_t *task_msg = apt_task_msg_acquire(server->resource_engine_msg_pool);
-       task_msg->type = MRCP_SERVER_RESOURCE_ENGINE_TASK_MSG;
+       engine_task_msg_data_t *data;
+       apt_task_msg_t *task_msg = apt_task_msg_acquire(server->engine_msg_pool);
+       task_msg->type = MRCP_SERVER_ENGINE_TASK_MSG;
        task_msg->sub_type = type;
-       data = (resource_engine_task_msg_data_t*) task_msg->data;
+       data = (engine_task_msg_data_t*) task_msg->data;
        data->channel = channel;
        data->status = status;
        data->mrcp_message = message;
 
-       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Resource Engine Task Message");
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Signal Engine Task Message");
        return apt_task_msg_signal(task,task_msg);
 }
 
@@ -902,10 +828,22 @@ static apt_bool_t mrcp_server_message_signal(mrcp_control_channel_t *channel, mr
                                                                TRUE);
 }
 
+static apt_bool_t mrcp_server_disconnect_signal(mrcp_control_channel_t *channel)
+{
+       mrcp_connection_agent_t *agent = channel->agent;
+       return mrcp_server_connection_task_msg_signal(
+                                                               CONNECTION_AGENT_TASK_MSG_DISCONNECT,
+                                                               agent,
+                                                               channel,
+                                                               NULL,
+                                                               NULL,
+                                                               TRUE);
+}
+
 static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel, apt_bool_t status)
 {
        return mrcp_server_engine_task_msg_signal(
-                                                               RESOURCE_ENGINE_TASK_MSG_OPEN_CHANNEL,
+                                                               ENGINE_TASK_MSG_OPEN_CHANNEL,
                                                                channel,
                                                                status,
                                                                NULL);
@@ -914,7 +852,7 @@ static apt_bool_t mrcp_server_channel_open_signal(mrcp_engine_channel_t *channel
 static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channel)
 {
        return mrcp_server_engine_task_msg_signal(
-                                                               RESOURCE_ENGINE_TASK_MSG_CLOSE_CHANNEL,
+                                                               ENGINE_TASK_MSG_CLOSE_CHANNEL,
                                                                channel,
                                                                TRUE,
                                                                NULL);
@@ -923,7 +861,7 @@ static apt_bool_t mrcp_server_channel_close_signal(mrcp_engine_channel_t *channe
 static apt_bool_t mrcp_server_channel_message_signal(mrcp_engine_channel_t *channel, mrcp_message_t *message)
 {
        return mrcp_server_engine_task_msg_signal(
-                                                               RESOURCE_ENGINE_TASK_MSG_MESSAGE,
+                                                               ENGINE_TASK_MSG_MESSAGE,
                                                                channel,
                                                                TRUE,
                                                                message);
index 7269ddf60f345654d596eeb6cdd4c295d0897222..b2543009214dc8b74b0275edd64d150c189224ec 100644 (file)
 #include "mrcp_server_session.h"
 #include "mrcp_resource.h"
 #include "mrcp_resource_factory.h"
-#include "mrcp_resource_engine.h"
+#include "mrcp_engine_iface.h"
 #include "mrcp_sig_agent.h"
 #include "mrcp_server_connection.h"
 #include "mrcp_session_descriptor.h"
 #include "mrcp_control_descriptor.h"
 #include "mrcp_state_machine.h"
 #include "mrcp_message.h"
-#include "mpf_user.h"
-#include "mpf_termination.h"
-#include "mpf_engine.h"
+#include "mpf_termination_factory.h"
+#include "mpf_stream.h"
 #include "apt_consumer_task.h"
 #include "apt_log.h"
 
@@ -37,19 +36,19 @@ struct mrcp_channel_t {
        /** Memory pool */
        apr_pool_t             *pool;
        /** MRCP resource */
-       apt_str_t               resource_name;
-       /** MRCP resource */
        mrcp_resource_t        *resource;
        /** MRCP session entire channel belongs to */
        mrcp_session_t         *session;
        /** MRCP control channel */
        mrcp_control_channel_t *control_channel;
-       /** MRCP resource engine channel */
+       /** MRCP engine channel */
        mrcp_engine_channel_t  *engine_channel;
        /** MRCP resource state machine  */
        mrcp_state_machine_t   *state_machine;
-       /** media descriptor id */
+       /** media descriptor id (position in session descriptor) */
        apr_size_t              id;
+       /** array of cmid attributes (used for resource grouping) */
+       apr_array_header_t     *cmid_arr;
        /** waiting state of control media */
        apt_bool_t              waiting_for_channel;
        /** waiting state of media termination */
@@ -60,11 +59,16 @@ typedef struct mrcp_termination_slot_t mrcp_termination_slot_t;
 
 struct mrcp_termination_slot_t {
        /** RTP termination */
-       mpf_termination_t *termination;
-       /** media descriptor id */
-       apr_size_t              id;
+       mpf_termination_t  *termination;
+       /** media descriptor id (position in SDP message) */
+       apr_size_t          id;
+       /** media id (used for resource grouping) */
+       apr_size_t          mid;
+       /** Array of associated MRCP channels (mrcp_channel_t*) */
+       apr_array_header_t *channels;
+
        /** waiting state */
-       apt_bool_t         waiting;
+       apt_bool_t          waiting;
 };
 
 extern const mrcp_engine_channel_event_vtable_t engine_channel_vtable;
@@ -78,21 +82,13 @@ static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *sess
 static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
 static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
 
-static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *session, const mpf_message_t *mpf_message);
-static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *session, const mpf_message_t *mpf_message);
-
+static apt_bool_t mrcp_server_engine_channels_update(mrcp_server_session_t *session);
 static apt_bool_t mrcp_server_session_answer_send(mrcp_server_session_t *session);
+static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *session);
 static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *session);
 
 static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session, const apt_str_t *resource_name);
 
-static apt_bool_t mrcp_server_mpf_request_send(
-                                               mrcp_server_session_t *session, 
-                                               mpf_command_type_e command_id, 
-                                               mpf_context_t *context, 
-                                               mpf_termination_t *termination, 
-                                               void *descriptor);
-
 static apt_bool_t state_machine_on_message_dispatch(mrcp_state_machine_t *state_machine, mrcp_message_t *message);
 static apt_bool_t state_machine_on_deactivate(mrcp_state_machine_t *state_machine);
 
@@ -107,27 +103,44 @@ mrcp_server_session_t* mrcp_server_session_create()
        session->request_queue = apt_list_create(session->base.pool);
        session->offer = NULL;
        session->answer = NULL;
-       session->answer_flag_count = 0;
-       session->terminate_flag_count = 0;
-       session->deactivate_flag_count = 0;
+       session->mpf_task_msg = NULL;
+       session->subrequest_count = 0;
+       session->state = SESSION_STATE_NONE;
        return session;
 }
 
-static mrcp_engine_channel_t* mrcp_server_engine_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name)
+static APR_INLINE mrcp_version_e mrcp_session_version_get(mrcp_server_session_t *session)
 {
-       mrcp_resource_engine_t *resource_engine = apr_hash_get(
-                                                                                               session->profile->engine_table,
-                                                                                               resource_name->buf,
-                                                                                               resource_name->length);
-       if(!resource_engine) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find Resource Engine [%s]",resource_name->buf);
+       return session->base.signaling_agent->mrcp_version;
+}
+
+static mrcp_engine_channel_t* mrcp_server_engine_channel_create(
+                                                               mrcp_server_session_t *session,
+                                                               mrcp_channel_t *channel, 
+                                                               const apt_str_t *resource_name)
+{
+       mrcp_engine_t *engine = apr_hash_get(
+                                                                       session->profile->engine_table,
+                                                                       resource_name->buf,
+                                                                       resource_name->length);
+       if(!engine) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find MRCP Engine [%s]",resource_name->buf);
                return NULL;
        }
 
-       return resource_engine->method_vtable->create_channel(resource_engine,session->base.pool);
+       channel->state_machine = engine->create_state_machine(
+                                               channel,
+                                               mrcp_session_version_get(session),
+                                               channel->pool);
+       if(channel->state_machine) {
+               channel->state_machine->on_dispatch = state_machine_on_message_dispatch;
+               channel->state_machine->on_deactivate = state_machine_on_deactivate;
+       }
+
+       return mrcp_engine_channel_virtual_create(engine,mrcp_session_version_get(session),session->base.pool);
 }
 
-static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name, apr_size_t id)
+static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name, apr_size_t id, apr_array_header_t *cmid_arr)
 {
        mrcp_channel_t *channel;
        apr_pool_t *pool = session->base.pool;
@@ -140,37 +153,23 @@ static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session
        channel->state_machine = NULL;
        channel->engine_channel = NULL;
        channel->id = id;
+       channel->cmid_arr = cmid_arr;
        channel->waiting_for_channel = FALSE;
        channel->waiting_for_termination = FALSE;
-       apt_string_reset(&channel->resource_name);
 
        if(resource_name && resource_name->buf) {
-               mrcp_resource_id resource_id;
                mrcp_resource_t *resource;
                mrcp_engine_channel_t *engine_channel;
-               channel->resource_name = *resource_name;
-               resource_id = mrcp_resource_id_find(
-                                                               session->profile->resource_factory,
-                                                               resource_name);
-               resource = mrcp_resource_get(session->profile->resource_factory,resource_id);
+               resource = mrcp_resource_find(session->profile->resource_factory,resource_name);
                if(resource) {
                        channel->resource = resource;
-                       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_2) {
+                       if(mrcp_session_version_get(session) == MRCP_VERSION_2) {
                                channel->control_channel = mrcp_server_control_channel_create(
                                                                        session->profile->connection_agent,
                                                                        channel,
                                                                        pool);
                        }
-                       channel->state_machine = resource->create_server_state_machine(
-                                                               channel,
-                                                               session->base.signaling_agent->mrcp_version,
-                                                               pool);
-                       if(channel->state_machine) {
-                               channel->state_machine->on_dispatch = state_machine_on_message_dispatch;
-                               channel->state_machine->on_deactivate = state_machine_on_deactivate;
-                       }
-
-                       engine_channel = mrcp_server_engine_channel_create(session,resource_name);
+                       engine_channel = mrcp_server_engine_channel_create(session,channel,resource_name);
                        if(engine_channel) {
                                engine_channel->id = session->base.id;
                                engine_channel->event_obj = channel;
@@ -178,7 +177,7 @@ static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session
                                channel->engine_channel = engine_channel;
                        }
                        else {
-                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine Channel [%s]",resource_name->buf);
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Engine Channel [%s]",resource_name->buf);
                                session->answer->status = MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE;
                        }
                }
@@ -195,6 +194,48 @@ static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session
        return channel;
 }
 
+static APR_INLINE void mrcp_server_session_state_set(mrcp_server_session_t *session, mrcp_server_session_state_e state)
+{
+       if(session->subrequest_count != 0) {
+               /* error case */
+               session->subrequest_count = 0;
+       }
+       session->state = state;
+}
+
+static APR_INLINE void mrcp_server_session_subrequest_add(mrcp_server_session_t *session)
+{
+       session->subrequest_count++;
+}
+
+static void mrcp_server_session_subrequest_remove(mrcp_server_session_t *session)
+{
+       if(!session->subrequest_count) {
+               /* error case */
+               return;
+       }
+       session->subrequest_count--;
+       if(!session->subrequest_count) {
+               switch(session->state) {
+                       case SESSION_STATE_GENERATING_ANSWER:
+                               mrcp_server_engine_channels_update(session);
+                               break;
+                       case SESSION_STATE_INITIALIZING:
+                               /* send answer to client */
+                               mrcp_server_session_answer_send(session);
+                               break;
+                       case SESSION_STATE_DEACTIVATING:
+                               mrcp_server_session_terminate_process(session);
+                               break;
+                       case SESSION_STATE_TERMINATING:
+                               mrcp_server_session_terminate_send(session);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
 mrcp_session_t* mrcp_server_channel_session_get(mrcp_channel_t *channel)
 {
        return channel->session;
@@ -227,13 +268,7 @@ apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_d
        channel->waiting_for_channel = FALSE;
        answer->session_id = session->base.id;
        mrcp_session_control_media_set(session->answer,channel->id,answer);
-       if(session->answer_flag_count) {
-               session->answer_flag_count--;
-               if(!session->answer_flag_count) {
-                       /* send answer to client */
-                       mrcp_server_session_answer_send(session);
-               }
-       }
+       mrcp_server_session_subrequest_remove(session);
        return TRUE;
 }
 
@@ -245,12 +280,7 @@ apt_bool_t mrcp_server_on_channel_remove(mrcp_channel_t *channel, apt_bool_t sta
                return FALSE;
        }
        channel->waiting_for_channel = FALSE;
-       if(session->terminate_flag_count) {
-               session->terminate_flag_count--;
-               if(!session->terminate_flag_count) {
-                       mrcp_server_session_terminate_send(session);
-               }
-       }
+       mrcp_server_session_subrequest_remove(session);
        return TRUE;
 }
 
@@ -267,6 +297,12 @@ apt_bool_t mrcp_server_on_channel_message(mrcp_channel_t *channel, mrcp_message_
        return mrcp_server_signaling_message_process(signaling_message);
 }
 
+apt_bool_t mrcp_server_on_disconnect(mrcp_channel_t *channel)
+{
+       /* to be processed */
+       return TRUE;
+}
+
 apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_t status)
 {
        mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
@@ -274,13 +310,7 @@ apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_
        if(status == FALSE) {
                session->answer->status = MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE;
        }
-       if(session->answer_flag_count) {
-               session->answer_flag_count--;
-               if(!session->answer_flag_count) {
-                       /* send answer to client */
-                       mrcp_server_session_answer_send(session);
-               }
-       }
+       mrcp_server_session_subrequest_remove(session);
        return TRUE;
 }
 
@@ -288,12 +318,7 @@ apt_bool_t mrcp_server_on_engine_channel_close(mrcp_channel_t *channel)
 {
        mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Engine Channel Close");
-       if(session->terminate_flag_count) {
-               session->terminate_flag_count--;
-               if(!session->terminate_flag_count) {
-                       mrcp_server_session_terminate_send(session);
-               }
-       }
+       mrcp_server_session_subrequest_remove(session);
        return TRUE;
 }
 
@@ -307,41 +332,9 @@ apt_bool_t mrcp_server_on_engine_channel_message(mrcp_channel_t *channel, mrcp_m
 }
 
 
-apt_bool_t mrcp_server_mpf_message_process(mpf_message_t *mpf_message)
-{
-       mrcp_server_session_t *session = NULL;
-       if(mpf_message->context) {
-               session = mpf_context_object_get(mpf_message->context);
-       }
-       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
-               switch(mpf_message->command_id) {
-                       case MPF_COMMAND_ADD:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add");
-                               mrcp_server_on_termination_modify(session,mpf_message);
-                               break;
-                       case MPF_COMMAND_MODIFY:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify");
-                               mrcp_server_on_termination_modify(session,mpf_message);
-                               break;
-                       case MPF_COMMAND_SUBTRACT:
-                               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract");
-                               mrcp_server_on_termination_subtract(session,mpf_message);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
-       }
-       return TRUE;
-}
-
 static mrcp_session_descriptor_t* mrcp_session_answer_create(mrcp_session_descriptor_t *offer, apr_pool_t *pool)
 {
        int i;
-       void **control_slot;
-       mpf_rtp_media_descriptor_t **av_slot;
        mrcp_session_descriptor_t *answer = apr_palloc(pool,sizeof(mrcp_session_descriptor_t));
        apt_string_reset(&answer->origin);
        apt_string_reset(&answer->ip);
@@ -351,18 +344,15 @@ static mrcp_session_descriptor_t* mrcp_session_answer_create(mrcp_session_descri
        answer->status = offer->status;
        answer->control_media_arr = apr_array_make(pool,offer->control_media_arr->nelts,sizeof(void*));
        for(i=0; i<offer->control_media_arr->nelts; i++) {
-               control_slot = apr_array_push(answer->control_media_arr);
-               *control_slot = NULL;
+               APR_ARRAY_PUSH(answer->control_media_arr,void*) = NULL;
        }
        answer->audio_media_arr = apr_array_make(pool,offer->audio_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
        for(i=0; i<offer->audio_media_arr->nelts; i++) {
-               av_slot = apr_array_push(answer->audio_media_arr);
-               *av_slot = NULL;
+               APR_ARRAY_PUSH(answer->audio_media_arr,mpf_rtp_media_descriptor_t*) = NULL;
        }
        answer->video_media_arr = apr_array_make(pool,offer->video_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
        for(i=0; i<offer->video_media_arr->nelts; i++) {
-               av_slot = apr_array_push(answer->video_media_arr);
-               *av_slot = NULL;
+               APR_ARRAY_PUSH(answer->video_media_arr,mpf_rtp_media_descriptor_t*) = NULL;
        }
        return answer;
 }
@@ -376,7 +366,7 @@ static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *sessi
                }
                mrcp_server_session_add(session);
 
-               session->context = mpf_context_create(session,5,session->base.pool);
+               session->context = mpf_engine_context_create(session->profile->media_engine,session,5,session->base.pool);
        }
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Offer "APT_SID_FMT" [c:%d a:%d v:%d]",
                MRCP_SESSION_SID(&session->base),
@@ -388,7 +378,17 @@ static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *sessi
        session->offer = descriptor;
        session->answer = mrcp_session_answer_create(descriptor,session->base.pool);
 
-       if(session->base.signaling_agent->mrcp_version == MRCP_VERSION_1) {
+       mrcp_server_session_state_set(session,SESSION_STATE_GENERATING_ANSWER);
+
+       /* first, reset/destroy existing associations and topology */
+       if(mpf_engine_topology_message_add(
+                               session->profile->media_engine,
+                               MPF_RESET_ASSOCIATIONS,session->context,
+                               &session->mpf_task_msg) == TRUE){
+               mrcp_server_session_subrequest_add(session);
+       }
+
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
                if(mrcp_server_resource_offer_process(session,descriptor) == TRUE) {
                        mrcp_server_av_media_offer_process(session,descriptor);
                }
@@ -400,8 +400,17 @@ static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *sessi
                mrcp_server_control_media_offer_process(session,descriptor);
                mrcp_server_av_media_offer_process(session,descriptor);
        }
-       
-       if(!session->answer_flag_count) {
+
+       /* apply topology based on assigned associations */
+       if(mpf_engine_topology_message_add(
+                               session->profile->media_engine,
+                               MPF_APPLY_TOPOLOGY,session->context,
+                               &session->mpf_task_msg) == TRUE) {
+               mrcp_server_session_subrequest_add(session);
+       }
+       mpf_engine_message_send(session->profile->media_engine,&session->mpf_task_msg);
+
+       if(!session->subrequest_count) {
                /* send answer to client */
                mrcp_server_session_answer_send(session);
        }
@@ -414,8 +423,21 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s
        mrcp_termination_slot_t *slot;
        int i;
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Terminate Request "APT_SID_FMT,MRCP_SESSION_SID(&session->base));
+
+       mrcp_server_session_state_set(session,SESSION_STATE_TERMINATING);
+
+       if(session->context) {
+               /* first, destroy existing topology */
+               if(mpf_engine_topology_message_add(
+                                       session->profile->media_engine,
+                                       MPF_RESET_ASSOCIATIONS,session->context,
+                                       &session->mpf_task_msg) == TRUE){
+                       mrcp_server_session_subrequest_add(session);
+               }
+       }
+
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                /* send remove channel request */
@@ -423,7 +445,7 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s
                if(channel->control_channel) {
                        if(mrcp_server_control_channel_remove(channel->control_channel) == TRUE) {
                                channel->waiting_for_channel = TRUE;
-                               session->terminate_flag_count++;
+                               mrcp_server_session_subrequest_add(session);
                        }
                }
 
@@ -432,33 +454,44 @@ static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *s
                        /* send subtract termination request */
                        if(termination) {
                                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Channel Termination");
-                               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_SUBTRACT,session->context,termination,NULL) == TRUE) {
+                               if(mpf_engine_termination_message_add(
+                                                       session->profile->media_engine,
+                                                       MPF_SUBTRACT_TERMINATION,session->context,termination,NULL,
+                                                       &session->mpf_task_msg) == TRUE) {
                                        channel->waiting_for_termination = TRUE;
-                                       session->terminate_flag_count++;
+                                       mrcp_server_session_subrequest_add(session);
                                }
                        }
 
-                       /* close resource engine channel */
-                       if(mrcp_engine_channel_close(channel->engine_channel) == TRUE) {
-                               session->terminate_flag_count++;
+                       /* close engine channel */
+                       if(mrcp_engine_channel_virtual_close(channel->engine_channel) == TRUE) {
+                               mrcp_server_session_subrequest_add(session);
                        }
                }
        }
        for(i=0; i<session->terminations->nelts; i++) {
                /* get existing termination */
-               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
                if(!slot || !slot->termination) continue;
 
                /* send subtract termination request */
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract RTP Termination [%d]",i);
-               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_SUBTRACT,session->context,slot->termination,NULL) == TRUE) {
+               if(mpf_engine_termination_message_add(
+                               session->profile->media_engine,
+                               MPF_SUBTRACT_TERMINATION,session->context,slot->termination,NULL,
+                               &session->mpf_task_msg) == TRUE) {
                        slot->waiting = TRUE;
-                       session->terminate_flag_count++;
+                       mrcp_server_session_subrequest_add(session);
                }
        }
+
+       if(session->context) {
+               mpf_engine_message_send(session->profile->media_engine,&session->mpf_task_msg);
+       }
+
        mrcp_server_session_remove(session);
 
-       if(!session->terminate_flag_count) {
+       if(!session->subrequest_count) {
                mrcp_server_session_terminate_send(session);
        }
 
@@ -470,16 +503,17 @@ static apt_bool_t mrcp_server_session_deactivate(mrcp_server_session_t *session)
        mrcp_channel_t *channel;
        int i;
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Deactivate Session "APT_SID_FMT,MRCP_SESSION_SID(&session->base));
+       mrcp_server_session_state_set(session,SESSION_STATE_DEACTIVATING);
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel || !channel->state_machine) continue;
 
                if(mrcp_state_machine_deactivate(channel->state_machine) == TRUE) {
-                       session->deactivate_flag_count++;
+                       mrcp_server_session_subrequest_add(session);
                }
        }
        
-       if(!session->deactivate_flag_count) {
+       if(!session->subrequest_count) {
                mrcp_server_session_terminate_process(session);
        }
 
@@ -523,12 +557,63 @@ static apt_bool_t mrcp_server_signaling_message_dispatch(mrcp_server_session_t *
        return TRUE;
 }
 
+static apt_bool_t mrcp_server_engine_channels_update(mrcp_server_session_t *session)
+{
+       mrcp_channel_t *channel;
+       mrcp_session_descriptor_t *descriptor = session->offer;
+       if(!descriptor) {
+               return FALSE;
+       }
+       
+       mrcp_server_session_state_set(session,SESSION_STATE_INITIALIZING);
+
+       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
+               if(session->offer) {
+                       channel = mrcp_server_channel_find(session,&descriptor->resource_name);
+                       if(channel && channel->engine_channel) {
+                               /* open engine channel */
+                               if(mrcp_engine_channel_virtual_open(channel->engine_channel) == TRUE) {
+                                       mrcp_server_session_subrequest_add(session);
+                               }
+                       }
+               }
+       }
+       else {
+               int i;
+               mrcp_control_descriptor_t *control_descriptor;
+               for(i=0; i<session->channels->nelts; i++) {
+                       channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
+                       if(!channel || !channel->engine_channel) continue;
+
+                       control_descriptor = mrcp_session_control_media_get(descriptor,i);
+                       if(!control_descriptor) continue;
+
+                       if(control_descriptor->port) {
+                               /* open engine channel */
+                               if(mrcp_engine_channel_virtual_open(channel->engine_channel) == TRUE) {
+                                       mrcp_server_session_subrequest_add(session);
+                               }
+                       }
+                       else {
+                               /* close engine channel */
+                               if(mrcp_engine_channel_virtual_close(channel->engine_channel) == TRUE) {
+                                       mrcp_server_session_subrequest_add(session);
+                               }
+                       }
+               }
+       }
+
+       if(!session->subrequest_count) {
+               mrcp_server_session_answer_send(session);
+       }
+       return TRUE;
+}
+
 static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
 {
        if(descriptor->resource_state == TRUE) {
                /* setup */
                mrcp_channel_t *channel;
-               mrcp_channel_t **slot;
                int count = session->channels->nelts;
                channel = mrcp_server_channel_find(session,&descriptor->resource_name);
                if(channel) {
@@ -536,36 +621,22 @@ static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *sess
                        return TRUE;
                }
                /* create new MRCP channel instance */
-               channel = mrcp_server_channel_create(session,&descriptor->resource_name,count);
+               channel = mrcp_server_channel_create(session,&descriptor->resource_name,count,NULL);
                if(!channel || !channel->resource) {
                        return FALSE;
                }
                /* add to channel array */
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",count);
-               slot = apr_array_push(session->channels);
-               *slot = channel;
-
-               if(channel->engine_channel) {
-                       /* open resource engine channel */
-                       if(mrcp_engine_channel_open(channel->engine_channel) == TRUE) {
-                               mpf_termination_t *termination = channel->engine_channel->termination;
-                               session->answer_flag_count++;
-
-                               if(termination) {
-                                       /* send add termination request (add to media context) */
-                                       if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,NULL) == TRUE) {
-                                               channel->waiting_for_termination = TRUE;
-                                               session->answer_flag_count++;
-                                       }
-
-                                       if(termination->audio_stream) {
-                                               mpf_rtp_media_descriptor_t *rtp_media_descriptor = mrcp_session_audio_media_get(descriptor,0);
-                                               if(rtp_media_descriptor) {
-                                                       mpf_stream_mode_e mode = termination->audio_stream->mode;
-                                                       rtp_media_descriptor->mode |= mode;
-                                               }
-                                       }
-                               }
+               APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel;
+               if(channel->engine_channel && channel->engine_channel->termination) {
+                       mpf_termination_t *termination = channel->engine_channel->termination;
+                       /* send add termination request (add to media context) */
+                       if(mpf_engine_termination_message_add(
+                                       session->profile->media_engine,
+                                       MPF_ADD_TERMINATION,session->context,termination,NULL,
+                                       &session->mpf_task_msg) == TRUE) {
+                               channel->waiting_for_termination = TRUE;
+                               mrcp_server_session_subrequest_add(session);
                        }
                }
        }
@@ -589,8 +660,7 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t
        
        /* update existing control channels */
        for(i=0; i<count; i++) {
-               /* get existing termination */
-               channel = *((mrcp_channel_t**)session->channels->elts + i);
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                channel->waiting_for_channel = FALSE;
@@ -603,7 +673,7 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t
                        /* send offer */
                        if(mrcp_server_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) {
                                channel->waiting_for_channel = TRUE;
-                               session->answer_flag_count++;
+                               mrcp_server_session_subrequest_add(session);
                        }
                }
 
@@ -617,26 +687,23 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t
        
        /* add new control channels */
        for(; i<descriptor->control_media_arr->nelts; i++) {
-               mrcp_channel_t **slot;
                /* get control descriptor */
                control_descriptor = mrcp_session_control_media_get(descriptor,i);
                if(!control_descriptor) continue;
 
                /* create new MRCP channel instance */
-               channel = mrcp_server_channel_create(session,&control_descriptor->resource_name,i);
+               channel = mrcp_server_channel_create(session,&control_descriptor->resource_name,i,control_descriptor->cmid_arr);
                if(!channel) continue;
-               /* add to channel array */
 
                control_descriptor->session_id = session->base.id;
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel [%d]",i);
-               slot = apr_array_push(session->channels);
-               *slot = channel;
+               APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel;
 
                if(channel->control_channel) {
                        /* send modify connection request */
                        if(mrcp_server_control_channel_add(channel->control_channel,control_descriptor) == TRUE) {
                                channel->waiting_for_channel = TRUE;
-                               session->answer_flag_count++;
+                               mrcp_server_session_subrequest_add(session);
                        }
                }
 
@@ -647,28 +714,108 @@ static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t
                        mrcp_session_control_media_set(session->answer,channel->id,answer);
                }
                
-               if(channel->engine_channel) {
-                       /* open resource engine channel */
-                       if(mrcp_engine_channel_open(channel->engine_channel) == TRUE) {
-                               mpf_termination_t *termination = channel->engine_channel->termination;
-                               session->answer_flag_count++;
-
-                               if(termination) {
-                                       /* send add termination request (add to media context) */
-                                       if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,NULL) == TRUE) {
-                                               channel->waiting_for_termination = TRUE;
-                                               session->answer_flag_count++;
+               if(channel->engine_channel && channel->engine_channel->termination) {
+                       mpf_termination_t *termination = channel->engine_channel->termination;
+                       /* send add termination request (add to media context) */
+                       if(mpf_engine_termination_message_add(
+                                       session->profile->media_engine,
+                                       MPF_ADD_TERMINATION,session->context,termination,NULL,
+                                       &session->mpf_task_msg) == TRUE) {
+                               channel->waiting_for_termination = TRUE;
+                               mrcp_server_session_subrequest_add(session);
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
+static mpf_rtp_termination_descriptor_t* mrcp_server_associations_build(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_termination_slot_t *slot)
+{
+       int i;
+       mrcp_channel_t *channel;
+       mpf_audio_stream_t *audio_stream;
+       mpf_stream_capabilities_t *capabilities = NULL;
+       mpf_rtp_termination_descriptor_t *rtp_descriptor;
+       mpf_rtp_media_descriptor_t *media_descriptor = mrcp_session_audio_media_get(descriptor,slot->id);
+       if(!media_descriptor) {
+               return NULL;
+       }
+       /* construct termination descriptor */
+       rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
+       mpf_rtp_termination_descriptor_init(rtp_descriptor);
+       rtp_descriptor->audio.local = NULL;
+       rtp_descriptor->audio.remote = media_descriptor;
+
+       slot->mid = media_descriptor->mid;
+       slot->channels = apr_array_make(session->base.pool,1,sizeof(mrcp_channel_t*));
+       for(i=0; i<session->channels->nelts; i++) {
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
+               if(!channel) continue;
+
+               if(!channel->cmid_arr || mrcp_cmid_find(channel->cmid_arr,slot->mid) == TRUE) {
+                       APR_ARRAY_PUSH(slot->channels, mrcp_channel_t*) = channel;
+
+                       audio_stream = NULL;
+                       if(channel->engine_channel && channel->engine_channel->termination) {
+                               audio_stream = mpf_termination_audio_stream_get(channel->engine_channel->termination);
+                       }
+                       if(!audio_stream) continue;
+
+                       if(audio_stream->capabilities) {
+                               /* set descriptor according to media termination(s) 
+                               of associated control channel(s) */
+                               if(capabilities) {
+                                       mpf_stream_capabilities_merge(
+                                               capabilities,
+                                               audio_stream->capabilities,
+                                               session->base.pool);
                                        }
+                               else {
+                                       capabilities = mpf_stream_capabilities_clone(
+                                               audio_stream->capabilities,
+                                               session->base.pool);
+                               }
+                       }
+
+                       if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
+                               /* implicitly modify the descriptor, if needed */
+                               mpf_stream_direction_e direction = audio_stream->direction;
+                               media_descriptor->direction |= direction;
+                               if(media_descriptor->state == MPF_MEDIA_DISABLED) {
+                                       media_descriptor->state = MPF_MEDIA_ENABLED;
                                }
                        }
                }
        }
+       if(capabilities) {
+               capabilities->direction = mpf_stream_reverse_direction_get(capabilities->direction);
+               rtp_descriptor->audio.capabilities = capabilities;
+       }
+       return rtp_descriptor;
+}
 
+static apt_bool_t mrcp_server_associations_set(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_termination_slot_t *slot)
+{
+       int i;
+       mrcp_channel_t *channel;
+       for(i=0; i<slot->channels->nelts; i++) {
+               channel = ((mrcp_channel_t**)slot->channels->elts)[i];
+               if(!channel || !channel->engine_channel) continue;
+
+               if(mpf_engine_assoc_message_add(
+                               session->profile->media_engine,
+                               MPF_ADD_ASSOCIATION,session->context,slot->termination,channel->engine_channel->termination,
+                               &session->mpf_task_msg) == TRUE) {
+                       mrcp_server_session_subrequest_add(session);
+               }
+       }
        return TRUE;
 }
 
 static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
 {
+       mpf_rtp_termination_descriptor_t *rtp_descriptor;
        mrcp_termination_slot_t *slot;
        int i;
        int count = session->terminations->nelts;
@@ -684,28 +831,30 @@ static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *sess
        
        /* update existing terminations */
        for(i=0; i<count; i++) {
-               mpf_rtp_termination_descriptor_t *rtp_descriptor;
                /* get existing termination */
-               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
                if(!slot || !slot->termination) continue;
 
-               /* construct termination descriptor */
-               rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
-               mpf_rtp_termination_descriptor_init(rtp_descriptor);
-               rtp_descriptor->audio.local = NULL;
-               rtp_descriptor->audio.remote = mrcp_session_audio_media_get(descriptor,i);
+               /* build associations between specified RTP termination and control channels */
+               rtp_descriptor = mrcp_server_associations_build(session,descriptor,slot);
+               if(!rtp_descriptor) continue;
 
                /* send modify termination request */
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify RTP Termination [%d]",i);
-               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_MODIFY,session->context,slot->termination,rtp_descriptor) == TRUE) {
+               if(mpf_engine_termination_message_add(
+                               session->profile->media_engine,
+                               MPF_MODIFY_TERMINATION,session->context,slot->termination,rtp_descriptor,
+                               &session->mpf_task_msg) == TRUE) {
                        slot->waiting = TRUE;
-                       session->answer_flag_count++;
+                       mrcp_server_session_subrequest_add(session);
                }
+
+               /* set built associations */
+               mrcp_server_associations_set(session,descriptor,slot);
        }
        
        /* add new terminations */
        for(; i<descriptor->audio_media_arr->nelts; i++) {
-               mpf_rtp_termination_descriptor_t *rtp_descriptor;
                mpf_termination_t *termination;
                /* create new RTP termination instance */
                termination = mpf_termination_create(session->profile->rtp_termination_factory,session,session->base.pool);
@@ -713,20 +862,26 @@ static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *sess
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add RTP Termination [%d]",i);
                slot = apr_array_push(session->terminations);
                slot->id = i;
+               slot->mid = 0;
                slot->waiting = FALSE;
                slot->termination = termination;
+               slot->channels = NULL;
 
-               /* construct termination descriptor */
-               rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
-               mpf_rtp_termination_descriptor_init(rtp_descriptor);
-               rtp_descriptor->audio.local = NULL;
-               rtp_descriptor->audio.remote = mrcp_session_audio_media_get(descriptor,i);
+               /* build associations between specified RTP termination and control channels */
+               rtp_descriptor = mrcp_server_associations_build(session,descriptor,slot);
+               if(!rtp_descriptor) continue;
 
                /* send add termination request (add to media context) */
-               if(mrcp_server_mpf_request_send(session,MPF_COMMAND_ADD,session->context,termination,rtp_descriptor) == TRUE) {
+               if(mpf_engine_termination_message_add(
+                               session->profile->media_engine,
+                               MPF_ADD_TERMINATION,session->context,termination,rtp_descriptor,
+                               &session->mpf_task_msg) == TRUE) {
                        slot->waiting = TRUE;
-                       session->answer_flag_count++;
+                       mrcp_server_session_subrequest_add(session);
                }
+
+               /* set built associations */
+               mrcp_server_associations_set(session,descriptor,slot);
        }
        return TRUE;
 }
@@ -757,7 +912,7 @@ static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *sess
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                if(channel->control_channel) {
@@ -765,7 +920,7 @@ static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *sess
                        channel->control_channel = NULL;
                }
                if(channel->engine_channel) {
-                       mrcp_engine_channel_destroy(channel->engine_channel);
+                       mrcp_engine_channel_virtual_destroy(channel->engine_channel);
                        channel->engine_channel = NULL;
                }
        }
@@ -780,7 +935,7 @@ static mrcp_termination_slot_t* mrcp_server_rtp_termination_find(mrcp_server_ses
        int i;
        mrcp_termination_slot_t *slot;
        for(i=0; i<session->terminations->nelts; i++) {
-               slot = &((mrcp_termination_slot_t*)session->terminations->elts)[i];
+               slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
                if(slot && slot->termination == termination) {
                        return slot;
                }
@@ -793,7 +948,7 @@ static mrcp_channel_t* mrcp_server_channel_termination_find(mrcp_server_session_
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
                if(channel->engine_channel && channel->engine_channel->termination == termination) {
@@ -808,10 +963,10 @@ static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session,
        int i;
        mrcp_channel_t *channel;
        for(i=0; i<session->channels->nelts; i++) {
-               channel = ((mrcp_channel_t**)session->channels->elts)[i];
+               channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
                if(!channel) continue;
 
-               if(apt_string_compare(&channel->resource_name,resource_name) == TRUE) {
+               if(apt_string_compare(&channel->resource->name,resource_name) == TRUE) {
                        return channel;
                }
        }
@@ -834,30 +989,18 @@ static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *sessi
                termination_slot->waiting = FALSE;
                rtp_descriptor = mpf_message->descriptor;
                if(rtp_descriptor->audio.local) {
-                       session->answer->ip = rtp_descriptor->audio.local->base.ip;
-                       session->answer->ext_ip = rtp_descriptor->audio.local->base.ext_ip;
+                       session->answer->ip = rtp_descriptor->audio.local->ip;
+                       session->answer->ext_ip = rtp_descriptor->audio.local->ext_ip;
                        mrcp_session_audio_media_set(session->answer,termination_slot->id,rtp_descriptor->audio.local);
                }
-               if(session->answer_flag_count) {
-                       session->answer_flag_count--;
-                       if(!session->answer_flag_count) {
-                               /* send answer to client */
-                               mrcp_server_session_answer_send(session);
-                       }
-               }
+               mrcp_server_session_subrequest_remove(session);
        }
        else {
                /* engine channel termination */
                mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
                if(channel && channel->waiting_for_termination == TRUE) {
                        channel->waiting_for_termination = FALSE;
-                       if(session->answer_flag_count) {
-                               session->answer_flag_count--;
-                               if(!session->answer_flag_count) {
-                                       /* send answer to client */
-                                       mrcp_server_session_answer_send(session);
-                               }
-                       }
+                       mrcp_server_session_subrequest_remove(session);
                }
        }
        return TRUE;
@@ -876,25 +1019,61 @@ static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *ses
                        return FALSE;
                }
                termination_slot->waiting = FALSE;
-               if(session->terminate_flag_count) {
-                       session->terminate_flag_count--;
-                       if(!session->terminate_flag_count) {
-                               mrcp_server_session_terminate_send(session);
-                       }
-               }
+               mrcp_server_session_subrequest_remove(session);
        }
        else {
                /* engine channel termination */
                mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
                if(channel && channel->waiting_for_termination == TRUE) {
                        channel->waiting_for_termination = FALSE;
-                       if(session->terminate_flag_count) {
-                               session->terminate_flag_count--;
-                               if(!session->terminate_flag_count) {
-                                       mrcp_server_session_terminate_send(session);
-                               }
+                       mrcp_server_session_subrequest_remove(session);
+               }
+       }
+       return TRUE;
+}
+
+apt_bool_t mrcp_server_mpf_message_process(mpf_message_container_t *mpf_message_container)
+{
+       apr_size_t i;
+       mrcp_server_session_t *session;
+       const mpf_message_t *mpf_message;
+       for(i=0; i<mpf_message_container->count; i++) {
+               mpf_message = &mpf_message_container->messages[i];
+               if(mpf_message->context) {
+                       session = mpf_engine_context_object_get(mpf_message->context);
+               }
+               else {
+                       session = NULL;
+               }
+               
+               if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+                       switch(mpf_message->command_id) {
+                               case MPF_ADD_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Add");
+                                       mrcp_server_on_termination_modify(session,mpf_message);
+                                       break;
+                               case MPF_MODIFY_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Modify");
+                                       mrcp_server_on_termination_modify(session,mpf_message);
+                                       break;
+                               case MPF_SUBTRACT_TERMINATION:
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Termination Subtract");
+                                       mrcp_server_on_termination_subtract(session,mpf_message);
+                                       break;
+                               case MPF_ADD_ASSOCIATION:
+                               case MPF_REMOVE_ASSOCIATION:
+                               case MPF_RESET_ASSOCIATIONS:
+                               case MPF_APPLY_TOPOLOGY:
+                               case MPF_DESTROY_TOPOLOGY:
+                                       mrcp_server_session_subrequest_remove(session);
+                                       break;
+                               default:
+                                       break;
                        }
                }
+               else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
+               }
        }
        return TRUE;
 }
@@ -904,7 +1083,7 @@ static apt_bool_t state_machine_on_message_dispatch(mrcp_state_machine_t *state_
        mrcp_channel_t *channel = state_machine->obj;
 
        if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               /* send request message to resource engine for actual processing */
+               /* send request message to engine for actual processing */
                if(channel->engine_channel) {
                        mrcp_engine_channel_request_process(channel->engine_channel,message);
                }
@@ -944,33 +1123,6 @@ static apt_bool_t state_machine_on_deactivate(mrcp_state_machine_t *state_machin
 {
        mrcp_channel_t *channel = state_machine->obj;
        mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
-       if(session->deactivate_flag_count) {
-               session->deactivate_flag_count --;
-               if(!session->deactivate_flag_count) {
-                       mrcp_server_session_terminate_process(session);
-               }
-       }
+       mrcp_server_session_subrequest_remove(session);
        return TRUE;
 }
-
-static apt_bool_t mrcp_server_mpf_request_send(
-                                               mrcp_server_session_t *session, 
-                                               mpf_command_type_e command_id, 
-                                               mpf_context_t *context, 
-                                               mpf_termination_t *termination, 
-                                               void *descriptor)
-{
-       apt_task_t *media_task = mpf_task_get(session->profile->media_engine);
-       apt_task_msg_t *msg;
-       mpf_message_t *mpf_message;
-       msg = apt_task_msg_get(media_task);
-       msg->type = TASK_MSG_USER;
-       mpf_message = (mpf_message_t*) msg->data;
-
-       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
-       mpf_message->command_id = command_id;
-       mpf_message->context = context;
-       mpf_message->termination = termination;
-       mpf_message->descriptor = descriptor;
-       return apt_task_msg_signal(media_task,msg);
-}
index 192da1c8123239434e34f9aa7221b58f7fb110d3..173d1c39b2fbbb4261853f2a54db184b650fb5bf 100644 (file)
 
 APT_BEGIN_EXTERN_C
 
+/** Macro to log session pointers */
 #define MRCP_SESSION_PTR(session) (session)
+/** Macro to log session string identifiers */
 #define MRCP_SESSION_SID(session) \
        (session)->id.buf ? (session)->id.buf : "new"
 
+/** Macro to log session pointers and string identifiers */
 #define MRCP_SESSION_PTRSID(session) \
        MRCP_SESSION_PTR(session), MRCP_SESSION_SID(session)
 
index 4a2fa19b537cecd0ea100ec4d5f6bb600362c965..7a94a424960ea35b901804eaffa80bcab38e4866 100644 (file)
@@ -69,8 +69,7 @@ static APR_INLINE apr_size_t mrcp_session_media_count_get(const mrcp_session_des
 
 static APR_INLINE apr_size_t mrcp_session_control_media_add(mrcp_session_descriptor_t *descriptor, void *media)
 {
-       void **slot = apr_array_push(descriptor->control_media_arr);
-       *slot = media;
+       APR_ARRAY_PUSH(descriptor->control_media_arr,void*) = media;
        return mrcp_session_media_count_get(descriptor) - 1;
 }
 
@@ -79,7 +78,7 @@ static APR_INLINE void* mrcp_session_control_media_get(const mrcp_session_descri
        if((int)id >= descriptor->control_media_arr->nelts) {
                return NULL;
        }
-       return ((void**)descriptor->control_media_arr->elts)[id];
+       return APR_ARRAY_IDX(descriptor->control_media_arr,id,void*);
 }
 
 static APR_INLINE apt_bool_t mrcp_session_control_media_set(mrcp_session_descriptor_t *descriptor, apr_size_t id, void *media)
@@ -87,15 +86,14 @@ static APR_INLINE apt_bool_t mrcp_session_control_media_set(mrcp_session_descrip
        if((int)id >= descriptor->control_media_arr->nelts) {
                return FALSE;
        }
-       ((void**)descriptor->control_media_arr->elts)[id] = media;
+       APR_ARRAY_IDX(descriptor->control_media_arr,id,void*) = media;
        return TRUE;
 }
 
 
 static APR_INLINE apr_size_t mrcp_session_audio_media_add(mrcp_session_descriptor_t *descriptor, mpf_rtp_media_descriptor_t *media)
 {
-       mpf_rtp_media_descriptor_t **slot = apr_array_push(descriptor->audio_media_arr);
-       *slot = media;
+       APR_ARRAY_PUSH(descriptor->audio_media_arr,mpf_rtp_media_descriptor_t*) = media;
        return mrcp_session_media_count_get(descriptor) - 1;
 }
 
@@ -104,7 +102,7 @@ static APR_INLINE mpf_rtp_media_descriptor_t* mrcp_session_audio_media_get(const
        if((int)id >= descriptor->audio_media_arr->nelts) {
                return NULL;
        }
-       return ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[id];
+       return APR_ARRAY_IDX(descriptor->audio_media_arr,id,mpf_rtp_media_descriptor_t*);
 }
 
 static APR_INLINE apt_bool_t mrcp_session_audio_media_set(const mrcp_session_descriptor_t *descriptor, apr_size_t id, mpf_rtp_media_descriptor_t* media)
@@ -112,15 +110,14 @@ static APR_INLINE apt_bool_t mrcp_session_audio_media_set(const mrcp_session_des
        if((int)id >= descriptor->audio_media_arr->nelts) {
                return FALSE;
        }
-       ((mpf_rtp_media_descriptor_t**)descriptor->audio_media_arr->elts)[id] = media;
+       APR_ARRAY_IDX(descriptor->audio_media_arr,id,mpf_rtp_media_descriptor_t*) = media;
        return TRUE;
 }
 
 
 static APR_INLINE apr_size_t mrcp_session_video_media_add(mrcp_session_descriptor_t *descriptor, mpf_rtp_media_descriptor_t *media)
 {
-       mpf_rtp_media_descriptor_t **slot = apr_array_push(descriptor->video_media_arr);
-       *slot = media;
+       APR_ARRAY_PUSH(descriptor->video_media_arr,mpf_rtp_media_descriptor_t*) = media;
        return mrcp_session_media_count_get(descriptor) - 1;
 }
 
@@ -129,7 +126,7 @@ static APR_INLINE mpf_rtp_media_descriptor_t* mrcp_session_video_media_get(const
        if((int)id >= descriptor->video_media_arr->nelts) {
                return NULL;
        }
-       return ((mpf_rtp_media_descriptor_t**)descriptor->video_media_arr->elts)[id];
+       return APR_ARRAY_IDX(descriptor->video_media_arr,id,mpf_rtp_media_descriptor_t*);
 }
 
 static APR_INLINE apt_bool_t mrcp_session_video_media_set(mrcp_session_descriptor_t *descriptor, apr_size_t id, mpf_rtp_media_descriptor_t* media)
@@ -137,7 +134,7 @@ static APR_INLINE apt_bool_t mrcp_session_video_media_set(mrcp_session_descripto
        if((int)id >= descriptor->video_media_arr->nelts) {
                return FALSE;
        }
-       ((mpf_rtp_media_descriptor_t**)descriptor->video_media_arr->elts)[id] = media;
+       APR_ARRAY_IDX(descriptor->video_media_arr,id,mpf_rtp_media_descriptor_t*) = media;
        return TRUE;
 }
 
index 2d823331b70b25574517f2eb03e7a8e8e17fb77c..014261f81df27dadb7ca249ff39dfe5f9b49c3f5 100644 (file)
@@ -11,32 +11,31 @@ noinst_LTLIBRARIES       = libmrcp.la
 
 include_HEADERS          = include/mrcp.h \
                            include/mrcp_types.h \
+                           message/include/mrcp_start_line.h \
                            message/include/mrcp_header_accessor.h \
                            message/include/mrcp_generic_header.h \
                            message/include/mrcp_message.h \
-                           control/include/mrcp_state_machine.h \
                            control/include/mrcp_resource.h \
                            control/include/mrcp_resource_factory.h \
+                           control/include/mrcp_resource_loader.h \
                            control/include/mrcp_stream.h \
                            resources/include/mrcp_synth_header.h \
                            resources/include/mrcp_synth_resource.h \
-                           resources/include/mrcp_synth_state_machine.h \
                            resources/include/mrcp_recog_header.h \
                            resources/include/mrcp_recog_resource.h \
-                           resources/include/mrcp_recog_state_machine.h \
-                           resources/include/mrcp_default_factory.h
+                           resources/include/mrcp_recorder_header.h \
+                           resources/include/mrcp_recorder_resource.h
 
 libmrcp_la_SOURCES       = message/src/mrcp_header_accessor.c \
                            message/src/mrcp_generic_header.c \
+                           message/src/mrcp_start_line.c \
                            message/src/mrcp_message.c \
                            control/src/mrcp_resource_factory.c \
+                           control/src/mrcp_resource_loader.c \
                            control/src/mrcp_stream.c \
                            resources/src/mrcp_synth_header.c \
                            resources/src/mrcp_synth_resource.c \
-                           resources/src/mrcp_synth_server_state_machine.c \
-                           resources/src/mrcp_synth_client_state_machine.c \
                            resources/src/mrcp_recog_header.c \
                            resources/src/mrcp_recog_resource.c \
-                           resources/src/mrcp_recog_server_state_machine.c \
-                           resources/src/mrcp_recog_client_state_machine.c \
-                           resources/src/mrcp_default_factory.c
+                           resources/src/mrcp_recorder_header.c \
+                           resources/src/mrcp_recorder_resource.c
index b46851b2acaddcb8aec14be0073b3cade3037cd3..dd7a7f8abd1e31c0f5f7f62da2a8b1fe45533d98 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "mrcp_types.h"
 #include "mrcp_header_accessor.h"
-#include "mrcp_state_machine.h"
 
 APT_BEGIN_EXTERN_C
 
@@ -32,33 +31,48 @@ APT_BEGIN_EXTERN_C
 /** MRCP resource definition */
 struct mrcp_resource_t {
        /** MRCP resource identifier */
-       mrcp_resource_id            id;
+       mrcp_resource_id id;
+       /** MRCP resource name */
+       apt_str_t        name;
 
-       /** Set resource specific data in a message by resource id */
-       apt_bool_t (*resourcify_message_by_id)(mrcp_resource_t *resource, mrcp_message_t *message);
-       /** Set resource specific data in a message by resource name */
-       apt_bool_t (*resourcify_message_by_name)(mrcp_resource_t *resource, mrcp_message_t *message);
+       /** Get string table of methods */
+       const apt_str_table_item_t* (*get_method_str_table)(mrcp_version_e version);
+       /** Number of methods */
+       apr_size_t       method_count;
 
-       /** Create client side state machine */
-       mrcp_state_machine_t* (*create_client_state_machine)(void *obj, mrcp_version_e version, apr_pool_t *pool);
-       /** Create server side state machine */
-       mrcp_state_machine_t* (*create_server_state_machine)(void *obj, mrcp_version_e version, apr_pool_t *pool);
+       /** Get string table of events */
+       const apt_str_table_item_t* (*get_event_str_table)(mrcp_version_e version);
+       /** Number of events */
+       apr_size_t       event_count;
+
+       /** Get vtable of resource header */
+       const mrcp_header_vtable_t* (*get_resource_header_vtable)(mrcp_version_e version);
 };
 
 /** Initialize MRCP resource */
-static APR_INLINE void mrcp_resource_init(mrcp_resource_t *resource)
+static APR_INLINE mrcp_resource_t* mrcp_resource_create(apr_pool_t *pool)
 {
-       resource->resourcify_message_by_id = NULL;
-       resource->resourcify_message_by_name = NULL;
-       resource->create_client_state_machine = NULL;
-       resource->create_server_state_machine = NULL;
+       mrcp_resource_t *resource = (mrcp_resource_t*) apr_palloc(pool, sizeof(mrcp_resource_t));
+       resource->id = 0;
+       apt_string_reset(&resource->name);
+       resource->method_count = 0;
+       resource->event_count = 0;
+       resource->get_method_str_table = NULL;
+       resource->get_event_str_table = NULL;
+       resource->get_resource_header_vtable = NULL;
+       return resource;
 }
 
 /** Validate MRCP resource */
 static APR_INLINE apt_bool_t mrcp_resource_validate(mrcp_resource_t *resource)
 {
-       return (resource->resourcify_message_by_id && 
-               resource->resourcify_message_by_name) ? TRUE : FALSE;
+       if(resource->method_count && resource->event_count &&
+               resource->get_method_str_table && resource->get_event_str_table &&
+                resource->get_resource_header_vtable &&
+                resource->name.buf && resource->name.length) {
+               return TRUE;
+       }
+       return FALSE;
 }
 
 APT_END_EXTERN_C
index 59af8e8ae02f04efe1ba24e1c69e7357c056eb43..f0349a7e2e82632e382f0efe4907386baa4ea159 100644 (file)
@@ -22,7 +22,6 @@
  * @brief Aggregation of MRCP Resources
  */ 
 
-#include "apt_string_table.h"
 #include "apt_text_stream.h"
 #include "mrcp_types.h"
 
@@ -34,27 +33,14 @@ MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_create(apr_size_t r
 /** Destroy MRCP resource factory */
 MRCP_DECLARE(apt_bool_t) mrcp_resource_factory_destroy(mrcp_resource_factory_t *resource_factory);
 
-/** Set MRCP resource string table */
-MRCP_DECLARE(apt_bool_t) mrcp_resource_string_table_set(mrcp_resource_factory_t *resource_factory, const apt_str_table_item_t *string_table);
-
 /** Register MRCP resource */
-MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource, mrcp_resource_id resource_id);
+MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource);
 
 /** Get MRCP resource by resource id */
 MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id);
 
-/** Get resource name associated with specified resource id */
-MRCP_DECLARE(const apt_str_t*) mrcp_resource_name_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id);
-
-/** Find resource id associated with specified resource name */
-MRCP_DECLARE(mrcp_resource_id) mrcp_resource_id_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *resource_name);
-
-
-/** Associate MRCP resource specific data by resource identifier */
-MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_id(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message);
-
-/** Associate MRCP resource specific data by resource name */
-MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_name(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message);
+/** Find MRCP resource by resource name */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *name);
 
 
 APT_END_EXTERN_C
diff --git a/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h b/libs/unimrcp/libs/mrcp/control/include/mrcp_resource_loader.h
new file mode 100644 (file)
index 0000000..e88cca4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 __MRCP_RESOURCE_LOADER_H__
+#define __MRCP_RESOURCE_LOADER_H__
+
+/**
+ * @file mrcp_resource_loader.h
+ * @brief MRCP Resource Loader
+ */ 
+
+#include "apt_string.h"
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque resource loader declaration */
+typedef struct mrcp_resource_loader_t mrcp_resource_loader_t;
+
+
+/** Create MRCP resource loader */
+MRCP_DECLARE(mrcp_resource_loader_t*) mrcp_resource_loader_create(apt_bool_t load_all_resources, apr_pool_t *pool);
+
+/** Load all MRCP resources */
+MRCP_DECLARE(apt_bool_t) mrcp_resources_load(mrcp_resource_loader_t *loader);
+
+/** Load MRCP resource by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_load(mrcp_resource_loader_t *loader, const apt_str_t *name);
+
+/** Load MRCP resource by resource identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_load_by_id(mrcp_resource_loader_t *loader, mrcp_resource_id id);
+
+/** Get MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(mrcp_resource_loader_t *loader);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RESOURCE_LOADER_H__*/
index 7280d3df4123a580a1f48cf267e3fc8118526338..894f89f1587f16d992dba8027fc72cef9fee2d51 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <apr_hash.h>
 #include "mrcp_resource_factory.h"
 #include "mrcp_message.h"
 #include "mrcp_resource.h"
 
 /** Resource factory definition (aggregation of resources) */
 struct mrcp_resource_factory_t {
-       /** Array of MRCP resources */
-       mrcp_resource_t           **resource_array;
+       /** Array of MRCP resources (reference by id) */
+       mrcp_resource_t **resource_array;
        /** Number of MRCP resources */
-       apr_size_t                  resource_count;
-       /** String table of MRCP resource names */
-       const apt_str_table_item_t *string_table;
+       apr_size_t        resource_count;
+       /** Hash of MRCP resources (reference by name) */
+       apr_hash_t       *resource_hash;
 };
 
 /** Create MRCP resource factory */
@@ -44,8 +45,7 @@ MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_create(apr_size_t r
        for(i=0; i<resource_count; i++) {
                resource_factory->resource_array[i] = NULL;
        }
-       resource_factory->string_table = NULL;
-       
+       resource_factory->resource_hash = apr_hash_make(pool);
        return resource_factory;
 }
 
@@ -59,30 +59,23 @@ MRCP_DECLARE(apt_bool_t) mrcp_resource_factory_destroy(mrcp_resource_factory_t *
        return TRUE;
 }
 
-/** Set MRCP resource string table */
-MRCP_DECLARE(apt_bool_t) mrcp_resource_string_table_set(mrcp_resource_factory_t *resource_factory, const apt_str_table_item_t *string_table)
-{
-       resource_factory->string_table = string_table;
-       return TRUE;
-}
-
 /** Register MRCP resource */
-MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource, mrcp_resource_id resource_id)
+MRCP_DECLARE(apt_bool_t) mrcp_resource_register(mrcp_resource_factory_t *resource_factory, mrcp_resource_t *resource)
 {      
-       if(!resource || resource_id >= resource_factory->resource_count) {
+       if(!resource || resource->id >= resource_factory->resource_count) {
                /* invalid params */
                return FALSE;
        }
-       if(resource_factory->resource_array[resource_id]) {
+       if(resource_factory->resource_array[resource->id]) {
                /* resource with specified id already exists */
                return FALSE;
        }
-       resource->id = resource_id;
        if(mrcp_resource_validate(resource) != TRUE) {
                /* invalid resource */
                return FALSE;
        }
        resource_factory->resource_array[resource->id] = resource;
+       apr_hash_set(resource_factory->resource_hash,resource->name.buf,resource->name.length,resource);
        return TRUE;
 }
 
@@ -95,57 +88,12 @@ MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_get(mrcp_resource_factory_t *resour
        return resource_factory->resource_array[resource_id];
 }
 
-
-/** Set header accessor interface */
-static APR_INLINE void mrcp_generic_header_accessor_set(mrcp_message_t *message)
-{
-       message->header.generic_header_accessor.vtable = mrcp_generic_header_vtable_get(message->start_line.version);
-}
-
-/** Associate MRCP resource specific data by resource identifier */
-MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_id(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message)
-{
-       mrcp_resource_t *resource;
-       const apt_str_t *name;
-       resource = mrcp_resource_get(resource_factory,message->channel_id.resource_id);
-       if(!resource) {
-               return FALSE;
-       }
-       name = mrcp_resource_name_get(resource_factory,resource->id);
-       if(!name) {
-               return FALSE;
-       }
-       /* associate resource_name and resource_id */
-       message->channel_id.resource_name = *name;
-
-       mrcp_generic_header_accessor_set(message);
-       return resource->resourcify_message_by_id(resource,message);
-}
-
-/** Associate MRCP resource specific data by resource name */
-MRCP_DECLARE(apt_bool_t) mrcp_message_resourcify_by_name(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message)
+/** Find MRCP resource by resource name */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_resource_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *name)
 {
-       mrcp_resource_t *resource;
-       /* associate resource_name and resource_id */
-       const apt_str_t *name = &message->channel_id.resource_name;
-       message->channel_id.resource_id = mrcp_resource_id_find(resource_factory,name);
-       resource = mrcp_resource_get(resource_factory,message->channel_id.resource_id);
-       if(!resource) {
-               return FALSE;
+       if(!name->buf || !name->length) {
+               return NULL;
        }
 
-       mrcp_generic_header_accessor_set(message);
-       return resource->resourcify_message_by_name(resource,message);
-}
-
-/** Get resource name associated with specified resource id */
-MRCP_DECLARE(const apt_str_t*) mrcp_resource_name_get(mrcp_resource_factory_t *resource_factory, mrcp_resource_id resource_id)
-{
-       return apt_string_table_str_get(resource_factory->string_table,resource_factory->resource_count,resource_id);
-}
-
-/** Find resource id associated with specified resource name */
-MRCP_DECLARE(mrcp_resource_id) mrcp_resource_id_find(mrcp_resource_factory_t *resource_factory, const apt_str_t *resource_name)
-{
-       return apt_string_table_id_find(resource_factory->string_table,resource_factory->resource_count,resource_name);
+       return apr_hash_get(resource_factory->resource_hash,name->buf,name->length);
 }
diff --git a/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c b/libs/unimrcp/libs/mrcp/control/src/mrcp_resource_loader.c
new file mode 100644 (file)
index 0000000..c670b8b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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 "mrcp_resource_loader.h"
+#include "mrcp_resource_factory.h"
+#include "mrcp_resource.h"
+#include "mrcp_synth_resource.h"
+#include "mrcp_recog_resource.h"
+#include "mrcp_recorder_resource.h"
+#include "apt_log.h"
+
+/** Resource loader */
+struct mrcp_resource_loader_t {
+       mrcp_resource_factory_t *factory;
+       apr_pool_t              *pool;
+};
+
+/** String table of MRCPv2 resources (mrcp_resource_types_e) */
+static const apt_str_table_item_t mrcp_resource_string_table[] = {
+       {{"speechsynth",11},6},
+       {{"speechrecog",11},6},
+       {{"recorder",    8},0}
+};
+
+static mrcp_resource_t* mrcp_resource_create_by_id(mrcp_resource_id id, apr_pool_t *pool);
+
+/** Create default MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_loader_t*) mrcp_resource_loader_create(apt_bool_t load_all_resources, apr_pool_t *pool)
+{
+       mrcp_resource_loader_t *loader;
+       mrcp_resource_factory_t *resource_factory;
+       resource_factory = mrcp_resource_factory_create(MRCP_RESOURCE_TYPE_COUNT,pool);
+       if(!resource_factory) {
+               return NULL;
+       }
+       
+       loader = apr_palloc(pool,sizeof(mrcp_resource_loader_t));
+       loader->factory = resource_factory;
+       loader->pool = pool;
+
+       if(load_all_resources == TRUE) {
+               mrcp_resources_load(loader);
+       }
+
+       return loader;
+}
+
+/** Load all MRCP resources */
+MRCP_DECLARE(apt_bool_t) mrcp_resources_load(mrcp_resource_loader_t *loader)
+{
+       mrcp_resource_id id;
+       for(id=0; id<MRCP_RESOURCE_TYPE_COUNT; id++) {
+               mrcp_resource_load_by_id(loader,id);
+       }
+       return TRUE;
+}
+
+/** Load MRCP resource by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_load(mrcp_resource_loader_t *loader, const apt_str_t *name)
+{
+       mrcp_resource_id id = apt_string_table_id_find(
+                                                       mrcp_resource_string_table,
+                                                       MRCP_RESOURCE_TYPE_COUNT,
+                                                       name);
+
+       mrcp_resource_t *resource = mrcp_resource_create_by_id(id,loader->pool);
+       if(!resource) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Failed to Load Resource [%d]",id);
+               return FALSE;
+       }
+
+       apt_string_copy(&resource->name,name,loader->pool);
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Resource [%s]",name->buf);
+       return mrcp_resource_register(loader->factory,resource);
+}
+
+/** Load MRCP resource by resource identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_resource_load_by_id(mrcp_resource_loader_t *loader, mrcp_resource_id id)
+{
+       const apt_str_t *name = apt_string_table_str_get(
+                                                               mrcp_resource_string_table,
+                                                               MRCP_RESOURCE_TYPE_COUNT,
+                                                               id);
+       mrcp_resource_t *resource = mrcp_resource_create_by_id(id,loader->pool);
+       if(!resource || !name) {
+               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Failed to Load Resource [%d]",id);
+               return FALSE;
+       }
+
+       resource->name = *name;
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Resource [%s]",resource->name.buf);
+       return mrcp_resource_register(loader->factory,resource);
+}
+
+/** Get MRCP resource factory */
+MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_resource_factory_get(mrcp_resource_loader_t *loader)
+{
+       return loader->factory;
+}
+
+static mrcp_resource_t* mrcp_resource_create_by_id(mrcp_resource_id id, apr_pool_t *pool)
+{
+       mrcp_resource_t *resource = NULL;
+       switch(id) {
+               case MRCP_SYNTHESIZER_RESOURCE:
+                       resource = mrcp_synth_resource_create(pool);
+                       break;
+               case MRCP_RECOGNIZER_RESOURCE:
+                       resource = mrcp_recog_resource_create(pool);
+                       break;
+               case MRCP_RECORDER_RESOURCE:
+                       resource = mrcp_recorder_resource_create(pool);
+                       break;
+       }
+       
+       if(resource) {
+               resource->id = id;
+       }
+       return resource;
+}
index f90d0686424999ff67e5d0b041edbdefcc0db17a..43844161f514214f3d82c26985914e5acb3aa774 100644 (file)
@@ -121,6 +121,8 @@ static mrcp_stream_result_e mrcp_message_body_generate(mrcp_message_t *message,
 /** Parse MRCP message (excluding message body) */
 MRCP_DECLARE(apt_bool_t) mrcp_message_parse(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream)
 {
+       mrcp_resource_t *resource;
+
        /* parse start-line */
        if(mrcp_start_line_parse(&message->start_line,stream,message->pool) == FALSE) {
                return FALSE;
@@ -130,7 +132,13 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_parse(mrcp_resource_factory_t *resource_fa
                mrcp_channel_id_parse(&message->channel_id,stream,message->pool);
        }
 
-       if(mrcp_message_resourcify_by_name(resource_factory,message) == FALSE) {
+       /* find resource */
+       resource = mrcp_resource_find(resource_factory,&message->channel_id.resource_name);
+       if(!resource) {
+               return FALSE;
+       }
+
+       if(mrcp_message_resource_set(message,resource) == FALSE) {
                return FALSE;
        }
 
@@ -145,11 +153,6 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_parse(mrcp_resource_factory_t *resource_fa
 /** Generate MRCP message (excluding message body) */
 MRCP_DECLARE(apt_bool_t) mrcp_message_generate(mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream)
 {
-       /* initialize resource specific data */
-       if(mrcp_message_resourcify_by_id(resource_factory,message) == FALSE) {
-               return FALSE;
-       }
-
        /* validate message */
        if(mrcp_message_validate(message) == FALSE) {
                return FALSE;
@@ -170,7 +173,10 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_generate(mrcp_resource_factory_t *resource
        }
 
        /* finalize start-line generation */
-       mrcp_start_line_finalize(&message->start_line,message->body.length,stream);
+       if(mrcp_start_line_finalize(&message->start_line,message->body.length,stream) == FALSE) {
+               return FALSE;
+       }
+
        return TRUE;
 }
 
index 9b381ab2c3a9a81969ad85af1a095b204cfe7f2f..3177077b39ab99662bee9f88bb4b86a473bbc7fe 100644 (file)
@@ -31,22 +31,39 @@ typedef enum {
        
        MRCP_VERSION_UNKNOWN = 0,  /**< Unknown version */
        MRCP_VERSION_1 = 1,        /**< MRCPv1 (RFC4463) */
-       MRCP_VERSION_2 = 2         /**< MRCPv2 (draft-ietf-speechsc-mrcpv2-15) */
+       MRCP_VERSION_2 = 2         /**< MRCPv2 (draft-ietf-speechsc-mrcpv2-20) */
 } mrcp_version_e;
 
 /** Enumeration of MRCP resource types */
 typedef enum {
        MRCP_SYNTHESIZER_RESOURCE, /**< Synthesizer resource */
        MRCP_RECOGNIZER_RESOURCE,  /**< Recognizer resource */
+       MRCP_RECORDER_RESOURCE,    /**< Recorder resource */
 
        MRCP_RESOURCE_TYPE_COUNT   /**< Number of resources */
 } mrcp_resource_type_e;
 
-/** Message identifier used in request/response/event messages. */
-typedef apr_size_t  mrcp_request_id;
-/** Method identifier associated with method name. */
+/* MRCPv2 specifies request-id as 32bit unsigned integer,
+ * while MRCPv1 doesn't limit this value (1 * DIGIT).
+ * Some MRCPv1 clients use too long request-id. 
+ * To support them #define TOO_LONG_MRCP_REQUEST_ID
+ */
+#ifdef TOO_LONG_MRCP_REQUEST_ID
+/** MRCP request identifier */
+typedef apr_uint64_t  mrcp_request_id;
+/** Format to log MRCP request identifier */
+#define MRCP_REQUEST_ID_FMT    APR_UINT64_T_FMT
+#else 
+/** MRCP request identifier */
+typedef apr_uint32_t  mrcp_request_id;
+/** Format to log MRCP request identifier */
+#define MRCP_REQUEST_ID_FMT    "d"
+#endif
+
+
+/** Method identifier associated with method name */
 typedef apr_size_t mrcp_method_id;
-/** Resource identifier associated with resource name. */
+/** Resource identifier associated with resource name */
 typedef apr_size_t mrcp_resource_id;
 
 
index 769ab089893331044d67e774b33967729fdc883e..497a14d7c3c30b9c609513f2e980312b0947c1c5 100644 (file)
  */ 
 
 #include "mrcp_types.h"
+#include "mrcp_start_line.h"
 #include "mrcp_header_accessor.h"
 
 APT_BEGIN_EXTERN_C
 
-/** Request-states used in MRCP response message */
-typedef enum {
-       /** The request was processed to completion and there will be no        
-           more events from that resource to the client with that request-id */
-       MRCP_REQUEST_STATE_COMPLETE,
-       /** The job has been placed on a queue and will be processed in first-in-first-out order */
-       MRCP_REQUEST_STATE_INPROGRESS,
-       /** Indicate that further event messages will be delivered with that request-id */
-       MRCP_REQUEST_STATE_PENDING,
-       
-       /** Number of request states */
-       MRCP_REQUEST_STATE_COUNT,
-       /** Unknown request state */
-       MRCP_REQUEST_STATE_UNKNOWN = MRCP_REQUEST_STATE_COUNT
-} mrcp_request_state_e;
-
-/** Status codes */
-typedef enum {
-       MRCP_STATUS_CODE_UNKNOWN                   = 0,
-       /* success codes (2xx) */
-       MRCP_STATUS_CODE_SUCCESS                   = 200,
-       MRCP_STATUS_CODE_SUCCESS_WITH_IGNORE       = 201,
-       /* failure codes (4xx) */
-       MRCP_STATUS_CODE_METHOD_NOT_ALLOWED        = 401,
-       MRCP_STATUS_CODE_METHOD_NOT_VALID          = 402,
-       MRCP_STATUS_CODE_UNSUPPORTED_PARAM         = 403,
-       MRCP_STATUS_CODE_ILLEGAL_PARAM_VALUE       = 404,
-       MRCP_STATUS_CODE_NOT_FOUND                 = 405,
-       MRCP_STATUS_CODE_MISSING_PARAM             = 406,
-       MRCP_STATUS_CODE_METHOD_FAILED             = 407,
-       MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE      = 408,
-       MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE   = 409,
-       MRCP_STATUS_CODE_RESOURCE_SPECIFIC_FAILURE = 421
-} mrcp_status_code_e;
-
-/** MRCP message types */
-typedef enum {
-       MRCP_MESSAGE_TYPE_UNKNOWN,
-       MRCP_MESSAGE_TYPE_REQUEST,
-       MRCP_MESSAGE_TYPE_RESPONSE,
-       MRCP_MESSAGE_TYPE_EVENT
-} mrcp_message_type_e;
-
-
-/** MRCP start-line declaration */
-typedef struct mrcp_start_line_t mrcp_start_line_t;
 /** MRCP channel-id declaration */
 typedef struct mrcp_channel_id mrcp_channel_id;
 /** MRCP message header declaration */
 typedef struct mrcp_message_header_t mrcp_message_header_t;
 
-
-/** Start-line of MRCP message */
-struct mrcp_start_line_t {
-       /** MRCP message type */
-       mrcp_message_type_e  message_type;
-       /** Version of protocol in use */
-       mrcp_version_e       version;
-       /** Specify the length of the message, including the start-line (v2) */
-       size_t               length;
-       /** Unique identifier among client and server */
-       mrcp_request_id      request_id;
-       /** MRCP method name */
-       apt_str_t            method_name;
-       /** MRCP method id (associated with method name) */
-       mrcp_method_id       method_id;
-       /** Success or failure or other status of the request */
-       mrcp_status_code_e   status_code;
-       /** The state of the job initiated by the request */
-       mrcp_request_state_e request_state;
-};
-
-/** Initialize MRCP start-line */
-MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line);
-/** Parse MRCP start-line */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool);
-/** Generate MRCP start-line */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream);
-/** Finalize MRCP start-line generation */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream);
-
-
 /** MRCP channel-identifier */
 struct mrcp_channel_id {
        /** Unambiguous string identifying the MRCP session */
        apt_str_t        session_id;
        /** MRCP resource name */
        apt_str_t        resource_name;
-       /** MRCP resource id (associated with resource name) */
-       mrcp_resource_id resource_id;
 };
 
 /** Initialize MRCP channel-identifier */
@@ -172,34 +94,33 @@ MRCP_DECLARE(apt_bool_t) mrcp_message_header_inherit(mrcp_message_header_t *mess
 /** MRCP message */
 struct mrcp_message_t {
        /** Start-line of MRCP message */
-       mrcp_start_line_t      start_line;
+       mrcp_start_line_t     start_line;
        /** Channel-identifier of MRCP message */
-       mrcp_channel_id        channel_id;
+       mrcp_channel_id       channel_id;
        /** Header of MRCP message */
-       mrcp_message_header_t  header;
+       mrcp_message_header_t header;
        /** Body of MRCP message */
-       apt_str_t              body;
+       apt_str_t             body;
 
+       /** Associated MRCP resource */
+       mrcp_resource_t      *resource;
        /** Memory pool MRCP message is allocated from */
-       apr_pool_t            *pool;
+       apr_pool_t           *pool;
 };
 
 /** Create MRCP message */
 MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool);
 
-/** Initialize MRCP message */
-MRCP_DECLARE(void) mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool);
-
-/** Initialize MRCP response/event message by request message */
-MRCP_DECLARE(void) mrcp_message_init_by_request(mrcp_message_t *message, const mrcp_message_t *request_message);
-
 /** Create MRCP request message */
-MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_id resource_id, mrcp_method_id method_id, apr_pool_t *pool);
+MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_t *resource, mrcp_version_e version, mrcp_method_id method_id, apr_pool_t *pool);
 /** Create MRCP response message */
 MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool);
 /** Create MRCP event message */
 MRCP_DECLARE(mrcp_message_t*) mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool);
 
+/** Associate MRCP resource specific data by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, mrcp_resource_t *resource);
+
 /** Validate MRCP message */
 MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message);
 
diff --git a/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h b/libs/unimrcp/libs/mrcp/message/include/mrcp_start_line.h
new file mode 100644 (file)
index 0000000..1c6db22
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 __MRCP_START_LINE_H__
+#define __MRCP_START_LINE_H__
+
+/**
+ * @file mrcp_start_line.h
+ * @brief MRCP Start Line Definition
+ */ 
+
+#include "mrcp_types.h"
+#include "apt_text_stream.h"
+
+APT_BEGIN_EXTERN_C
+
+/** Request-states used in MRCP response message */
+typedef enum {
+       /** The request was processed to completion and there will be no        
+           more events from that resource to the client with that request-id */
+       MRCP_REQUEST_STATE_COMPLETE,
+       /** The job has been placed on a queue and will be processed in first-in-first-out order */
+       MRCP_REQUEST_STATE_INPROGRESS,
+       /** Indicate that further event messages will be delivered with that request-id */
+       MRCP_REQUEST_STATE_PENDING,
+       
+       /** Number of request states */
+       MRCP_REQUEST_STATE_COUNT,
+       /** Unknown request state */
+       MRCP_REQUEST_STATE_UNKNOWN = MRCP_REQUEST_STATE_COUNT
+} mrcp_request_state_e;
+
+/** Status codes */
+typedef enum {
+       MRCP_STATUS_CODE_UNKNOWN                   = 0,
+       /* success codes (2xx) */
+       MRCP_STATUS_CODE_SUCCESS                   = 200,
+       MRCP_STATUS_CODE_SUCCESS_WITH_IGNORE       = 201,
+       /* failure codes (4xx) */
+       MRCP_STATUS_CODE_METHOD_NOT_ALLOWED        = 401,
+       MRCP_STATUS_CODE_METHOD_NOT_VALID          = 402,
+       MRCP_STATUS_CODE_UNSUPPORTED_PARAM         = 403,
+       MRCP_STATUS_CODE_ILLEGAL_PARAM_VALUE       = 404,
+       MRCP_STATUS_CODE_NOT_FOUND                 = 405,
+       MRCP_STATUS_CODE_MISSING_PARAM             = 406,
+       MRCP_STATUS_CODE_METHOD_FAILED             = 407,
+       MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE      = 408,
+       MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE   = 409,
+       MRCP_STATUS_CODE_RESOURCE_SPECIFIC_FAILURE = 421
+} mrcp_status_code_e;
+
+/** MRCP message types */
+typedef enum {
+       MRCP_MESSAGE_TYPE_UNKNOWN,
+       MRCP_MESSAGE_TYPE_REQUEST,
+       MRCP_MESSAGE_TYPE_RESPONSE,
+       MRCP_MESSAGE_TYPE_EVENT
+} mrcp_message_type_e;
+
+
+/** MRCP start-line declaration */
+typedef struct mrcp_start_line_t mrcp_start_line_t;
+
+/** Start-line of MRCP message */
+struct mrcp_start_line_t {
+       /** MRCP message type */
+       mrcp_message_type_e  message_type;
+       /** Version of protocol in use */
+       mrcp_version_e       version;
+       /** Specify the length of the message, including the start-line (v2) */
+       apr_size_t           length;
+       /** Unique identifier among client and server */
+       mrcp_request_id      request_id;
+       /** MRCP method name */
+       apt_str_t            method_name;
+       /** MRCP method id (associated with method name) */
+       mrcp_method_id       method_id;
+       /** Success or failure or other status of the request */
+       mrcp_status_code_e   status_code;
+       /** The state of the job initiated by the request */
+       mrcp_request_state_e request_state;
+};
+
+/** Initialize MRCP start-line */
+MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line);
+/** Parse MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool);
+/** Generate MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream);
+/** Finalize MRCP start-line generation */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream);
+
+/** Parse MRCP request-id */
+MRCP_DECLARE(mrcp_request_id) mrcp_request_id_parse(const apt_str_t *field);
+/** Generate MRCP request-id */
+MRCP_DECLARE(apt_bool_t) mrcp_request_id_generate(mrcp_request_id request_id, apt_text_stream_t *stream);
+
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_START_LINE_H__*/
index fe1b796dcd70dae0107b06ba7d01aa6801d95937..3f2c57ab107ca882dd4269d8b42132082fcb028f 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "mrcp_generic_header.h"
+#include "mrcp_start_line.h"
 
 /** String table of mrcp generic-header fields (mrcp_generic_header_id) */
 static const apt_str_table_item_t generic_header_string_table[] = {
@@ -36,7 +37,6 @@ static const apt_str_table_item_t generic_header_string_table[] = {
        {{"Set-Cookie2",               11},10}
 };
 
-
 /** Parse mrcp request-id list */
 static apt_bool_t mrcp_request_id_list_parse(mrcp_request_id_list_t *request_id_list, const apt_str_t *value)
 {
@@ -49,7 +49,7 @@ static apt_bool_t mrcp_request_id_list_parse(mrcp_request_id_list_t *request_id_
                if(apt_text_field_read(&stream,',',TRUE,&field) == FALSE) {
                        break;
                }
-               request_id_list->ids[request_id_list->count] = apt_size_value_parse(&field);
+               request_id_list->ids[request_id_list->count] = mrcp_request_id_parse(&field);
                request_id_list->count++;
        }
        return TRUE;
@@ -60,7 +60,7 @@ static apt_bool_t mrcp_request_id_list_generate(mrcp_request_id_list_t *request_
 {
        size_t i;
        for(i=0; i<request_id_list->count; i++) {
-               apt_size_value_generate(request_id_list->ids[i],stream);
+               mrcp_request_id_generate(request_id_list->ids[i],stream);
                if(i < request_id_list->count-1) {
                        *stream->pos++ = ',';
                }
index e7219006dc6bcd755ef14f9e2ee631af130ba7e5..5c293ec11cbf143beb46ab43f72b79296d781786 100644 (file)
@@ -79,6 +79,10 @@ MRCP_DECLARE(apt_bool_t) mrcp_header_generate(mrcp_header_accessor_t *accessor,
 
 MRCP_DECLARE(void) mrcp_header_property_add(mrcp_header_accessor_t *accessor, apr_size_t id)
 {
+       if(!accessor->vtable) {
+               return;
+       }
+
        if(id < accessor->vtable->field_count) {
                char *prop = &accessor->properties[id];
                if((*prop & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) {
@@ -90,6 +94,10 @@ MRCP_DECLARE(void) mrcp_header_property_add(mrcp_header_accessor_t *accessor, ap
 
 MRCP_DECLARE(void) mrcp_header_name_property_add(mrcp_header_accessor_t *accessor, apr_size_t id)
 {
+       if(!accessor->vtable) {
+               return;
+       }
+
        if(id < accessor->vtable->field_count) {
                char *prop = &accessor->properties[id];
                if((*prop & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) {
@@ -102,6 +110,10 @@ MRCP_DECLARE(void) mrcp_header_name_property_add(mrcp_header_accessor_t *accesso
 
 MRCP_DECLARE(void) mrcp_header_property_remove(mrcp_header_accessor_t *accessor, apr_size_t id)
 {
+       if(!accessor->vtable) {
+               return;
+       }
+
        if(id < accessor->vtable->field_count) {
                char *prop = &accessor->properties[id];
                if((*prop & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
@@ -113,6 +125,10 @@ MRCP_DECLARE(void) mrcp_header_property_remove(mrcp_header_accessor_t *accessor,
 
 MRCP_DECLARE(apt_bool_t) mrcp_header_property_check(mrcp_header_accessor_t *accessor, apr_size_t id)
 {
+       if(!accessor->vtable) {
+               return FALSE;
+       }
+
        if((id < accessor->vtable->field_count) && accessor->properties) {
                if((accessor->properties[id] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
                        return TRUE;
@@ -161,12 +177,14 @@ MRCP_DECLARE(apt_bool_t) mrcp_header_inherit(mrcp_header_accessor_t *accessor, c
        for(i=0, j=0; i<parent->vtable->field_count && j < parent->counter; i++) {
                if((parent->properties[i] & MRCP_HEADER_FIELD_NAME) == MRCP_HEADER_FIELD_NAME) {
                        j++;
-                       if((parent->properties[i] & MRCP_HEADER_FIELD_VALUE) == MRCP_HEADER_FIELD_VALUE) {
-                               accessor->vtable->duplicate_field(accessor,parent,i,pool);
-                               mrcp_header_property_add(accessor,i);
-                       }
-                       else {
-                               mrcp_header_name_property_add(accessor,i);
+                       if((accessor->properties[i] & MRCP_HEADER_FIELD_NAME) != MRCP_HEADER_FIELD_NAME) {
+                               if((parent->properties[i] & MRCP_HEADER_FIELD_VALUE) == MRCP_HEADER_FIELD_VALUE) {
+                                       accessor->vtable->duplicate_field(accessor,parent,i,pool);
+                                       mrcp_header_property_add(accessor,i);
+                               }
+                               else {
+                                       mrcp_header_name_property_add(accessor,i);
+                               }
                        }
                }
        }
index dbe8627f5d910a96546ac11f9e9589c542612243..96b52784f51042829bdd4284c103d2c8e29d7a7f 100644 (file)
 
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
+#include "mrcp_resource.h"
 #include "apt_log.h"
 
-/** Protocol name used in version string */
-#define MRCP_NAME               "MRCP"
-#define MRCP_NAME_LENGTH        (sizeof(MRCP_NAME)-1)
-
 #define MRCP_CHANNEL_ID         "Channel-Identifier"
 #define MRCP_CHANNEL_ID_LENGTH  (sizeof(MRCP_CHANNEL_ID)-1)
 
-/** Separators used in MRCP version string parse/generate */
-#define MRCP_NAME_VERSION_SEPARATOR        '/'
-#define MRCP_VERSION_MAJOR_MINOR_SEPARATOR '.'
-
-#define MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT 4
-
-
-/** String table of MRCP request-states (mrcp_request_state_t) */
-static const apt_str_table_item_t mrcp_request_state_string_table[] = {
-       {{"COMPLETE",    8},0},
-       {{"IN-PROGRESS",11},0},
-       {{"PENDING",     7},0}
-};
-
-
-/** Parse MRCP version */
-static mrcp_version_e mrcp_version_parse(const apt_str_t *field)
-{
-       mrcp_version_e version = MRCP_VERSION_UNKNOWN;
-       const char *pos;
-       if(field->length <= MRCP_NAME_LENGTH || strncasecmp(field->buf,MRCP_NAME,MRCP_NAME_LENGTH) != 0) {
-               /* unexpected protocol name */
-               return version;
-       }
-
-       pos = field->buf + MRCP_NAME_LENGTH;
-       if(*pos == MRCP_NAME_VERSION_SEPARATOR) {
-               pos++;
-               switch(*pos) {
-                       case '1': version = MRCP_VERSION_1; break;
-                       case '2': version = MRCP_VERSION_2; break;
-                       default: ;
-               }
-       }
-       return version;
-}
-
-/** Generate MRCP version */
-static apt_bool_t mrcp_version_generate(mrcp_version_e version, apt_text_stream_t *stream)
-{
-       memcpy(stream->pos,MRCP_NAME,MRCP_NAME_LENGTH);
-       stream->pos += MRCP_NAME_LENGTH;
-       *stream->pos++ = MRCP_NAME_VERSION_SEPARATOR;
-       apt_size_value_generate(version,stream);
-       *stream->pos++ = MRCP_VERSION_MAJOR_MINOR_SEPARATOR;
-       *stream->pos++ = '0';
-       return TRUE;
-}
-
-/** Parse MRCP request-state used in MRCP response and event */
-static APR_INLINE mrcp_request_state_e mrcp_request_state_parse(const apt_str_t *request_state_str)
-{
-       return apt_string_table_id_find(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state_str);
-}
-
-/** Generate MRCP request-state used in MRCP response and event */
-static apt_bool_t mrcp_request_state_generate(mrcp_request_state_e request_state, apt_text_stream_t *stream)
-{
-       const apt_str_t *name;
-       name = apt_string_table_str_get(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state);
-       if(request_state < MRCP_REQUEST_STATE_COUNT) {
-               memcpy(stream->pos,name->buf,name->length);
-               stream->pos += name->length;
-       }
-       return TRUE;
-}
-
-
-/** Parse MRCP request-id */
-static APR_INLINE mrcp_request_id mrcp_request_id_parse(const apt_str_t *field)
-{
-       return apt_size_value_parse(field);
-}
-
-/** Generate MRCP request-id */
-static APR_INLINE apt_bool_t mrcp_request_id_generate(mrcp_request_id request_id, apt_text_stream_t *stream)
-{
-       return apt_size_value_generate(request_id,stream);
-}
-
-/** Parse MRCP status-code */
-static APR_INLINE mrcp_status_code_e mrcp_status_code_parse(const apt_str_t *field)
-{
-       return apt_size_value_parse(field);
-}
-
-/** Generate MRCP status-code */
-static APR_INLINE size_t  mrcp_status_code_generate(mrcp_status_code_e status_code, apt_text_stream_t *stream)
-{
-       return apt_size_value_generate(status_code,stream);
-}
-
-
-/** Parse MRCP request-line */
-static apt_bool_t mrcp_request_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
-{
-       apt_str_t field;
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in request-line");
-               return FALSE;
-       }
-       start_line->request_id = mrcp_request_id_parse(&field);
-
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
-               return FALSE;
-       }
-
-       start_line->request_state = mrcp_request_state_parse(&field);
-       if(start_line->request_state == MRCP_REQUEST_STATE_UNKNOWN) {
-               /* request-line */
-               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
-       }
-       else {
-               /* event line */
-               start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
-
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
-                       return FALSE;
-               }
-       }
-
-       start_line->version = mrcp_version_parse(&field);
-       if(start_line->version == MRCP_VERSION_UNKNOWN) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown mrcp-version");
-               return FALSE;
-       }
-       return TRUE;
-}
-
-/** Generate MRCP request-line */
-static apt_bool_t mrcp_request_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
-{
-       memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
-       stream->pos += start_line->method_name.length;
-       *stream->pos++ = APT_TOKEN_SP;
-
-       mrcp_request_id_generate(start_line->request_id,stream);
-       *stream->pos++ = APT_TOKEN_SP;
-
-       if(start_line->message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               if(start_line->status_code != MRCP_STATUS_CODE_UNKNOWN) {
-                       mrcp_status_code_generate(start_line->status_code,stream);
-                       *stream->pos++ = APT_TOKEN_SP;
-               }
-       }
-       else if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
-               mrcp_request_state_generate(start_line->request_state,stream);
-               *stream->pos++ = APT_TOKEN_SP;
-       }
-
-       mrcp_version_generate(start_line->version,stream);
-       return TRUE;
-}
-
-/** Parse MRCP response-line */
-static apt_bool_t mrcp_response_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
-{
-       apt_str_t field;
-       start_line->length = 0;
-       if(start_line->version == MRCP_VERSION_2) {
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in response-line");
-                       return FALSE;
-               }
-               start_line->length = apt_size_value_parse(&field);
-       }
-
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in response-line");
-               return FALSE;
-       }
-       start_line->request_id = mrcp_request_id_parse(&field);
-
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in response-line");
-               return FALSE;
-       }
-       start_line->status_code = mrcp_status_code_parse(&field);
-
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in response-line");
-               return FALSE;
-       }
-       start_line->request_state = mrcp_request_state_parse(&field);
-       return TRUE;
-}
-
-/** Generate MRCP response-line */
-static apt_bool_t mrcp_response_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
-{
-       mrcp_version_generate(start_line->version,stream);
-       *stream->pos++ = APT_TOKEN_SP;
-
-       mrcp_request_id_generate(start_line->request_id,stream);
-       *stream->pos++ = APT_TOKEN_SP;
-
-       mrcp_status_code_generate(start_line->status_code,stream);
-       *stream->pos++ = APT_TOKEN_SP;
-
-       mrcp_request_state_generate(start_line->request_state,stream);
-       return TRUE;
-}
-
-/** Parse MRCP v2 start-line */
-static apt_bool_t mrcp_v2_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream, apr_pool_t *pool)
-{
-       apt_str_t field;
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in v2 start-line");
-               return FALSE;
-       }
-       start_line->length = apt_size_value_parse(&field);
-
-       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
-               return FALSE;
-       }
-       start_line->request_id = mrcp_request_id_parse(&field);
-       if(start_line->request_id == 0 && *field.buf != '0') {
-               /* parsing MRCP v2 request or event */
-               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
-               apt_string_copy(&start_line->method_name,&field,pool);
-
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
-                       return FALSE;
-               }
-               start_line->request_id = mrcp_request_id_parse(&field);
-
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == TRUE) {
-                       /* parsing MRCP v2 event */
-                       start_line->request_state = mrcp_request_state_parse(&field);
-                       start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
-               }
-       }
-       else {
-               /* parsing MRCP v2 response */
-               start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
-
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in v2 start-line");
-                       return FALSE;
-               }
-               start_line->status_code = mrcp_status_code_parse(&field);
-
-               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in v2 start-line");
-                       return FALSE;
-               }
-               start_line->request_state = mrcp_request_state_parse(&field);
-       }
-
-       return TRUE;
-}
-
-/** Generate MRCP v2 start-line */
-static apt_bool_t mrcp_v2_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
-{
-       char *pos = stream->pos;
-       mrcp_version_generate(start_line->version,stream);
-       *stream->pos++ = APT_TOKEN_SP;
-
-       start_line->length = stream->pos - pos; /* length is temrorary used to store offset */
-       /* reserving MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT space for start_line->length */
-       memset(stream->pos,APT_TOKEN_SP,MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT+1);
-       stream->pos += MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT+1;
-
-       if(start_line->message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
-               mrcp_request_id_generate(start_line->request_id,stream);
-               *stream->pos++ = APT_TOKEN_SP;
-
-               mrcp_status_code_generate(start_line->status_code,stream);
-               *stream->pos++ = APT_TOKEN_SP;
-
-               mrcp_request_state_generate(start_line->request_state,stream);
-               *stream->pos++ = APT_TOKEN_SP;
-       }
-       else {
-               memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
-               stream->pos += start_line->method_name.length;
-               *stream->pos++ = APT_TOKEN_SP;
-
-               mrcp_request_id_generate(start_line->request_id,stream);
-               if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
-                       *stream->pos++ = APT_TOKEN_SP;
-                       mrcp_request_state_generate(start_line->request_state,stream);
-               }
-       }
-       return TRUE;
-}
-
-/** Initialize MRCP start-line */
-MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line)
-{
-       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
-       start_line->version = MRCP_VERSION_UNKNOWN;
-       start_line->length = 0;
-       start_line->request_id = 0;
-       apt_string_reset(&start_line->method_name);
-       start_line->status_code = MRCP_STATUS_CODE_UNKNOWN;
-       start_line->request_state = MRCP_REQUEST_STATE_UNKNOWN;
-}
-
-/** Parse MRCP start-line */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool)
-{
-       apt_text_stream_t line;
-       apt_str_t field;
-       apt_bool_t status = TRUE;
-       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
-       if(apt_text_line_read(text_stream,&line.text) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse MRCP start-line");
-               return FALSE;
-       }
-       line.pos = line.text.buf;
-
-       if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot read the first field in start-line");
-               return FALSE;
-       }
-
-       if(field.buf == strstr(field.buf,MRCP_NAME)) {
-               start_line->version = mrcp_version_parse(&field);
-
-               if(start_line->version == MRCP_VERSION_1) {
-                       /* parsing MRCP v1 response */
-                       start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
-                       status = mrcp_response_line_parse(start_line,&line);
-               }
-               else if(start_line->version == MRCP_VERSION_2) {
-                       /* parsing MRCP v2 start-line (request/response/event) */
-                       status = mrcp_v2_start_line_parse(start_line,&line,pool);
-               }
-               else {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown MRCP version");
-                       return FALSE;
-               }
-       }
-       else {
-               /* parsing MRCP v1 request or event */
-               apt_string_copy(&start_line->method_name,&field,pool);
-               status = mrcp_request_line_parse(start_line,&line);
-       }
-       return status;
-}
-
-/** Generate MRCP start-line */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream)
-{
-       apt_bool_t status = FALSE;
-       if(start_line->version == MRCP_VERSION_1) {
-               switch(start_line->message_type) {
-                       case MRCP_MESSAGE_TYPE_REQUEST:
-                               status = mrcp_request_line_generate(start_line,text_stream);
-                               break;
-                       case MRCP_MESSAGE_TYPE_RESPONSE:
-                               status = mrcp_response_line_generate(start_line,text_stream);
-                               break;
-                       case MRCP_MESSAGE_TYPE_EVENT:
-                               status = mrcp_request_line_generate(start_line,text_stream);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       else if(start_line->version == MRCP_VERSION_2) {
-               status = mrcp_v2_start_line_generate(start_line,text_stream);
-       }
-
-       if(status == TRUE) {
-               apt_text_eol_insert(text_stream);
-       }
-       
-       return status;
-}
-
-/** Finalize MRCP start-line generation */
-MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream)
-{
-       apr_size_t length = text_stream->pos - text_stream->text.buf + content_length;
-       if(start_line->version == MRCP_VERSION_2) {
-               /* message-length includes the number of bytes that specify the message-length in the header */
-               /* too comlex to generate!!! see the discussion */
-               /* http://www1.ietf.org/mail-archive/web/speechsc/current/msg01734.html */
-               apt_str_t field;
-               field.buf = text_stream->text.buf + start_line->length; /* length is temrorary used to store offset */
-               length -= MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT;
-               apt_var_length_value_generate(&length,MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT,&field);
-               field.buf[field.length] = APT_TOKEN_SP;
-               start_line->length += field.length;
-
-               field.length = MRCP_MESSAGE_LENGTH_MAX_DIGITS_COUNT - field.length;
-               if(field.length) {
-                       memmove(text_stream->text.buf+field.length,text_stream->text.buf,start_line->length);
-                       text_stream->text.buf += field.length;
-                       text_stream->text.length -= field.length;
-               }
-       }
-
-       start_line->length = length;
-       return TRUE;
-}
-
 /** Initialize MRCP channel-identifier */
 MRCP_DECLARE(void) mrcp_channel_id_init(mrcp_channel_id *channel_id)
 {
        apt_string_reset(&channel_id->session_id);
        apt_string_reset(&channel_id->resource_name);
-       channel_id->resource_id = 0;
 }
 
 /** Parse MRCP channel-identifier */
@@ -599,43 +190,113 @@ MRCP_DECLARE(apt_bool_t) mrcp_body_generate(mrcp_message_t *message, apt_text_st
        return TRUE;
 }
 
-
-/** Create MRCP message */
-MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool)
-{
-       mrcp_message_t *message = apr_palloc(pool,sizeof(mrcp_message_t));
-       mrcp_message_init(message,pool);
-       return message;
-}
-
 /** Initialize MRCP message */
-MRCP_DECLARE(void) mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool)
+static void mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool)
 {
        mrcp_start_line_init(&message->start_line);
        mrcp_channel_id_init(&message->channel_id);
        mrcp_message_header_init(&message->header);
        apt_string_reset(&message->body);
+       message->resource = NULL;
        message->pool = pool;
 }
 
-/** Initialize response/event message by request message */
-MRCP_DECLARE(void) mrcp_message_init_by_request(mrcp_message_t *message, const mrcp_message_t *request_message)
+/** Set header accessor interface */
+static APR_INLINE void mrcp_generic_header_accessor_set(mrcp_message_t *message)
+{
+       message->header.generic_header_accessor.vtable = mrcp_generic_header_vtable_get(message->start_line.version);
+}
+
+/** Associate MRCP resource specific data by resource identifier */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set_by_id(mrcp_message_t *message, mrcp_resource_t *resource)
+{
+       if(!resource) {
+               return FALSE;
+       }
+       message->resource = resource;
+       
+       message->channel_id.resource_name = resource->name;
+
+       mrcp_generic_header_accessor_set(message);
+       message->header.resource_header_accessor.vtable = 
+               resource->get_resource_header_vtable(message->start_line.version);
+
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       resource->get_method_str_table(message->start_line.version),
+                       resource->method_count,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               const apt_str_t *name = apt_string_table_str_get(
+                       resource->get_event_str_table(message->start_line.version),
+                       resource->event_count,
+                       message->start_line.method_id);
+               if(!name) {
+                       return FALSE;
+               }
+               message->start_line.method_name = *name;
+       }
+
+       return TRUE;
+}
+
+/** Associate MRCP resource specific data by resource name */
+MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, mrcp_resource_t *resource)
+{
+       if(!resource) {
+               return FALSE;
+       }
+       message->resource = resource;
+
+       mrcp_generic_header_accessor_set(message);
+       message->header.resource_header_accessor.vtable = 
+               resource->get_resource_header_vtable(message->start_line.version);
+       
+       /* associate method_name and method_id */
+       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       resource->get_method_str_table(message->start_line.version),
+                       resource->method_count,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= resource->method_count) {
+                       return FALSE;
+               }
+       }
+       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               message->start_line.method_id = apt_string_table_id_find(
+                       resource->get_event_str_table(message->start_line.version),
+                       resource->event_count,
+                       &message->start_line.method_name);
+               if(message->start_line.method_id >= resource->event_count) {
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+/** Create MRCP message */
+MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool)
 {
-       message->channel_id = request_message->channel_id;
-       message->start_line.request_id = request_message->start_line.request_id;
-       message->start_line.version = request_message->start_line.version;
-       message->start_line.method_id = request_message->start_line.method_id;
-       message->header.generic_header_accessor.vtable = request_message->header.generic_header_accessor.vtable;
-       message->header.resource_header_accessor.vtable = request_message->header.resource_header_accessor.vtable;
+       mrcp_message_t *message = apr_palloc(pool,sizeof(mrcp_message_t));
+       mrcp_message_init(message,pool);
+       return message;
 }
 
 /** Create MRCP request message */
-MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_id resource_id, mrcp_method_id method_id, apr_pool_t *pool)
+MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_t *resource, mrcp_version_e version, mrcp_method_id method_id, apr_pool_t *pool)
 {
        mrcp_message_t *request_message = mrcp_message_create(pool);
        request_message->start_line.message_type = MRCP_MESSAGE_TYPE_REQUEST;
+       request_message->start_line.version = version;
        request_message->start_line.method_id = method_id;
-       request_message->channel_id.resource_id = resource_id;
+       mrcp_message_resource_set_by_id(request_message,resource);
        return request_message;
 }
 
@@ -643,12 +304,16 @@ MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(mrcp_resource_id resource_id,
 MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool)
 {
        mrcp_message_t *response_message = mrcp_message_create(pool);
-       if(request_message) {
-               mrcp_message_init_by_request(response_message,request_message);
-       }
        response_message->start_line.message_type = MRCP_MESSAGE_TYPE_RESPONSE;
        response_message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
        response_message->start_line.status_code = MRCP_STATUS_CODE_SUCCESS;
+       if(request_message) {
+               response_message->channel_id = request_message->channel_id;
+               response_message->start_line.request_id = request_message->start_line.request_id;
+               response_message->start_line.version = request_message->start_line.version;
+               response_message->start_line.method_id = request_message->start_line.method_id;
+               mrcp_message_resource_set_by_id(response_message,request_message->resource);
+       }
        return response_message;
 }
 
@@ -656,11 +321,14 @@ MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request
 MRCP_DECLARE(mrcp_message_t*) mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool)
 {
        mrcp_message_t *event_message = mrcp_message_create(pool);
-       if(request_message) {
-               mrcp_message_init_by_request(event_message,request_message);
-       }
        event_message->start_line.message_type = MRCP_MESSAGE_TYPE_EVENT;
        event_message->start_line.method_id = event_id;
+       if(request_message) {
+               event_message->channel_id = request_message->channel_id;
+               event_message->start_line.request_id = request_message->start_line.request_id;
+               event_message->start_line.version = request_message->start_line.version;
+               mrcp_message_resource_set_by_id(event_message,request_message->resource);
+       }
        return event_message;
 }
 
diff --git a/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c b/libs/unimrcp/libs/mrcp/message/src/mrcp_start_line.c
new file mode 100644 (file)
index 0000000..0e7e7a9
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include "mrcp_start_line.h"
+#include "apt_string_table.h"
+#include "apt_log.h"
+
+/** Protocol name used in version string */
+#define MRCP_NAME               "MRCP"
+#define MRCP_NAME_LENGTH        (sizeof(MRCP_NAME)-1)
+
+/** Separators used in MRCP version string parse/generate */
+#define MRCP_NAME_VERSION_SEPARATOR        '/'
+#define MRCP_VERSION_MAJOR_MINOR_SEPARATOR '.'
+
+/** Max number of digits message length consists of */
+#define MAX_DIGIT_COUNT 6
+
+
+/** String table of MRCP request-states (mrcp_request_state_t) */
+static const apt_str_table_item_t mrcp_request_state_string_table[] = {
+       {{"COMPLETE",    8},0},
+       {{"IN-PROGRESS",11},0},
+       {{"PENDING",     7},0}
+};
+
+
+/** Parse MRCP version */
+static mrcp_version_e mrcp_version_parse(const apt_str_t *field)
+{
+       mrcp_version_e version = MRCP_VERSION_UNKNOWN;
+       const char *pos;
+       if(field->length <= MRCP_NAME_LENGTH || strncasecmp(field->buf,MRCP_NAME,MRCP_NAME_LENGTH) != 0) {
+               /* unexpected protocol name */
+               return version;
+       }
+
+       pos = field->buf + MRCP_NAME_LENGTH;
+       if(*pos == MRCP_NAME_VERSION_SEPARATOR) {
+               pos++;
+               switch(*pos) {
+                       case '1': version = MRCP_VERSION_1; break;
+                       case '2': version = MRCP_VERSION_2; break;
+                       default: ;
+               }
+       }
+       return version;
+}
+
+/** Generate MRCP version */
+static apt_bool_t mrcp_version_generate(mrcp_version_e version, apt_text_stream_t *stream)
+{
+       memcpy(stream->pos,MRCP_NAME,MRCP_NAME_LENGTH);
+       stream->pos += MRCP_NAME_LENGTH;
+       *stream->pos++ = MRCP_NAME_VERSION_SEPARATOR;
+       apt_size_value_generate(version,stream);
+       *stream->pos++ = MRCP_VERSION_MAJOR_MINOR_SEPARATOR;
+       *stream->pos++ = '0';
+       return TRUE;
+}
+
+/** Parse MRCP request-state used in MRCP response and event */
+static APR_INLINE mrcp_request_state_e mrcp_request_state_parse(const apt_str_t *request_state_str)
+{
+       return apt_string_table_id_find(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state_str);
+}
+
+/** Generate MRCP request-state used in MRCP response and event */
+static apt_bool_t mrcp_request_state_generate(mrcp_request_state_e request_state, apt_text_stream_t *stream)
+{
+       const apt_str_t *name;
+       name = apt_string_table_str_get(mrcp_request_state_string_table,MRCP_REQUEST_STATE_COUNT,request_state);
+       if(request_state < MRCP_REQUEST_STATE_COUNT) {
+               memcpy(stream->pos,name->buf,name->length);
+               stream->pos += name->length;
+       }
+       return TRUE;
+}
+
+
+/** Parse MRCP status-code */
+static APR_INLINE mrcp_status_code_e mrcp_status_code_parse(const apt_str_t *field)
+{
+       return apt_size_value_parse(field);
+}
+
+/** Generate MRCP status-code */
+static APR_INLINE size_t  mrcp_status_code_generate(mrcp_status_code_e status_code, apt_text_stream_t *stream)
+{
+       return apt_size_value_generate(status_code,stream);
+}
+
+
+/** Parse MRCP request-line */
+static apt_bool_t mrcp_request_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       apt_str_t field;
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in request-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
+               return FALSE;
+       }
+
+       start_line->request_state = mrcp_request_state_parse(&field);
+       if(start_line->request_state == MRCP_REQUEST_STATE_UNKNOWN) {
+               /* request-line */
+               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
+       }
+       else {
+               /* event line */
+               start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse mrcp-version in request-line");
+                       return FALSE;
+               }
+       }
+
+       start_line->version = mrcp_version_parse(&field);
+       if(start_line->version == MRCP_VERSION_UNKNOWN) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown mrcp-version");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/** Generate MRCP request-line */
+static apt_bool_t mrcp_request_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
+       stream->pos += start_line->method_name.length;
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_id_generate(start_line->request_id,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       if(start_line->message_type == MRCP_MESSAGE_TYPE_REQUEST) {
+               if(start_line->status_code != MRCP_STATUS_CODE_UNKNOWN) {
+                       mrcp_status_code_generate(start_line->status_code,stream);
+                       *stream->pos++ = APT_TOKEN_SP;
+               }
+       }
+       else if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
+               mrcp_request_state_generate(start_line->request_state,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+       }
+
+       mrcp_version_generate(start_line->version,stream);
+       return TRUE;
+}
+
+/** Parse MRCP response-line */
+static apt_bool_t mrcp_response_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       apt_str_t field;
+       start_line->length = 0;
+       if(start_line->version == MRCP_VERSION_2) {
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in response-line");
+                       return FALSE;
+               }
+               start_line->length = apt_size_value_parse(&field);
+       }
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in response-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in response-line");
+               return FALSE;
+       }
+       start_line->status_code = mrcp_status_code_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in response-line");
+               return FALSE;
+       }
+       start_line->request_state = mrcp_request_state_parse(&field);
+       return TRUE;
+}
+
+/** Generate MRCP response-line */
+static apt_bool_t mrcp_response_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       mrcp_version_generate(start_line->version,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_id_generate(start_line->request_id,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_status_code_generate(start_line->status_code,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       mrcp_request_state_generate(start_line->request_state,stream);
+       return TRUE;
+}
+
+/** Parse MRCP v2 start-line */
+static apt_bool_t mrcp_v2_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream, apr_pool_t *pool)
+{
+       apt_str_t field;
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in v2 start-line");
+               return FALSE;
+       }
+       start_line->length = apt_size_value_parse(&field);
+
+       if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
+               return FALSE;
+       }
+       start_line->request_id = mrcp_request_id_parse(&field);
+       if(start_line->request_id == 0 && *field.buf != '0') {
+               /* parsing MRCP v2 request or event */
+               start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
+               apt_string_copy(&start_line->method_name,&field,pool);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
+                       return FALSE;
+               }
+               start_line->request_id = mrcp_request_id_parse(&field);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == TRUE) {
+                       /* parsing MRCP v2 event */
+                       start_line->request_state = mrcp_request_state_parse(&field);
+                       start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
+               }
+       }
+       else {
+               /* parsing MRCP v2 response */
+               start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in v2 start-line");
+                       return FALSE;
+               }
+               start_line->status_code = mrcp_status_code_parse(&field);
+
+               if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in v2 start-line");
+                       return FALSE;
+               }
+               start_line->request_state = mrcp_request_state_parse(&field);
+       }
+
+       return TRUE;
+}
+
+/** Generate MRCP v2 start-line */
+static apt_bool_t mrcp_v2_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *stream)
+{
+       char *pos = stream->pos;
+       mrcp_version_generate(start_line->version,stream);
+       *stream->pos++ = APT_TOKEN_SP;
+
+       start_line->length = stream->pos - pos; /* length is temporary used to store offset */
+       /* reserving MAX_DIGIT_COUNT space for start_line->length */
+       memset(stream->pos,APT_TOKEN_SP,MAX_DIGIT_COUNT+1);
+       stream->pos += MAX_DIGIT_COUNT+1;
+
+       if(start_line->message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
+               mrcp_request_id_generate(start_line->request_id,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_status_code_generate(start_line->status_code,stream);
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_request_state_generate(start_line->request_state,stream);
+       }
+       else {
+               memcpy(stream->pos,start_line->method_name.buf,start_line->method_name.length);
+               stream->pos += start_line->method_name.length;
+               *stream->pos++ = APT_TOKEN_SP;
+
+               mrcp_request_id_generate(start_line->request_id,stream);
+               if(start_line->message_type == MRCP_MESSAGE_TYPE_EVENT) {
+                       *stream->pos++ = APT_TOKEN_SP;
+                       mrcp_request_state_generate(start_line->request_state,stream);
+               }
+       }
+       return TRUE;
+}
+
+/** Initialize MRCP start-line */
+MRCP_DECLARE(void) mrcp_start_line_init(mrcp_start_line_t *start_line)
+{
+       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
+       start_line->version = MRCP_VERSION_UNKNOWN;
+       start_line->length = 0;
+       start_line->request_id = 0;
+       apt_string_reset(&start_line->method_name);
+       start_line->status_code = MRCP_STATUS_CODE_UNKNOWN;
+       start_line->request_state = MRCP_REQUEST_STATE_UNKNOWN;
+}
+
+/** Parse MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool)
+{
+       apt_text_stream_t line;
+       apt_str_t field;
+       apt_bool_t status = TRUE;
+       start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
+       if(apt_text_line_read(text_stream,&line.text) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse MRCP start-line");
+               return FALSE;
+       }
+       line.pos = line.text.buf;
+
+       if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot read the first field in start-line");
+               return FALSE;
+       }
+
+       if(field.buf == strstr(field.buf,MRCP_NAME)) {
+               start_line->version = mrcp_version_parse(&field);
+
+               if(start_line->version == MRCP_VERSION_1) {
+                       /* parsing MRCP v1 response */
+                       start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
+                       status = mrcp_response_line_parse(start_line,&line);
+               }
+               else if(start_line->version == MRCP_VERSION_2) {
+                       /* parsing MRCP v2 start-line (request/response/event) */
+                       status = mrcp_v2_start_line_parse(start_line,&line,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown MRCP version");
+                       return FALSE;
+               }
+       }
+       else {
+               /* parsing MRCP v1 request or event */
+               apt_string_copy(&start_line->method_name,&field,pool);
+               status = mrcp_request_line_parse(start_line,&line);
+       }
+       return status;
+}
+
+/** Generate MRCP start-line */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream)
+{
+       apt_bool_t status = FALSE;
+       if(start_line->version == MRCP_VERSION_1) {
+               switch(start_line->message_type) {
+                       case MRCP_MESSAGE_TYPE_REQUEST:
+                               status = mrcp_request_line_generate(start_line,text_stream);
+                               break;
+                       case MRCP_MESSAGE_TYPE_RESPONSE:
+                               status = mrcp_response_line_generate(start_line,text_stream);
+                               break;
+                       case MRCP_MESSAGE_TYPE_EVENT:
+                               status = mrcp_request_line_generate(start_line,text_stream);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       else if(start_line->version == MRCP_VERSION_2) {
+               status = mrcp_v2_start_line_generate(start_line,text_stream);
+       }
+
+       if(status == TRUE) {
+               apt_text_eol_insert(text_stream);
+       }
+       
+       return status;
+}
+
+/** Finalize MRCP start-line generation */
+MRCP_DECLARE(apt_bool_t) mrcp_start_line_finalize(mrcp_start_line_t *start_line, apr_size_t content_length, apt_text_stream_t *text_stream)
+{
+       apr_size_t length = text_stream->pos - text_stream->text.buf + content_length;
+       if(start_line->version == MRCP_VERSION_2) {
+               /* message-length includes the number of bytes that specify the message-length in the header */
+               /* too comlex to generate!!! see the discussion */
+               /* http://www1.ietf.org/mail-archive/web/speechsc/current/msg01734.html */
+               apt_str_t field;
+               field.buf = text_stream->text.buf + start_line->length; /* length is temporary used to store offset */
+               length -= MAX_DIGIT_COUNT;
+               if(apt_var_length_value_generate(&length,MAX_DIGIT_COUNT,&field) == FALSE) {
+                       return FALSE;
+               }
+               field.buf[field.length] = APT_TOKEN_SP;
+               start_line->length += field.length;
+
+               field.length = MAX_DIGIT_COUNT - field.length;
+               if(field.length) {
+                       memmove(text_stream->text.buf+field.length,text_stream->text.buf,start_line->length);
+                       text_stream->text.buf += field.length;
+                       text_stream->text.length -= field.length;
+               }
+       }
+
+       start_line->length = length;
+       return TRUE;
+}
+
+/** Parse MRCP request-id */
+MRCP_DECLARE(mrcp_request_id) mrcp_request_id_parse(const apt_str_t *field)
+{
+       if(field->buf) {
+#ifdef TOO_LONG_MRCP_REQUEST_ID
+               return apr_atoi64(field->buf);
+#else
+               return atol(field->buf);
+#endif
+       }
+       return 0;
+}
+
+/** Generate MRCP request-id */
+MRCP_DECLARE(apt_bool_t) mrcp_request_id_generate(mrcp_request_id request_id, apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos, "%"MRCP_REQUEST_ID_FMT, request_id);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+       return TRUE;
+}
index 514be9360b131245e1d3f89bd966ff5915015d65..9963bbc266ec184d574af4ef07f83b4521e72d54 100644 (file)
                                        RelativePath=".\message\include\mrcp_message.h"
                                        >
                                </File>
+                               <File
+                                       RelativePath=".\message\include\mrcp_start_line.h"
+                                       >
+                               </File>
                        </Filter>
                        <Filter
                                Name="src"
                                        RelativePath=".\message\src\mrcp_message.c"
                                        >
                                </File>
+                               <File
+                                       RelativePath=".\message\src\mrcp_start_line.c"
+                                       >
+                               </File>
                        </Filter>
                </Filter>
                <Filter
                                        >
                                </File>
                                <File
-                                       RelativePath=".\control\include\mrcp_state_machine.h"
+                                       RelativePath=".\control\include\mrcp_resource_loader.h"
                                        >
                                </File>
                                <File
                                        RelativePath=".\control\src\mrcp_resource_factory.c"
                                        >
                                </File>
+                               <File
+                                       RelativePath=".\control\src\mrcp_resource_loader.c"
+                                       >
+                               </File>
                                <File
                                        RelativePath=".\control\src\mrcp_stream.c"
                                        >
                                Name="include"
                                Filter="h;hpp;hxx;hm;inl;inc;xsd"
                                >
-                               <File
-                                       RelativePath=".\resources\include\mrcp_default_factory.h"
-                                       >
-                               </File>
                                <File
                                        RelativePath=".\resources\include\mrcp_recog_header.h"
                                        >
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\include\mrcp_recog_state_machine.h"
+                                       RelativePath=".\resources\include\mrcp_recorder_header.h"
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\include\mrcp_synth_header.h"
+                                       RelativePath=".\resources\include\mrcp_recorder_resource.h"
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\include\mrcp_synth_resource.h"
+                                       RelativePath=".\resources\include\mrcp_synth_header.h"
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\include\mrcp_synth_state_machine.h"
+                                       RelativePath=".\resources\include\mrcp_synth_resource.h"
                                        >
                                </File>
                        </Filter>
                                Name="src"
                                Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
                                >
-                               <File
-                                       RelativePath=".\resources\src\mrcp_default_factory.c"
-                                       >
-                               </File>
-                               <File
-                                       RelativePath=".\resources\src\mrcp_recog_client_state_machine.c"
-                                       >
-                               </File>
                                <File
                                        RelativePath=".\resources\src\mrcp_recog_header.c"
                                        >
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\src\mrcp_recog_server_state_machine.c"
+                                       RelativePath=".\resources\src\mrcp_recorder_header.c"
                                        >
                                </File>
                                <File
-                                       RelativePath=".\resources\src\mrcp_synth_client_state_machine.c"
+                                       RelativePath=".\resources\src\mrcp_recorder_resource.c"
                                        >
                                </File>
                                <File
                                        RelativePath=".\resources\src\mrcp_synth_resource.c"
                                        >
                                </File>
-                               <File
-                                       RelativePath=".\resources\src\mrcp_synth_server_state_machine.c"
-                                       >
-                               </File>
                        </Filter>
                </Filter>
        </Files>
index 1669147e50348f58e9dfbd0ffd31ba84587419dd..4b2192b399e30d2a0e0ca878a2176e4584c790f7 100644 (file)
@@ -206,7 +206,7 @@ struct mrcp_recog_header_t {
 
 
 /** Get recognizer header vtable */
-MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_recog_header_vtable_get(mrcp_version_e version);
+const mrcp_header_vtable_t* mrcp_recog_header_vtable_get(mrcp_version_e version);
 
 /** Get recognizer completion cause string */
 MRCP_DECLARE(const apt_str_t*) mrcp_recog_completion_cause_get(mrcp_recog_completion_cause_e completion_cause, mrcp_version_e version);
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_header.h
new file mode 100644 (file)
index 0000000..af17723
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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 __MRCP_RECORDER_HEADER_H__
+#define __MRCP_RECORDER_HEADER_H__
+
+/**
+ * @file mrcp_recorder_header.h
+ * @brief MRCP Recorder Header
+ */ 
+
+#include "mrcp_types.h"
+#include "mrcp_header_accessor.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP recorder header fields */
+typedef enum {
+       RECORDER_HEADER_SENSITIVITY_LEVEL,
+       RECORDER_HEADER_NO_INPUT_TIMEOUT,
+       RECORDER_HEADER_COMPLETION_CAUSE,
+       RECORDER_HEADER_COMPLETION_REASON,
+       RECORDER_HEADER_FAILED_URI,
+       RECORDER_HEADER_FAILED_URI_CAUSE,
+       RECORDER_HEADER_RECORD_URI,
+       RECORDER_HEADER_MEDIA_TYPE,
+       RECORDER_HEADER_MAX_TIME,
+       RECORDER_HEADER_TRIM_LENGTH,
+       RECORDER_HEADER_FINAL_SILENCE,
+       RECORDER_HEADER_CAPTURE_ON_SPEECH,
+       RECORDER_HEADER_VER_BUFFER_UTTERANCE,
+       RECORDER_HEADER_START_INPUT_TIMERS,
+       RECORDER_HEADER_NEW_AUDIO_CHANNEL,
+
+       RECORDER_HEADER_COUNT
+} mrcp_recorder_header_id;
+
+
+/** MRCP recorder completion-cause  */
+typedef enum {
+       RECORDER_COMPLETION_CAUSE_SUCCESS_SILENCE         = 0,
+       RECORDER_COMPLETION_CAUSE_SUCCESS_MAXTIME         = 1,
+       RECORDER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT        = 2,
+       RECORDER_COMPLETION_CAUSE_URI_FAILURE             = 3,
+       RECORDER_COMPLETION_CAUSE_ERROR                   = 4,
+
+       RECORDER_COMPLETION_CAUSE_COUNT                   = 5,
+       RECORDER_COMPLETION_CAUSE_UNKNOWN                 = RECORDER_COMPLETION_CAUSE_COUNT
+} mrcp_recorder_completion_cause_e;
+
+
+
+/** MRCP recorder-header declaration */
+typedef struct mrcp_recorder_header_t mrcp_recorder_header_t;
+
+/** MRCP recorder-header */
+struct mrcp_recorder_header_t {
+       /** To filter out background noise and not mistake it for speech */
+       float                            sensitivity_level;
+       /** When recording is started and there is no speech detected for a
+       certain period of time, the recorder can send a RECORD-COMPLETE event */
+       apr_size_t                       no_input_timeout;
+       /** MUST be part of a RECORD-COMPLETE event coming from the 
+       recorder resource to the client */
+       mrcp_recorder_completion_cause_e completion_cause;
+       /** MAY be specified in a RECORD-COMPLETE event coming from
+       the recorder resource to the client */
+       apt_str_t                        completion_reason;
+       /** When a recorder method needs to post the audio to a URI and access to
+       the URI fails, the server MUST provide the failed URI in this header
+       in the method response */
+       apt_str_t                        failed_uri;
+       /** When a recorder method needs to post the audio to a URI and access to
+       the URI fails, the server MUST provide the URI specific or protocol
+       specific response code through this header in the method response */
+       apt_str_t                        failed_uri_cause;
+       /** When a recorder method contains this header the server must capture
+       the audio and store it */
+       apt_str_t                        record_uri;
+       /** A RECORD method MUST contain this header, which specifies to the
+       server the Media Type of the captured audio or video */
+       apt_str_t                        media_type;
+       /** When recording is started this specifies the maximum length of the
+       recording in milliseconds, calculated from the time the actual
+       capture and store begins and is not necessarily the time the RECORD
+       method is received */
+       apr_size_t                       max_time;
+       /** This header MAY be sent on a STOP method and specifies the length of
+       audio to be trimmed from the end of the recording after the stop */
+       apr_size_t                       trim_length;
+       /**  When recorder is started and the actual capture begins, this header
+       specifies the length of silence in the audio that is to be
+       interpreted as the end of the recording*/
+       apr_size_t                       final_silence;
+       /** f false, the recorder MUST start capturing immediately when started.
+       If true, the recorder MUST wait for the endpointing functionality to
+       detect speech before it starts capturing */
+       apt_bool_t                       capture_on_speech;
+       /** Tells the server to buffer the utterance associated with this 
+       recording request into the verification buffer */
+       apt_bool_t                       ver_buffer_utterance;
+       /** MAY be sent as part of the RECORD request. A value of false tells the 
+       recorder resource to start the operation, but not to start the no-input 
+       timer until the client sends a START-INPUT-TIMERS */
+       apt_bool_t                       start_input_timers;
+       /** MAY be specified in a RECORD request and allows the
+       client to tell the server that, from this point on, further input
+       audio comes from a different audio source */
+       apt_bool_t                       new_audio_channel;
+};
+
+
+/** Get recorder header vtable */
+const mrcp_header_vtable_t* mrcp_recorder_header_vtable_get(mrcp_version_e version);
+
+/** Get recorder completion cause string */
+MRCP_DECLARE(const apt_str_t*) mrcp_recorder_completion_cause_get(
+                                                                       mrcp_recorder_completion_cause_e completion_cause, 
+                                                                       mrcp_version_e version);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RECORDER_HEADER_H__*/
diff --git a/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h b/libs/unimrcp/libs/mrcp/resources/include/mrcp_recorder_resource.h
new file mode 100644 (file)
index 0000000..b9afa34
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 __MRCP_RECORDER_RESOURCE_H__
+#define __MRCP_RECORDER_RESOURCE_H__
+
+/**
+ * @file mrcp_recorder_resource.h
+ * @brief MRCP Recorder Resource
+ */ 
+
+#include "mrcp_types.h"
+
+APT_BEGIN_EXTERN_C
+
+/** MRCP recorder methods */
+typedef enum {
+       RECORDER_SET_PARAMS,
+       RECORDER_GET_PARAMS,
+       RECORDER_RECORD,
+       RECORDER_STOP,
+       RECORDER_START_INPUT_TIMERS,
+
+       RECORDER_METHOD_COUNT
+} mrcp_recorder_method_id;
+
+/** MRCP recorder events */
+typedef enum {
+       RECORDER_START_OF_INPUT,
+       RECORDER_RECORD_COMPLETE,
+
+       RECORDER_EVENT_COUNT
+} mrcp_recorder_event_id;
+
+/** Create MRCP recorder resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_recorder_resource_create(apr_pool_t *pool);
+
+APT_END_EXTERN_C
+
+#endif /*__MRCP_RECORDER_RESOURCE_H__*/
index f0bf60c9f6f878b9301ca86155977d1972431643..359af6bd593b2ab698bb7f179f17815e57c2b726 100644 (file)
@@ -291,7 +291,7 @@ struct mrcp_synth_header_t {
 };
 
 /** Get synthesizer header vtable */
-MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_synth_header_vtable_get(mrcp_version_e version);
+const mrcp_header_vtable_t* mrcp_synth_header_vtable_get(mrcp_version_e version);
 
 /** Get synthesizer completion cause string */
 MRCP_DECLARE(const apt_str_t*) mrcp_synth_completion_cause_get(mrcp_synth_completion_cause_e completion_cause, mrcp_version_e version);
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_default_factory.c
deleted file mode 100644 (file)
index d34ba99..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 "mrcp_default_factory.h"
-#include "mrcp_synth_resource.h"
-#include "mrcp_recog_resource.h"
-#include "apt_log.h"
-
-/** String table of MRCPv2 resources (mrcp_resource_types_e) */
-static const apt_str_table_item_t mrcp_resource_string_table[] = {
-       {{"speechsynth",11},6},
-       {{"speechrecog",11},6}
-};
-
-/** Create default MRCP resource factory */
-MRCP_DECLARE(mrcp_resource_factory_t*) mrcp_default_factory_create(apr_pool_t *pool)
-{
-       mrcp_resource_t *resource;
-       mrcp_resource_factory_t *resource_factory;
-       /* create resource factory instance */
-       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCP Resource Factory [%d]",MRCP_RESOURCE_TYPE_COUNT);
-       resource_factory = mrcp_resource_factory_create(MRCP_RESOURCE_TYPE_COUNT,pool);
-       if(!resource_factory) {
-               return NULL;
-       }
-       
-       /* set resource string table */
-       mrcp_resource_string_table_set(resource_factory,mrcp_resource_string_table);
-
-       /* create and register resources */
-       resource = mrcp_synth_resource_create(pool);
-       if(resource) {
-               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Synthesizer Resource");
-               mrcp_resource_register(resource_factory,resource,MRCP_SYNTHESIZER_RESOURCE);
-       }
-       
-       resource = mrcp_recog_resource_create(pool);
-       if(resource) {
-               apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Register Recognizer Resource");
-               mrcp_resource_register(resource_factory,resource,MRCP_RECOGNIZER_RESOURCE);
-       }
-
-       return resource_factory;
-}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recog_client_state_machine.c
deleted file mode 100644 (file)
index 358f5ee..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 "mrcp_state_machine.h"
-#include "mrcp_recog_state_machine.h"
-#include "mrcp_message.h"
-
-
-/** Update state according to request received from user level or response/event received from MRCP server */
-static apt_bool_t recog_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
-{
-       /* no actual state machine processing yet, dispatch whatever received */
-       return state_machine->on_dispatch(state_machine,message);
-}
-
-/** Create MRCP recognizer client state machine */
-mrcp_state_machine_t* mrcp_recog_client_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
-{
-       mrcp_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_state_machine_t));
-       mrcp_state_machine_init(state_machine,obj);
-       state_machine->update = recog_state_update;
-       return state_machine;
-}
index 1d1a997014b1e5f38e98f003afeeac9f26b22f24..4a4076faf33404e77e339b5d8b16720f4139d265 100644 (file)
@@ -638,7 +638,7 @@ static const mrcp_header_vtable_t v2_vtable = {
        RECOGNIZER_HEADER_COUNT
 };
 
-MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_recog_header_vtable_get(mrcp_version_e version)
+const mrcp_header_vtable_t* mrcp_recog_header_vtable_get(mrcp_version_e version)
 {
        if(version == MRCP_VERSION_1) {
                return &v1_vtable;
index 819b8b09a61b9dc0eee0b5cb4a3a7a84cfe1273f..bf9dc56f3aa1e9b8a5ee8aaf33bbef0a1f2715e7 100644 (file)
@@ -16,9 +16,7 @@
 
 #include "mrcp_recog_resource.h"
 #include "mrcp_recog_header.h"
-#include "mrcp_recog_state_machine.h"
 #include "mrcp_resource.h"
-#include "mrcp_message.h"
 
 /** String table of MRCP recognizer methods (mrcp_recognizer_method_id) */
 static const apt_str_table_item_t v1_recog_method_string_table[] = {
@@ -71,73 +69,15 @@ static APR_INLINE const apt_str_table_item_t* recog_event_string_table_get(mrcp_
        return v2_recog_event_string_table;
 }
 
-/** Set resource specifica data */
-static apt_bool_t recog_message_resourcify_by_id(mrcp_resource_t *resource, mrcp_message_t *message)
-{
-       /* associate method_name and method_id */
-       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               const apt_str_t *name = apt_string_table_str_get(
-                       recog_method_string_table_get(message->start_line.version),
-                       RECOGNIZER_METHOD_COUNT,
-                       message->start_line.method_id);
-               if(!name) {
-                       return FALSE;
-               }
-               message->start_line.method_name = *name;
-       }
-       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
-               const apt_str_t *name = apt_string_table_str_get(
-                       recog_event_string_table_get(message->start_line.version),
-                       RECOGNIZER_EVENT_COUNT,
-                       message->start_line.method_id);
-               if(!name) {
-                       return FALSE;
-               }
-               message->start_line.method_name = *name;
-       }
-
-       message->header.resource_header_accessor.vtable = mrcp_recog_header_vtable_get(message->start_line.version);
-       return TRUE;
-}
-
-/** Set resource specifica data */
-static apt_bool_t recog_message_resourcify_by_name(mrcp_resource_t *resource, mrcp_message_t *message)
-{
-       /* associate method_name and method_id */
-       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               message->start_line.method_id = apt_string_table_id_find(
-                       recog_method_string_table_get(message->start_line.version),
-                       RECOGNIZER_METHOD_COUNT,
-                       &message->start_line.method_name);
-               if(message->start_line.method_id >= RECOGNIZER_METHOD_COUNT) {
-                       return FALSE;
-               }
-       }
-       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
-               message->start_line.method_id = apt_string_table_id_find(
-                       recog_event_string_table_get(message->start_line.version),
-                       RECOGNIZER_EVENT_COUNT,
-                       &message->start_line.method_name);
-               if(message->start_line.method_id >= RECOGNIZER_EVENT_COUNT) {
-                       return FALSE;
-               }
-       }
-
-       message->header.resource_header_accessor.vtable = mrcp_recog_header_vtable_get(message->start_line.version);
-       return TRUE;
-}
-
-
 /** Create MRCP recognizer resource */
 MRCP_DECLARE(mrcp_resource_t*) mrcp_recog_resource_create(apr_pool_t *pool)
 {
-       mrcp_resource_t *resource = apr_palloc(pool,sizeof(mrcp_resource_t));
-       mrcp_resource_init(resource);
-
-       resource->resourcify_message_by_id = recog_message_resourcify_by_id;
-       resource->resourcify_message_by_name = recog_message_resourcify_by_name;
+       mrcp_resource_t *resource = mrcp_resource_create(pool);
 
-       resource->create_client_state_machine = mrcp_recog_client_state_machine_create;
-       resource->create_server_state_machine = mrcp_recog_server_state_machine_create;
+       resource->method_count = RECOGNIZER_METHOD_COUNT;
+       resource->event_count = RECOGNIZER_EVENT_COUNT;
+       resource->get_method_str_table = recog_method_string_table_get;
+       resource->get_event_str_table = recog_event_string_table_get;
+       resource->get_resource_header_vtable = mrcp_recog_header_vtable_get;
        return resource;
 }
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_header.c
new file mode 100644 (file)
index 0000000..1b51da8
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * 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 <stdio.h>
+#include "mrcp_recorder_header.h"
+
+/** String table of recorder headers (mrcp_recorder_header_id) */
+static const apt_str_table_item_t recorder_header_string_table[] = {
+       {{"Sensitivity-Level",    17},3},
+       {{"No-Input-Timeout",     16},2},
+       {{"Completion-Cause",     16},16},
+       {{"Completion-Reason",    17},11},
+       {{"Failed-Uri",           10},10},
+       {{"Failed-Uri-Cause",     16},16},
+       {{"Record-Uri",           10},0},
+       {{"Media-Type",           10},2},
+       {{"Max-Time",              8},2},
+       {{"Trim-Length",          11},0},
+       {{"Final-Silence",        13},1},
+       {{"Capture-On-Speech",    17},2},
+       {{"Ver-Buffer-Utterance", 20},0},
+       {{"Start-Input-Timers",   18},1},
+       {{"New-Audio-Channel",    17},2}
+};
+
+/** String table of recorder completion-cause fields (mrcp_recorder_completion_cause_e) */
+static const apt_str_table_item_t completion_cause_string_table[] = {
+       {{"success-silence",  15},8},
+       {{"success-maxtime",  15},8},
+       {{"no-input-timeout", 16},0},
+       {{"uri-failure",      11},0},
+       {{"error",             5},0}
+};
+
+/** Generate MRCP recorder completion-cause */
+static apt_bool_t mrcp_completion_cause_generate(
+                                               mrcp_recorder_completion_cause_e completion_cause, 
+                                               const apt_str_t *name, 
+                                               apt_text_stream_t *stream)
+{
+       int length = sprintf(stream->pos,"%03"APR_SIZE_T_FMT" ",completion_cause);
+       if(length <= 0) {
+               return FALSE;
+       }
+       stream->pos += length;
+
+       if(name) {
+               memcpy(stream->pos,name->buf,name->length);
+               stream->pos += name->length;
+       }
+       return TRUE;
+}
+
+
+/** Initialize recorder header */
+static void mrcp_recorder_header_init(mrcp_recorder_header_t *recorder_header)
+{
+       recorder_header->sensitivity_level = 0.0;
+       recorder_header->no_input_timeout = 0;
+       recorder_header->completion_cause = RECORDER_COMPLETION_CAUSE_COUNT;
+       apt_string_reset(&recorder_header->completion_reason);
+       apt_string_reset(&recorder_header->failed_uri);
+       apt_string_reset(&recorder_header->failed_uri_cause);
+       apt_string_reset(&recorder_header->record_uri);
+       apt_string_reset(&recorder_header->media_type);
+       recorder_header->max_time = 0;
+       recorder_header->trim_length = 0;
+       recorder_header->final_silence = 0;
+       recorder_header->capture_on_speech = FALSE;
+       recorder_header->ver_buffer_utterance = FALSE;
+       recorder_header->start_input_timers = FALSE;
+       recorder_header->new_audio_channel = FALSE;
+}
+
+/** Allocate MRCP recorder header */
+static void* mrcp_recorder_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
+{
+       mrcp_recorder_header_t *recorder_header = apr_palloc(pool,sizeof(mrcp_recorder_header_t));
+       mrcp_recorder_header_init(recorder_header);
+       accessor->data = recorder_header;
+       return accessor->data;
+}
+
+/** Parse MRCP recorder header */
+static apt_bool_t mrcp_recorder_header_parse(mrcp_header_accessor_t *accessor, apr_size_t id, const apt_str_t *value, apr_pool_t *pool)
+{
+       apt_bool_t status = TRUE;
+       mrcp_recorder_header_t *recorder_header = accessor->data;
+       switch(id) {
+               case RECORDER_HEADER_SENSITIVITY_LEVEL:
+                       recorder_header->sensitivity_level = apt_float_value_parse(value);
+                       break;
+               case RECORDER_HEADER_NO_INPUT_TIMEOUT:
+                       recorder_header->no_input_timeout = apt_size_value_parse(value);
+                       break;
+               case RECORDER_HEADER_COMPLETION_CAUSE:
+                       recorder_header->completion_cause = apt_size_value_parse(value);
+                       break;
+               case RECORDER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&recorder_header->completion_reason,value,pool);
+                       break;
+               case RECORDER_HEADER_FAILED_URI:
+                       apt_string_copy(&recorder_header->failed_uri,value,pool);
+                       break;
+               case RECORDER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&recorder_header->failed_uri_cause,value,pool);
+                       break;
+               case RECORDER_HEADER_RECORD_URI:
+                       apt_string_copy(&recorder_header->record_uri,value,pool);
+                       break;
+               case RECORDER_HEADER_MEDIA_TYPE:
+                       apt_string_copy(&recorder_header->media_type,value,pool);
+                       break;
+               case RECORDER_HEADER_MAX_TIME:
+                       recorder_header->max_time = apt_size_value_parse(value);
+                       break;
+               case RECORDER_HEADER_TRIM_LENGTH:
+                       recorder_header->trim_length = apt_size_value_parse(value);
+                       break;
+               case RECORDER_HEADER_FINAL_SILENCE:
+                       recorder_header->final_silence = apt_size_value_parse(value);
+                       break;
+               case RECORDER_HEADER_CAPTURE_ON_SPEECH:
+                       apt_boolean_value_parse(value,&recorder_header->capture_on_speech);
+                       break;
+               case RECORDER_HEADER_VER_BUFFER_UTTERANCE:
+                       apt_boolean_value_parse(value,&recorder_header->ver_buffer_utterance);
+                       break;
+               case RECORDER_HEADER_START_INPUT_TIMERS:
+                       apt_boolean_value_parse(value,&recorder_header->start_input_timers);
+                       break;
+               case RECORDER_HEADER_NEW_AUDIO_CHANNEL:
+                       apt_boolean_value_parse(value,&recorder_header->new_audio_channel);
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+/** Generate MRCP recorder header */
+static apt_bool_t mrcp_recorder_header_generate(mrcp_header_accessor_t *accessor, apr_size_t id, apt_text_stream_t *value)
+{
+       mrcp_recorder_header_t *recorder_header = accessor->data;
+       switch(id) {
+               case RECORDER_HEADER_SENSITIVITY_LEVEL:
+                       apt_float_value_generate(recorder_header->sensitivity_level,value);
+                       break;
+               case RECORDER_HEADER_NO_INPUT_TIMEOUT:
+                       apt_size_value_generate(recorder_header->no_input_timeout,value);
+                       break;
+               case RECORDER_HEADER_COMPLETION_CAUSE:
+               {
+                       const apt_str_t *name = apt_string_table_str_get(
+                               completion_cause_string_table,
+                               RECORDER_COMPLETION_CAUSE_COUNT,
+                               recorder_header->completion_cause);
+                       mrcp_completion_cause_generate(recorder_header->completion_cause,name,value);
+                       break;
+               }
+               case RECORDER_HEADER_COMPLETION_REASON:
+                       apt_string_value_generate(&recorder_header->completion_reason,value);
+                       break;
+               case RECORDER_HEADER_FAILED_URI:
+                       apt_string_value_generate(&recorder_header->failed_uri,value);
+                       break;
+               case RECORDER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_value_generate(&recorder_header->failed_uri_cause,value);
+                       break;
+               case RECORDER_HEADER_RECORD_URI:
+                       apt_string_value_generate(&recorder_header->record_uri,value);
+                       break;
+               case RECORDER_HEADER_MEDIA_TYPE:
+                       apt_string_value_generate(&recorder_header->media_type,value);
+                       break;
+               case RECORDER_HEADER_MAX_TIME:
+                       apt_size_value_generate(recorder_header->max_time,value);
+                       break;
+               case RECORDER_HEADER_TRIM_LENGTH:
+                       apt_size_value_generate(recorder_header->trim_length,value);
+                       break;
+               case RECORDER_HEADER_FINAL_SILENCE:
+                       apt_size_value_generate(recorder_header->final_silence,value);
+                       break;
+               case RECORDER_HEADER_CAPTURE_ON_SPEECH:
+                       apt_boolean_value_generate(recorder_header->capture_on_speech,value);
+                       break;
+               case RECORDER_HEADER_VER_BUFFER_UTTERANCE:
+                       apt_boolean_value_generate(recorder_header->ver_buffer_utterance,value);
+                       break;
+               case RECORDER_HEADER_START_INPUT_TIMERS:
+                       apt_boolean_value_generate(recorder_header->start_input_timers,value);
+                       break;
+               case RECORDER_HEADER_NEW_AUDIO_CHANNEL:
+                       apt_boolean_value_generate(recorder_header->new_audio_channel,value);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
+/** Duplicate MRCP recorder header */
+static apt_bool_t mrcp_recorder_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, apr_pool_t *pool)
+{
+       mrcp_recorder_header_t *recorder_header = accessor->data;
+       const mrcp_recorder_header_t *src_recorder_header = src->data;
+       apt_bool_t status = TRUE;
+
+       if(!recorder_header || !src_recorder_header) {
+               return FALSE;
+       }
+       
+       switch(id) {
+               case RECORDER_HEADER_SENSITIVITY_LEVEL:
+                       recorder_header->sensitivity_level = src_recorder_header->sensitivity_level;
+                       break;
+               case RECORDER_HEADER_NO_INPUT_TIMEOUT:
+                       recorder_header->no_input_timeout = src_recorder_header->no_input_timeout;
+                       break;
+               case RECORDER_HEADER_COMPLETION_CAUSE:
+                       recorder_header->completion_cause = src_recorder_header->completion_cause;
+                       break;
+               case RECORDER_HEADER_COMPLETION_REASON:
+                       apt_string_copy(&recorder_header->completion_reason,&src_recorder_header->completion_reason,pool);
+                       break;
+               case RECORDER_HEADER_FAILED_URI:
+                       apt_string_copy(&recorder_header->failed_uri,&src_recorder_header->failed_uri,pool);
+                       break;
+               case RECORDER_HEADER_FAILED_URI_CAUSE:
+                       apt_string_copy(&recorder_header->failed_uri_cause,&src_recorder_header->failed_uri_cause,pool);
+                       break;
+               case RECORDER_HEADER_RECORD_URI:
+                       apt_string_copy(&recorder_header->record_uri,&src_recorder_header->record_uri,pool);
+                       break;
+               case RECORDER_HEADER_MEDIA_TYPE:
+                       apt_string_copy(&recorder_header->media_type,&src_recorder_header->media_type,pool);
+                       break;
+               case RECORDER_HEADER_MAX_TIME:
+                       recorder_header->max_time = src_recorder_header->max_time;
+                       break;
+               case RECORDER_HEADER_TRIM_LENGTH:
+                       recorder_header->trim_length = src_recorder_header->trim_length;
+                       break;
+               case RECORDER_HEADER_FINAL_SILENCE:
+                       recorder_header->final_silence = src_recorder_header->final_silence;
+                       break;
+               case RECORDER_HEADER_CAPTURE_ON_SPEECH:
+                       recorder_header->capture_on_speech = src_recorder_header->capture_on_speech;
+                       break;
+               case RECORDER_HEADER_VER_BUFFER_UTTERANCE:
+                       recorder_header->ver_buffer_utterance = src_recorder_header->ver_buffer_utterance;
+                       break;
+               case RECORDER_HEADER_START_INPUT_TIMERS:
+                       recorder_header->start_input_timers = src_recorder_header->start_input_timers;
+                       break;
+               case RECORDER_HEADER_NEW_AUDIO_CHANNEL:
+                       recorder_header->new_audio_channel = src_recorder_header->new_audio_channel;
+                       break;
+               default:
+                       status = FALSE;
+       }
+       return status;
+}
+
+static const mrcp_header_vtable_t vtable = {
+       mrcp_recorder_header_allocate,
+       NULL, /* nothing to destroy */
+       mrcp_recorder_header_parse,
+       mrcp_recorder_header_generate,
+       mrcp_recorder_header_duplicate,
+       recorder_header_string_table,
+       RECORDER_HEADER_COUNT
+};
+
+const mrcp_header_vtable_t* mrcp_recorder_header_vtable_get(mrcp_version_e version)
+{
+       return &vtable;
+}
+
+MRCP_DECLARE(const apt_str_t*) mrcp_recorder_completion_cause_get(
+                                                                       mrcp_recorder_completion_cause_e completion_cause, 
+                                                                       mrcp_version_e version)
+{
+       return apt_string_table_str_get(completion_cause_string_table,RECORDER_COMPLETION_CAUSE_COUNT,completion_cause);
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_recorder_resource.c
new file mode 100644 (file)
index 0000000..edb047c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 "mrcp_recorder_resource.h"
+#include "mrcp_recorder_header.h"
+#include "mrcp_resource.h"
+
+/** String table of MRCP recorder methods (mrcp_recorder_method_id) */
+static const apt_str_table_item_t recorder_method_string_table[] = {
+       {{"SET-PARAMS",         10},10},
+       {{"GET-PARAMS",         10},0},
+       {{"RECORD",              6},0},
+       {{"STOP",                4},2},
+       {{"START-INPUT-TIMERS", 18},2}
+};
+
+/** String table of MRCP recorder events (mrcp_recorder_event_id) */
+static const apt_str_table_item_t recorder_event_string_table[] = {
+       {{"START-OF-INPUT",     14},0},
+       {{"RECORD-COMPLETE",    15},0}
+};
+
+static APR_INLINE const apt_str_table_item_t* recorder_method_string_table_get(mrcp_version_e version)
+{
+       return recorder_method_string_table;
+}
+
+static APR_INLINE const apt_str_table_item_t* recorder_event_string_table_get(mrcp_version_e version)
+{
+       return recorder_event_string_table;
+}
+
+/** Create MRCP recorder resource */
+MRCP_DECLARE(mrcp_resource_t*) mrcp_recorder_resource_create(apr_pool_t *pool)
+{
+       mrcp_resource_t *resource = mrcp_resource_create(pool);
+
+       resource->method_count = RECORDER_METHOD_COUNT;
+       resource->event_count = RECORDER_EVENT_COUNT;
+       resource->get_method_str_table = recorder_method_string_table_get;
+       resource->get_event_str_table = recorder_event_string_table_get;
+       resource->get_resource_header_vtable = mrcp_recorder_header_vtable_get;
+       return resource;
+}
diff --git a/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c b/libs/unimrcp/libs/mrcp/resources/src/mrcp_synth_client_state_machine.c
deleted file mode 100644 (file)
index b34378d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 "mrcp_state_machine.h"
-#include "mrcp_synth_state_machine.h"
-#include "mrcp_message.h"
-
-
-/** Update state according to request received from user level or response/event received from MRCP server */
-static apt_bool_t synth_state_update(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
-{
-       /* no actual state machine processing yet, dispatch whatever received */
-       return state_machine->on_dispatch(state_machine,message);
-}
-
-/** Create MRCP synthesizer client state machine */
-mrcp_state_machine_t* mrcp_synth_client_state_machine_create(void *obj, mrcp_version_e version, apr_pool_t *pool)
-{
-       mrcp_state_machine_t *state_machine = apr_palloc(pool,sizeof(mrcp_state_machine_t));
-       mrcp_state_machine_init(state_machine,obj);
-       state_machine->update = synth_state_update;
-       return state_machine;
-}
index 0a84904da340e6ef35f33702cb42596c92ea70ee..3a8c804d4d0d8e6721eaf9a587b34136b42d0f9c 100644 (file)
@@ -548,7 +548,7 @@ static const mrcp_header_vtable_t vtable = {
        SYNTHESIZER_HEADER_COUNT
 };
 
-MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_synth_header_vtable_get(mrcp_version_e version)
+const mrcp_header_vtable_t* mrcp_synth_header_vtable_get(mrcp_version_e version)
 {
        return &vtable;
 }
index 9018f49002df983ddf1c8a432e1e247b30970c6a..702af0a6e5b0d7fcfda5ad935be7ff5ba48720c3 100644 (file)
@@ -16,9 +16,7 @@
 
 #include "mrcp_synth_resource.h"
 #include "mrcp_synth_header.h"
-#include "mrcp_synth_state_machine.h"
 #include "mrcp_resource.h"
-#include "mrcp_message.h"
 
 /** String table of MRCP synthesizer methods (mrcp_synthesizer_method_id) */
 static const apt_str_table_item_t synth_method_string_table[] = {
@@ -39,75 +37,25 @@ static const apt_str_table_item_t synth_event_string_table[] = {
        {{"SPEAK-COMPLETE",14},3}
 };
 
-/** Set resource specifica data */
-static apt_bool_t synth_message_resourcify_by_id(mrcp_resource_t *resource, mrcp_message_t *message)
+static APR_INLINE const apt_str_table_item_t* synth_method_string_table_get(mrcp_version_e version)
 {
-       /* associate method_name and method_id */
-       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               const apt_str_t *name = apt_string_table_str_get(
-                       synth_method_string_table,
-                       SYNTHESIZER_METHOD_COUNT,
-                       message->start_line.method_id);
-               if(!name) {
-                       return FALSE;
-               }
-               message->start_line.method_name = *name;
-       }
-       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
-               const apt_str_t *name = apt_string_table_str_get(
-                       synth_event_string_table,
-                       SYNTHESIZER_EVENT_COUNT,
-                       message->start_line.method_id);
-               if(!name) {
-                       return FALSE;
-               }
-               message->start_line.method_name = *name;
-       }
-
-       message->header.resource_header_accessor.vtable = 
-               mrcp_synth_header_vtable_get(message->start_line.version);
-       return TRUE;
+       return synth_method_string_table;
 }
 
-/** Set resource specifica data */
-static apt_bool_t synth_message_resourcify_by_name(mrcp_resource_t *resource, mrcp_message_t *message)
+static APR_INLINE const apt_str_table_item_t* synth_event_string_table_get(mrcp_version_e version)
 {
-       /* associate method_name and method_id */
-       if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
-               message->start_line.method_id = apt_string_table_id_find(
-                       synth_method_string_table,
-                       SYNTHESIZER_METHOD_COUNT,
-                       &message->start_line.method_name);
-               if(message->start_line.method_id >= SYNTHESIZER_METHOD_COUNT) {
-                       return FALSE;
-               }
-       }
-       else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
-               message->start_line.method_id = apt_string_table_id_find(
-                       synth_event_string_table,
-                       SYNTHESIZER_EVENT_COUNT,
-                       &message->start_line.method_name);
-               if(message->start_line.method_id >= SYNTHESIZER_EVENT_COUNT) {
-                       return FALSE;
-               }
-       }
-
-       message->header.resource_header_accessor.vtable = 
-               mrcp_synth_header_vtable_get(message->start_line.version);
-       return TRUE;
+       return synth_event_string_table;
 }
 
-
 /** Create MRCP synthesizer resource */
 MRCP_DECLARE(mrcp_resource_t*) mrcp_synth_resource_create(apr_pool_t *pool)
 {
-       mrcp_resource_t *resource = apr_palloc(pool,sizeof(mrcp_resource_t));
-       mrcp_resource_init(resource);
-
-       resource->resourcify_message_by_id = synth_message_resourcify_by_id;
-       resource->resourcify_message_by_name = synth_message_resourcify_by_name;
+       mrcp_resource_t *resource = mrcp_resource_create(pool);
 
-       resource->create_client_state_machine = mrcp_synth_client_state_machine_create;
-       resource->create_server_state_machine = mrcp_synth_server_state_machine_create;
+       resource->method_count = SYNTHESIZER_METHOD_COUNT;
+       resource->event_count = SYNTHESIZER_EVENT_COUNT;
+       resource->get_method_str_table = synth_method_string_table_get;
+       resource->get_event_str_table = synth_event_string_table_get;
+       resource->get_resource_header_vtable = mrcp_synth_header_vtable_get;
        return resource;
 }
index bcef530f87b5a0cdb03b717ca35e19683ed86e97..82d44ea865a5353f2e7793e19d99b079285ebbaf 100644 (file)
@@ -77,7 +77,7 @@ struct mrcp_connection_t {
 };
 
 /** Create MRCP connection. */
-mrcp_connection_t* mrcp_connection_create();
+mrcp_connection_t* mrcp_connection_create(void);
 
 /** Destroy MRCP connection. */
 void mrcp_connection_destroy(mrcp_connection_t *connection);
@@ -91,6 +91,8 @@ mrcp_control_channel_t* mrcp_connection_channel_find(mrcp_connection_t *connecti
 /** Remove Control Channel from MRCP connection. */
 apt_bool_t mrcp_connection_channel_remove(mrcp_connection_t *connection, mrcp_control_channel_t *channel);
 
+/** Raise disconnect event for each channel from the specified connection. */
+apt_bool_t mrcp_connection_disconnect_raise(mrcp_connection_t *connection, const mrcp_connection_event_vtable_t *vtable);
 
 APT_END_EXTERN_C
 
index 53744512165dbef7a4b1ca67bf4e54e7cc0add55..c7a02c0419e1013ec9b221ca8fa036e93c1830de 100644 (file)
@@ -53,6 +53,8 @@ struct mrcp_connection_event_vtable_t {
        apt_bool_t (*on_remove)(mrcp_control_channel_t *channel, apt_bool_t status);
        /** Message receive event handler */
        apt_bool_t (*on_receive)(mrcp_control_channel_t *channel, mrcp_message_t *message);
+       /** Disconnect event handler */
+       apt_bool_t (*on_disconnect)(mrcp_control_channel_t *channel);
 };
 
 /** MRCPv2 control channel */
index a9323ae75995ce8e3d63328f3fc1873e3fa9409e..b5dbc44c5fb5625e1df465f14424b5d476379c21 100644 (file)
  * @brief MRCPv2 Control Descriptor
  */ 
 
+#include <apr_tables.h>
 #include "apt_string.h"
 #include "mrcp_connection_types.h"
 
 APT_BEGIN_EXTERN_C
 
+/** TCP discard port used in offer/answer */
+#define TCP_DISCARD_PORT 9
+
+
 /** MRCPv2 proto transport */
 typedef enum {
        MRCP_PROTO_TCP,
@@ -85,25 +90,15 @@ struct mrcp_control_descriptor_t {
        apt_str_t              resource_name;
        /** Session identifier */
        apt_str_t              session_id;
-       /** Control media identifier */
-       apr_size_t             cmid;
+       /** Array of cmid attributes */
+       apr_array_header_t    *cmid_arr;
        /** Base identifier */
        apr_size_t             id;
 };
 
-/** Initialize MRCP control descriptor */
-static APR_INLINE void mrcp_control_descriptor_init(mrcp_control_descriptor_t *descriptor)
-{
-       apt_string_reset(&descriptor->ip);
-       descriptor->port = 0;
-       descriptor->proto = MRCP_PROTO_UNKNOWN;
-       descriptor->setup_type = MRCP_SETUP_TYPE_UNKNOWN;
-       descriptor->connection_type = MRCP_CONNECTION_TYPE_UNKNOWN;
-       apt_string_reset(&descriptor->resource_name);
-       apt_string_reset(&descriptor->session_id);
-       descriptor->cmid = 0;
-       descriptor->id = 0;
-}
+
+/** Create MRCP control descriptor */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_descriptor_create(apr_pool_t *pool);
 
 /** Create MRCP control offer */
 MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *pool);
@@ -111,6 +106,12 @@ MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *p
 /** Create MRCP control answer */
 MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_answer_create(mrcp_control_descriptor_t *offer, apr_pool_t *pool);
 
+/** Add cmid to cmid_arr */
+MRCP_DECLARE(void) mrcp_cmid_add(apr_array_header_t *cmid_arr, apr_size_t cmid);
+
+/** Find cmid in cmid_arr */
+MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(apr_array_header_t *cmid_arr, apr_size_t cmid);
+
 /** Get MRCP protocol transport name by identifier */
 MRCP_DECLARE(const apt_str_t*) mrcp_proto_get(mrcp_proto_type_e proto);
 
index 89f636eefa38073526f9687ce0a6105ab4c9fe86..a94765f042c5f8b7c3f1fd0b2065a0c015e79c6a 100644 (file)
@@ -96,6 +96,7 @@ MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_client_connection_agent_create(
                vtable->terminate = mrcp_client_agent_task_terminate;
                vtable->destroy = mrcp_client_agent_task_on_destroy;
        }
+       apt_task_auto_ready_set(agent->task,FALSE);
 
        agent->connection_list = apt_list_create(pool);
 
@@ -310,7 +311,8 @@ static mrcp_connection_t* mrcp_client_agent_connection_find(mrcp_connection_agen
                connection = apt_list_elem_object_get(elem);
                if(connection) {
                        if(apr_sockaddr_info_get(&sockaddr,descriptor->ip.buf,APR_INET,descriptor->port,0,connection->pool) == APR_SUCCESS) {
-                               if(apr_sockaddr_equal(sockaddr,connection->r_sockaddr) != 0) {
+                               if(apr_sockaddr_equal(sockaddr,connection->r_sockaddr) != 0 && 
+                                       descriptor->port == connection->r_sockaddr->port) {
                                        return connection;
                                }
                        }
@@ -514,7 +516,7 @@ static apt_bool_t mrcp_client_agent_messsage_receive(mrcp_connection_agent_t *ag
                apr_socket_close(connection->sock);
                connection->sock = NULL;
 
-//             agent->vtable->on_disconnect(agent,connection);
+               mrcp_connection_disconnect_raise(connection,agent->vtable);
                return TRUE;
        }
        /* calculate actual length of the stream */
@@ -588,6 +590,9 @@ static apt_bool_t mrcp_client_agent_task_run(apt_task_t *task)
                return FALSE;
        }
 
+       /* explicitly indicate task is ready to process messages */
+       apt_task_ready(agent->task);
+
        while(running) {
                status = apt_pollset_poll(agent->pollset, -1, &num, &ret_pfd);
                if(status != APR_SUCCESS) {
index 079671a491b8b094b32bd6457a757cec1a76d966..d174cb78d0a37b7a426ca06349e01100947167c4 100644 (file)
@@ -78,3 +78,21 @@ apt_bool_t mrcp_connection_channel_remove(mrcp_connection_t *connection, mrcp_co
        connection->access_count--;
        return TRUE;
 }
+
+apt_bool_t mrcp_connection_disconnect_raise(mrcp_connection_t *connection, const mrcp_connection_event_vtable_t *vtable)
+{
+       if(vtable && vtable->on_disconnect) {
+               mrcp_control_channel_t *channel;
+               void *val;
+               apr_hash_index_t *it = apr_hash_first(connection->pool,connection->channel_table);
+               /* walk through the list of channels and raise disconnect event for them */
+               for(; it; it = apr_hash_next(it)) {
+                       apr_hash_this(it,NULL,NULL,&val);
+                       channel = val;
+                       if(channel) {
+                               vtable->on_disconnect(channel);
+                       }
+               }
+       }
+       return TRUE;
+}
index 2e9a0e43c261cac478ccf1ca15b46f7d3852044c..de0de51aa94952ad09ae3f191a8f64c043b2cc21 100644 (file)
@@ -85,14 +85,30 @@ MRCP_DECLARE(mrcp_connection_type_e) mrcp_connection_type_find(const apt_str_t *
        return apt_string_table_id_find(mrcp_connection_value_table,MRCP_CONNECTION_TYPE_COUNT,attrib);
 }
 
+/** Create MRCP control descriptor */
+MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_descriptor_create(apr_pool_t *pool)
+{
+       mrcp_control_descriptor_t *descriptor;
+       descriptor = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
+
+       apt_string_reset(&descriptor->ip);
+       descriptor->port = 0;
+       descriptor->proto = MRCP_PROTO_UNKNOWN;
+       descriptor->setup_type = MRCP_SETUP_TYPE_UNKNOWN;
+       descriptor->connection_type = MRCP_CONNECTION_TYPE_UNKNOWN;
+       apt_string_reset(&descriptor->resource_name);
+       apt_string_reset(&descriptor->session_id);
+       descriptor->cmid_arr = apr_array_make(pool,1,sizeof(apr_size_t));
+       descriptor->id = 0;
+       return descriptor;
+}
+
 /** Create MRCP control offer */
 MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *pool)
 {
-       mrcp_control_descriptor_t *offer;
-       offer = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
-       mrcp_control_descriptor_init(offer);
+       mrcp_control_descriptor_t *offer = mrcp_control_descriptor_create(pool);
        offer->proto = MRCP_PROTO_TCP;
-       offer->port = 9;
+       offer->port = TCP_DISCARD_PORT;
        offer->setup_type = MRCP_SETUP_TYPE_ACTIVE;
        offer->connection_type = MRCP_CONNECTION_TYPE_EXISTING;
        return offer;
@@ -101,12 +117,29 @@ MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_offer_create(apr_pool_t *p
 /** Create MRCP control answer */
 MRCP_DECLARE(mrcp_control_descriptor_t*) mrcp_control_answer_create(mrcp_control_descriptor_t *offer, apr_pool_t *pool)
 {
-       mrcp_control_descriptor_t *answer;
-       answer = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
-       mrcp_control_descriptor_init(answer);
+       mrcp_control_descriptor_t *answer = mrcp_control_descriptor_create(pool);
        if(offer) {
                *answer = *offer;
+               answer->cmid_arr = apr_array_copy(pool,offer->cmid_arr);
        }
        answer->setup_type = MRCP_SETUP_TYPE_PASSIVE;
        return answer;
 }
+
+/** Add cmid to cmid_arr */
+MRCP_DECLARE(void) mrcp_cmid_add(apr_array_header_t *cmid_arr, apr_size_t cmid)
+{
+       APR_ARRAY_PUSH(cmid_arr, apr_size_t) = cmid;
+}
+
+/** Find cmid in cmid_arr */
+MRCP_DECLARE(apt_bool_t) mrcp_cmid_find(apr_array_header_t *cmid_arr, apr_size_t cmid)
+{
+       int i;
+       for(i=0; i<cmid_arr->nelts; i++) {
+               if(APR_ARRAY_IDX(cmid_arr,i,apr_size_t) == cmid) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
index 1655697c89f783b8e973cd45626d1d574b5877d5..ba500a20bdee6b8c0a8957697a116c6bf6fbf4e6 100644 (file)
@@ -114,6 +114,7 @@ MRCP_DECLARE(mrcp_connection_agent_t*) mrcp_server_connection_agent_create(
                vtable->terminate = mrcp_server_agent_task_terminate;
                vtable->destroy = mrcp_server_agent_task_on_destroy;
        }
+       apt_task_auto_ready_set(agent->task,FALSE);
 
        agent->msg_queue = apt_cyclic_queue_create(CYCLIC_QUEUE_DEFAULT_SIZE);
        apr_thread_mutex_create(&agent->guard,APR_THREAD_MUTEX_UNNESTED,pool);
@@ -610,12 +611,14 @@ static apt_bool_t mrcp_server_message_handler(void *obj, mrcp_message_t *message
        }
        else if(result == MRCP_STREAM_MESSAGE_INVALID) {
                /* error case */
-               mrcp_message_t *response;
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCPv2 Stream");
-               response = mrcp_response_create(message,message->pool);
-               response->start_line.status_code = MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE;
-               if(mrcp_server_agent_messsage_send(agent,connection,response) == FALSE) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send MRCPv2 Response");
+               if(message->resource) {
+                       mrcp_message_t *response;
+                       response = mrcp_response_create(message,message->pool);
+                       response->start_line.status_code = MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE;
+                       if(mrcp_server_agent_messsage_send(agent,connection,response) == FALSE) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Send MRCPv2 Response");
+                       }
                }
        }
        return TRUE;
@@ -713,6 +716,9 @@ static apt_bool_t mrcp_server_agent_task_run(apt_task_t *task)
                return FALSE;
        }
 
+       /* explicitly indicate task is ready to process messages */
+       apt_task_ready(agent->task);
+
        while(running) {
                status = apt_pollset_poll(agent->pollset, -1, &num, &ret_pfd);
                if(status != APR_SUCCESS) {
index 68b5ec2bbeb022b134992d3ce05f2194f16f0426..2a71c6ed2de7009826a567907a5d96baaf103ae8 100644 (file)
@@ -61,6 +61,7 @@ typedef enum{
        RTSP_TRANSPORT_ATTRIB_DESTINATION,
        RTSP_TRANSPORT_ATTRIB_UNICAST,
        RTSP_TRANSPORT_ATTRIB_MULTICAST,
+       RTSP_TRANSPORT_ATTRIB_MODE,
 
        RTSP_TRANSPORT_ATTRIB_COUNT,
        RTSP_TRANSPORT_ATTRIB_NONE = RTSP_TRANSPORT_ATTRIB_COUNT
@@ -135,6 +136,8 @@ struct rtsp_transport_t {
        apt_str_t                source;
        /** Destination IP address */
        apt_str_t                destination;
+       /** Mode indicates the method to support (either PLAY or RECORD) */
+       apt_str_t                mode;
 };
 
 /** RTSP header */
@@ -181,6 +184,7 @@ static APR_INLINE void rtsp_transport_init(rtsp_transport_t *transport)
        rtsp_port_range_init(&transport->server_port_range);
        apt_string_reset(&transport->source);
        apt_string_reset(&transport->destination);
+       apt_string_reset(&transport->mode);
 }
 
 /** Initialize header */
index 825e1f359d8d4883ca6661ad7238486366e9dd56..8b78005ff6418d9274194f5bd6a6bb10dd458bba 100644 (file)
@@ -582,10 +582,12 @@ static apt_bool_t rtsp_client_session_response_process(rtsp_client_t *client, rt
                apr_hash_set(session->resource_table,resource_name,APR_HASH_KEY_STRING,NULL);
 
                if(apr_hash_count(session->resource_table) == 0) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Session "APT_PTRSID_FMT,
-                               session,
-                               session->id.buf);
-                       apr_hash_set(session->connection->session_table,session->id.buf,session->id.length,NULL);
+                       if(session->connection) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove RTSP Session "APT_PTRSID_FMT,
+                                       session,
+                                       session->id.buf);
+                               apr_hash_set(session->connection->session_table,session->id.buf,session->id.length,NULL);
+                       }
                }
        }
 
index 9d6e12c5322d280fc88397ef61085df94e985216..b76f2ec383f526a5979d0f2a7e26717fde2a8246 100644 (file)
@@ -53,11 +53,12 @@ static const apt_str_table_item_t rtsp_profile_string_table[] = {
 /** String table of RTSP transport attributes (rtsp_transport_attrib_e) */
 static const apt_str_table_item_t rtsp_transport_attrib_string_table[] = {
        {{"client_port", 11},0},
-       {{"server_port", 11},1},
-       {{"source",      6}, 1},
+       {{"server_port", 11},2},
+       {{"source",       6},2},
        {{"destination", 11},0},
-       {{"unicast",     7}, 0},
-       {{"multicast",   9}, 0}
+       {{"unicast",      7},0},
+       {{"multicast",    9},1},
+       {{"mode",         4},2}
 };
 
 /** Parse RTSP transport port range */
@@ -96,15 +97,15 @@ static apt_bool_t rtsp_port_range_generate(rtsp_transport_attrib_e attrib, const
        return TRUE;
 }
 
-/** Parse RTSP source/destination address */
-static apt_bool_t rtsp_address_parse(apt_str_t *address, apt_text_stream_t *stream, apr_pool_t *pool)
+/** Parse text value of RTSP transport attrib (source/destination, e.t.c) */
+static apt_bool_t rtsp_transport_attrib_value_parse(apt_str_t *value, apt_text_stream_t *stream, apr_pool_t *pool)
 {
-       apt_str_t value;
-       /* read min value */
-       if(apt_text_field_read(stream,';',TRUE,&value) == FALSE) {
+       apt_str_t field;
+       /* read value */
+       if(apt_text_field_read(stream,';',TRUE,&field) == FALSE) {
                return FALSE;
        }
-       apt_string_copy(address,&value,pool);
+       apt_string_copy(value,&field,pool);
        return TRUE;
 }
 
@@ -132,10 +133,10 @@ static apt_bool_t rtsp_transport_attrib_parse(rtsp_transport_t *transport, const
                        rtsp_port_range_parse(&transport->client_port_range,&stream);
                        break;
                case RTSP_TRANSPORT_ATTRIB_SOURCE:
-                       rtsp_address_parse(&transport->source,&stream,pool);
+                       rtsp_transport_attrib_value_parse(&transport->source,&stream,pool);
                        break;
                case RTSP_TRANSPORT_ATTRIB_DESTINATION:
-                       rtsp_address_parse(&transport->destination,&stream,pool);
+                       rtsp_transport_attrib_value_parse(&transport->destination,&stream,pool);
                        break;
                case RTSP_TRANSPORT_ATTRIB_UNICAST:
                        transport->delivery = RTSP_DELIVERY_UNICAST;
@@ -143,6 +144,9 @@ static apt_bool_t rtsp_transport_attrib_parse(rtsp_transport_t *transport, const
                case RTSP_TRANSPORT_ATTRIB_MULTICAST:
                        transport->delivery = RTSP_DELIVERY_MULTICAST;
                        break;
+               case RTSP_TRANSPORT_ATTRIB_MODE:
+                       rtsp_transport_attrib_value_parse(&transport->mode,&stream,pool);
+                       break;
                default:
                        break;
        }
@@ -180,7 +184,7 @@ static apt_bool_t rtsp_transport_protocol_parse(rtsp_transport_t *transport, con
        if(transport->profile >= RTSP_PROFILE_COUNT) {
                return FALSE;
        }
-               
+
        /* read optional lower transport protocol (UDP) */
        if(apt_text_field_read(&stream,'/',TRUE,&field) == TRUE) {
                transport->lower_protocol = apt_string_table_id_find(rtsp_lower_transport_string_table,RTSP_LOWER_TRANSPORT_COUNT,&field);
@@ -256,6 +260,17 @@ static apt_bool_t rtsp_transport_generate(rtsp_transport_t *transport, apt_text_
                apt_text_char_insert(text_stream,';');
                rtsp_port_range_generate(RTSP_TRANSPORT_ATTRIB_SERVER_PORT,&transport->server_port_range,text_stream);
        }
+
+       if(transport->mode.length) {
+               const apt_str_t *str;
+               str = apt_string_table_str_get(rtsp_transport_attrib_string_table,RTSP_TRANSPORT_ATTRIB_COUNT,RTSP_TRANSPORT_ATTRIB_MODE);
+               if(str) {
+                       apt_text_char_insert(text_stream,';');
+                       apt_string_value_generate(str,text_stream);
+                       apt_text_char_insert(text_stream,'=');
+                       apt_string_value_generate(&transport->mode,text_stream);
+               }
+       }
        return TRUE;
 }
 
index 2b44e700a760ac5c29aa6a6237c00cddf1f763e5..2bb2ee60d09228d1cd1031e1dbe81850c605e25f 100644 (file)
@@ -46,13 +46,13 @@ RTSP_DECLARE(rtsp_message_t*) rtsp_response_create(const rtsp_message_t *request
 {
        const apt_str_t *reason_str;
        rtsp_status_line_t *status_line;
-       rtsp_message_t *response = rtsp_message_create(RTSP_MESSAGE_TYPE_RESPONSE,request->pool);
+       rtsp_message_t *response = rtsp_message_create(RTSP_MESSAGE_TYPE_RESPONSE,pool);
        status_line = &response->start_line.common.status_line;
        status_line->version = request->start_line.common.request_line.version;
        status_line->status_code = status_code;
        reason_str = rtsp_reason_phrase_get(reason);
        if(reason_str) {
-               apt_string_copy(&status_line->reason,reason_str,request->pool);
+               apt_string_copy(&status_line->reason,reason_str,pool);
        }
 
        if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CSEQ) == TRUE) {
@@ -60,6 +60,15 @@ RTSP_DECLARE(rtsp_message_t*) rtsp_response_create(const rtsp_message_t *request
                rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_CSEQ);
        }
 
+       if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) {
+               const rtsp_transport_t *req_transport = &request->header.transport;
+               rtsp_transport_t *res_transport = &response->header.transport;
+               if(req_transport->mode.length) {
+                       apt_string_copy(&res_transport->mode,&req_transport->mode,pool);
+                       rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);
+               }
+       }
+
        return response;
 }
 
index d568e9741c441e5ff85987229c9b3db6555d3a9a..ad7d251c40119ef9c5f331e127728da6f64eae5e 100644 (file)
@@ -70,7 +70,6 @@ struct rtsp_server_session_t {
 
        /** Session identifier */
        apt_str_t                 id;
-       apt_str_t                 url;
 
        /** Last cseq sent */
        apr_size_t                last_cseq;
@@ -80,6 +79,9 @@ struct rtsp_server_session_t {
        /** request queue */
        apt_obj_list_t           *request_queue;
 
+       /** Resource table */
+       apr_hash_t               *resource_table;
+
        /** In-progress termination request */
        apt_bool_t                terminating;
 };
@@ -261,9 +263,9 @@ static rtsp_server_session_t* rtsp_server_session_create(rtsp_server_t *server)
        session->last_cseq = 0;
        session->active_request = NULL;
        session->request_queue = apt_list_create(pool);
+       session->resource_table = apr_hash_make(pool);
        session->terminating = FALSE;
 
-       apt_string_reset(&session->url);
        apt_unique_id_generate(&session->id,RTSP_SESSION_ID_HEX_STRING_LENGTH,pool);
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create RTSP Session "APT_SID_FMT,session->id.buf);
        if(server->vtable->create_session(server,session) != TRUE) {
@@ -335,8 +337,14 @@ static apt_bool_t rtsp_server_session_terminate_request(rtsp_server_t *server, r
 static apt_bool_t rtsp_server_session_message_handle(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message)
 {
        if(message->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
-               rtsp_server_session_terminate_request(server,session);
-               return TRUE;
+               /* remove resource */
+               const char *resource_name = message->start_line.common.request_line.resource_name;
+               apr_hash_set(session->resource_table,resource_name,APR_HASH_KEY_STRING,NULL);
+
+               if(apr_hash_count(session->resource_table) == 0) {
+                       rtsp_server_session_terminate_request(server,session);
+                       return TRUE;
+               }
        }
 
        if(server->vtable->handle_message(server,session,message) != TRUE) {
@@ -349,7 +357,7 @@ static apt_bool_t rtsp_server_session_message_handle(rtsp_server_t *server, rtsp
        return TRUE;
 }
 
-/* Process incoming SETUP request */
+/* Process incoming SETUP/DESCRIBE request */
 static rtsp_server_session_t* rtsp_server_session_setup_process(rtsp_server_t *server, rtsp_server_connection_t *rtsp_connection, rtsp_message_t *message)
 {
        rtsp_server_session_t *session = NULL;
@@ -357,7 +365,6 @@ static rtsp_server_session_t* rtsp_server_session_setup_process(rtsp_server_t *s
                /* create new session */
                session = rtsp_server_session_create(server);
                session->connection = rtsp_connection;
-               session->url = message->start_line.common.request_line.url;
                apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add RTSP Session "APT_SID_FMT,session->id.buf);
                apr_hash_set(rtsp_connection->session_table,session->id.buf,session->id.length,session);
        }
@@ -405,13 +412,21 @@ static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rts
                                message->header.session_id.buf,
                                message->header.session_id.length);
        if(!session) {
-               /* error case */
+               /* error case, no such session */
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such RTSP Session "APT_SID_FMT,message->header.session_id.buf);
                return rtsp_server_error_respond(server,rtsp_connection,message,
                                                                RTSP_STATUS_CODE_NOT_FOUND,
                                                                RTSP_REASON_PHRASE_NOT_FOUND);
        }
        
+       if(session->terminating == TRUE) {
+               /* error case, session is being terminated */
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Acceptable Request "APT_SID_FMT,message->header.session_id.buf);
+               return rtsp_server_error_respond(server,rtsp_connection,message,
+                                                               RTSP_STATUS_CODE_NOT_ACCEPTABLE,
+                                                               RTSP_REASON_PHRASE_NOT_ACCEPTABLE);
+       }
+       
        if(session->active_request) {
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push RTSP Request to Queue "APT_SID_FMT,session->id.buf);
                apt_list_push_back(session->request_queue,message,message->pool);
@@ -427,34 +442,62 @@ static apt_bool_t rtsp_server_session_request_process(rtsp_server_t *server, rts
 /* Process outgoing RTSP response */
 static apt_bool_t rtsp_server_session_response_process(rtsp_server_t *server, rtsp_server_session_t *session, rtsp_message_t *message)
 {
-       if(session->id.buf) {
-               message->header.session_id = session->id;
-               rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
-       }
-
+       apt_bool_t terminate = FALSE;
+       rtsp_message_t *request = NULL;
        if(message->start_line.message_type == RTSP_MESSAGE_TYPE_REQUEST) {
                /* RTSP ANNOUNCE request (asynch event) */
-               message->start_line.common.request_line.url = session->url;
+               const char *resource_name = message->start_line.common.request_line.resource_name;
+               if(resource_name) {
+                       request = apr_hash_get(session->resource_table,resource_name,APR_HASH_KEY_STRING);
+               }
+               if(!request) {
+                       return FALSE;
+               }
+               message->start_line.common.request_line.url = request->start_line.common.request_line.url;
                message->header.cseq = session->last_cseq;
                rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_CSEQ);
                
+               if(session->id.buf) {
+                       message->header.session_id = session->id;
+                       rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+               }
                rtsp_server_message_send(server,session->connection->base,message);
                return TRUE;
        }
 
-       session->last_cseq = message->header.cseq;
-       rtsp_server_message_send(server,session->connection->base,message);
+       if(!session->active_request) {
+               /* unexpected response */
+               return FALSE;
+       }
 
-       if(session->active_request) {
-               rtsp_message_t *request = session->active_request;
+       request = session->active_request;
+       if(request->start_line.common.request_line.method_id == RTSP_METHOD_DESCRIBE) {
+               terminate = TRUE;
+       }
+       else {
+               if(session->id.buf) {
+                       message->header.session_id = session->id;
+                       rtsp_header_property_add(&message->header.property_set,RTSP_HEADER_FIELD_SESSION_ID);
+               }
                if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
-                       if(message->start_line.common.status_line.status_code != RTSP_STATUS_CODE_OK) {
-                               rtsp_server_session_terminate_request(server,session);
+                       if(message->start_line.common.status_line.status_code == RTSP_STATUS_CODE_OK) {
+                               /* add resource */
+                               const char *resource_name = request->start_line.common.request_line.resource_name;
+                               apr_hash_set(session->resource_table,resource_name,APR_HASH_KEY_STRING,request);
+                       }
+                       else if(apr_hash_count(session->resource_table) == 0) {
+                               terminate = TRUE;
                        }
                }
-               else if(request->start_line.common.request_line.method_id == RTSP_METHOD_DESCRIBE) {
-                       rtsp_server_session_terminate_request(server,session);
-               }
+       }
+
+       session->last_cseq = message->header.cseq;
+       rtsp_server_message_send(server,session->connection->base,message);
+
+       if(terminate == TRUE) {
+               session->active_request = NULL;
+               rtsp_server_session_terminate_request(server,session);
+               return TRUE;
        }
 
        session->active_request = apt_list_pop_front(session->request_queue);
index d5e36525fef3a9320833097c66bc208bb40f4337..56244af8c8e2cd96f4f625d8bb34e28bbe52368d 100644 (file)
@@ -56,14 +56,14 @@ MRCP_DECLARE(apr_size_t) sdp_string_generate_by_mrcp_descriptor(char *buffer, ap
        count = mrcp_session_media_count_get(descriptor);
        for(i=0; i<count; i++) {
                audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
-               if(audio_media && audio_media->base.id == i) {
+               if(audio_media && audio_media->id == i) {
                        /* generate audio media */
                        audio_index++;
                        offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
                        continue;
                }
                video_media = mrcp_session_video_media_get(descriptor,video_index);
-               if(video_media && video_media->base.id == i) {
+               if(video_media && video_media->id == i) {
                        /* generate video media */
                        video_index++;
                        offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
@@ -106,7 +106,7 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_sdp_session
                        {
                                mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                                mpf_rtp_media_descriptor_init(media);
-                               media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                               media->id = mrcp_session_audio_media_add(descriptor,media);
                                mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
                                break;
                        }
@@ -114,14 +114,13 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_sdp_session
                        {
                                mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                                mpf_rtp_media_descriptor_init(media);
-                               media->base.id = mrcp_session_video_media_add(descriptor,media);
+                               media->id = mrcp_session_video_media_add(descriptor,media);
                                mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
                                break;
                        }
                        case sdp_media_application:
                        {
-                               mrcp_control_descriptor_t *control_media = apr_palloc(pool,sizeof(mrcp_control_descriptor_t));
-                               mrcp_control_descriptor_init(control_media);
+                               mrcp_control_descriptor_t *control_media = mrcp_control_descriptor_create(pool);
                                control_media->id = mrcp_session_control_media_add(descriptor,control_media);
                                mrcp_control_media_generate(control_media,sdp_media,&descriptor->ip,pool);
                                break;
@@ -147,31 +146,38 @@ static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mr
        }
        offset += snprintf(buffer+offset,size-offset,
                "m=audio %d RTP/AVP", 
-               audio_media->base.state == MPF_MEDIA_ENABLED ? audio_media->base.port : 0);
+               audio_media->state == MPF_MEDIA_ENABLED ? audio_media->port : 0);
        for(i=0; i<descriptor_arr->nelts; i++) {
-               codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+               codec_descriptor = &APR_ARRAY_IDX(descriptor_arr,i,mpf_codec_descriptor_t);
                if(codec_descriptor->enabled == TRUE) {
                        offset += snprintf(buffer+offset,size-offset," %d", codec_descriptor->payload_type);
                }
        }
        offset += snprintf(buffer+offset,size-offset,"\r\n");
-       if(descriptor->ip.length && audio_media->base.ip.length && 
-               apt_string_compare(&descriptor->ip,&audio_media->base.ip) != TRUE) {
-               const char *media_ip = audio_media->base.ext_ip.buf ? audio_media->base.ext_ip.buf : audio_media->base.ip.buf;
+       if(descriptor->ip.length && audio_media->ip.length && 
+               apt_string_compare(&descriptor->ip,&audio_media->ip) != TRUE) {
+               const char *media_ip = audio_media->ext_ip.buf ? audio_media->ext_ip.buf : audio_media->ip.buf;
                offset += sprintf(buffer+offset,"c=IN IP4 %s\r\n",media_ip);
        }
-       if(audio_media->base.state == MPF_MEDIA_ENABLED) {
-               const apt_str_t *mode_str = mpf_stream_mode_str_get(audio_media->mode);
+       if(audio_media->state == MPF_MEDIA_ENABLED) {
+               const apt_str_t *direction_str = mpf_rtp_direction_str_get(audio_media->direction);
                for(i=0; i<descriptor_arr->nelts; i++) {
-                       codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+                       codec_descriptor = &APR_ARRAY_IDX(descriptor_arr,i,mpf_codec_descriptor_t);
                        if(codec_descriptor->enabled == TRUE && codec_descriptor->name.buf) {
                                offset += snprintf(buffer+offset,size-offset,"a=rtpmap:%d %s/%d\r\n",
                                        codec_descriptor->payload_type,
                                        codec_descriptor->name.buf,
                                        codec_descriptor->sampling_rate);
+                               if(codec_descriptor->format.buf) {
+                                       offset += snprintf(buffer+offset,size-offset,"a=fmtp:%d %s\r\n",
+                                               codec_descriptor->payload_type,
+                                               codec_descriptor->format.buf);
+                               }
                        }
                }
-               offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",mode_str ? mode_str->buf : "");
+               if(direction_str) {
+                       offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",direction_str->buf);
+               }
                
                if(audio_media->ptime) {
                        offset += snprintf(buffer+offset,size-offset,"a=ptime:%hu\r\n",audio_media->ptime);
@@ -184,6 +190,7 @@ static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mr
 /** Generate SDP media by MRCP control media descriptor */
 static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, const mrcp_session_descriptor_t *descriptor, const mrcp_control_descriptor_t *control_media, apt_bool_t offer)
 {
+       int i;
        apr_size_t offset = 0;
        const apt_str_t *proto;
        const apt_str_t *setup_type;
@@ -197,24 +204,21 @@ static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, cons
                                "m=application %d %s 1\r\n"
                                "a=setup:%s\r\n"
                                "a=connection:%s\r\n"
-                               "a=resource:%s\r\n"
-                               "a=cmid:%d\r\n",
+                               "a=resource:%s\r\n",
                                control_media->port,
                                proto ? proto->buf : "",
                                setup_type ? setup_type->buf : "",
                                connection_type ? connection_type->buf : "",
-                               control_media->resource_name.buf,
-                               control_media->cmid);
+                               control_media->resource_name.buf);
+
                }
                else {
                        offset += snprintf(buffer+offset,size-offset,
                                "m=application %d %s 1\r\n"
-                               "a=resource:%s\r\n"
-                               "a=cmid:%d\r\n",
+                               "a=resource:%s\r\n",
                                control_media->port,
                                proto ? proto->buf : "",
-                               control_media->resource_name.buf,
-                               control_media->cmid);
+                               control_media->resource_name.buf);
                }
        }
        else { /* answer */
@@ -223,29 +227,32 @@ static apr_size_t sdp_control_media_generate(char *buffer, apr_size_t size, cons
                                "m=application %d %s 1\r\n"
                                "a=setup:%s\r\n"
                                "a=connection:%s\r\n"
-                               "a=channel:%s@%s\r\n"
-                               "a=cmid:%d\r\n",
+                               "a=channel:%s@%s\r\n",
                                control_media->port,
                                proto ? proto->buf : "",
                                setup_type ? setup_type->buf : "",
                                connection_type ? connection_type->buf : "",
                                control_media->session_id.buf,
-                               control_media->resource_name.buf,
-                               control_media->cmid);
+                               control_media->resource_name.buf);
                }
                else {
                        offset += sprintf(buffer+offset,
                                "m=application %d %s 1\r\n"
-                               "a=channel:%s@%s\r\n"
-                               "a=cmid:%d\r\n",
+                               "a=channel:%s@%s\r\n",
                                control_media->port,
                                proto ? proto->buf : "",
                                control_media->session_id.buf,
-                               control_media->resource_name.buf,
-                               control_media->cmid);
+                               control_media->resource_name.buf);
                }
        }
 
+       for(i=0; i<control_media->cmid_arr->nelts; i++) {
+               offset += snprintf(buffer+offset,size-offset,
+                       "a=cmid:%d\r\n",
+                       APR_ARRAY_IDX(control_media->cmid_arr,i,apr_size_t));
+
+       }
+
        return offset;
 }
 
@@ -285,31 +292,31 @@ static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media,
 
        switch(sdp_media->m_mode) {
                case sdp_inactive:
-                       rtp_media->mode = STREAM_MODE_NONE;
+                       rtp_media->direction = STREAM_DIRECTION_NONE;
                        break;
                case sdp_sendonly:
-                       rtp_media->mode = STREAM_MODE_SEND;
+                       rtp_media->direction = STREAM_DIRECTION_SEND;
                        break;
                case sdp_recvonly:
-                       rtp_media->mode = STREAM_MODE_RECEIVE;
+                       rtp_media->direction = STREAM_DIRECTION_RECEIVE;
                        break;
                case sdp_sendrecv:
-                       rtp_media->mode = STREAM_MODE_SEND_RECEIVE;
+                       rtp_media->direction = STREAM_DIRECTION_DUPLEX;
                        break;
        }
 
        if(sdp_media->m_connections) {
-               apt_string_assign(&rtp_media->base.ip,sdp_media->m_connections->c_address,pool);
+               apt_string_assign(&rtp_media->ip,sdp_media->m_connections->c_address,pool);
        }
        else {
-               rtp_media->base.ip = *ip;
+               rtp_media->ip = *ip;
        }
        if(sdp_media->m_port) {
-               rtp_media->base.port = (apr_port_t)sdp_media->m_port;
-               rtp_media->base.state = MPF_MEDIA_ENABLED;
+               rtp_media->port = (apr_port_t)sdp_media->m_port;
+               rtp_media->state = MPF_MEDIA_ENABLED;
        }
        else {
-               rtp_media->base.state = MPF_MEDIA_DISABLED;
+               rtp_media->state = MPF_MEDIA_DISABLED;
        }
        return TRUE;
 }
@@ -348,7 +355,7 @@ static apt_bool_t mrcp_control_media_generate(mrcp_control_descriptor_t *control
                                apt_id_resource_parse(&value,'@',&control_media->session_id,&control_media->resource_name,pool);
                                break;
                        case MRCP_ATTRIB_CMID:
-                               control_media->cmid = atoi(attrib->a_value);
+                               mrcp_cmid_add(control_media->cmid_arr,atoi(attrib->a_value));
                                break;
                        default:
                                break;
@@ -385,9 +392,11 @@ MRCP_DECLARE(apr_size_t) sdp_resource_discovery_string_generate(const char *ip,
                        "m=application 0 TCP/MRCPv2 1\r\n"
                        "a=resource:speechsynth\r\n"
                        "a=resource:speechrecog\r\n"
-                       "m=audio 0 RTP/AVP 0 8\r\n"
+                       "m=audio 0 RTP/AVP 0 8 96 101\r\n"
                        "a=rtpmap:0 PCMU/8000\r\n"
-                       "a=rtpmap:8 PCMA/8000\r\n",
+                       "a=rtpmap:8 PCMA/8000\r\n"
+                       "a=rtpmap:96 L16/8000\r\n"
+                       "a=rtpmap:101 telephone-event/8000\r\n",
                        origin,
                        ip,
                        ip);
index d89aa9be3d1c4e72793918884886e7e713f04a72..aa7a5fb75361a98f512dce289b363d347ae0f116 100644 (file)
@@ -521,8 +521,11 @@ static void mrcp_sofia_event_callback(
                        mrcp_sofia_on_resource_discover(status,sofia_agent,nh,sofia_session,sip,tags);
                        break;
                case nua_r_shutdown:
-                       /* break main loop of sofia thread */
-                       su_root_break(sofia_agent->root);
+                       /* if status < 200, shutdown still in progress */
+                       if(status >= 200) {
+                               /* break main loop of sofia thread */
+                               su_root_break(sofia_agent->root);
+                       }
                        break;
                default: 
                        break;
index cb8e112a4a80e746625520ef27beada2f6a191dc..c5f81a22b5a36948c8549c3b203454c5aa674662 100644 (file)
@@ -276,7 +276,8 @@ static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_ses
        nua_respond(sofia_session->nh, SIP_200_OK, 
                                SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
                                TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
-                           NUTAG_AUTOANSWER(0),
+                               SOATAG_AUDIO_AUX("telephone-event"),
+                               NUTAG_AUTOANSWER(0),
                                TAG_END());
        
        return TRUE;
@@ -403,6 +404,7 @@ static void mrcp_sofia_on_resource_discover(mrcp_sofia_agent_t   *sofia_agent,
                                NUTAG_WITH_CURRENT(sofia_agent->nua),
                                SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str),
                                TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)),
+                               SOATAG_AUDIO_AUX("telephone-event"),
                                TAG_END());
 }
 
@@ -427,10 +429,13 @@ static void mrcp_sofia_event_callback( nua_event_t           nua_event,
                        mrcp_sofia_on_resource_discover(sofia_agent,nh,sofia_session,sip,tags);
                        break;
                case nua_r_shutdown:
-                       /* break main loop of sofia thread */
-                       su_root_break(sofia_agent->root);
+                       /* if status < 200, shutdown still in progress */
+                       if(status >= 200) {
+                               /* break main loop of sofia thread */
+                               su_root_break(sofia_agent->root);
+                       }
                        break;
-               default: 
+               default:
                        break;
        }
 }
index 59fbf64e860ad4389da3e918ba25cd82b8f5c5ca..58d35347d0afff782149fac1b496bf3527d94337 100644 (file)
@@ -61,7 +61,7 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_request_generate(
                                                                                        const apr_table_t *resource_map,
                                                                                        apr_pool_t *pool);
 
-/** Generate resource descovery descriptor by RTSP response */
+/** Generate resource discovery descriptor by RTSP response */
 MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_generate(
                                                                                        const rtsp_message_t *request, 
                                                                                        const rtsp_message_t *response,
index f1ea89185a6be868c0521bf98c044422e7cd84bc..e35055fdc9b648c232a27a8fd4c099ca65915d33 100644 (file)
@@ -36,26 +36,33 @@ static apr_size_t sdp_rtp_media_generate(char *buffer, apr_size_t size, const mr
        }
        offset += snprintf(buffer+offset,size-offset,
                "m=audio %d RTP/AVP", 
-               audio_media->base.state == MPF_MEDIA_ENABLED ? audio_media->base.port : 0);
+               audio_media->state == MPF_MEDIA_ENABLED ? audio_media->port : 0);
        for(i=0; i<descriptor_arr->nelts; i++) {
-               codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+               codec_descriptor = &APR_ARRAY_IDX(descriptor_arr,i,mpf_codec_descriptor_t);
                if(codec_descriptor->enabled == TRUE) {
                        offset += snprintf(buffer+offset,size-offset," %d", codec_descriptor->payload_type);
                }
        }
        offset += snprintf(buffer+offset,size-offset,"\r\n");
-       if(audio_media->base.state == MPF_MEDIA_ENABLED) {
-               const apt_str_t *mode_str = mpf_stream_mode_str_get(audio_media->mode);
+       if(audio_media->state == MPF_MEDIA_ENABLED) {
+               const apt_str_t *direction_str = mpf_rtp_direction_str_get(audio_media->direction);
                for(i=0; i<descriptor_arr->nelts; i++) {
-                       codec_descriptor = (mpf_codec_descriptor_t*)descriptor_arr->elts + i;
+                       codec_descriptor = &APR_ARRAY_IDX(descriptor_arr,i,mpf_codec_descriptor_t);
                        if(codec_descriptor->enabled == TRUE && codec_descriptor->name.buf) {
                                offset += snprintf(buffer+offset,size-offset,"a=rtpmap:%d %s/%d\r\n",
                                        codec_descriptor->payload_type,
                                        codec_descriptor->name.buf,
                                        codec_descriptor->sampling_rate);
+                               if(codec_descriptor->format.buf) {
+                                       offset += snprintf(buffer+offset,size-offset,"a=fmtp:%d %s\r\n",
+                                               codec_descriptor->payload_type,
+                                               codec_descriptor->format.buf);
+                               }
                        }
                }
-               offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",mode_str ? mode_str->buf : "");
+               if(direction_str) {
+                       offset += snprintf(buffer+offset,size-offset,"a=%s\r\n",direction_str->buf);
+               }
                
                if(audio_media->ptime) {
                        offset += snprintf(buffer+offset,size-offset,"a=ptime:%hu\r\n",
@@ -98,31 +105,31 @@ static apt_bool_t mpf_rtp_media_generate(mpf_rtp_media_descriptor_t *rtp_media,
 
        switch(sdp_media->m_mode) {
                case sdp_inactive:
-                       rtp_media->mode = STREAM_MODE_NONE;
+                       rtp_media->direction = STREAM_DIRECTION_NONE;
                        break;
                case sdp_sendonly:
-                       rtp_media->mode = STREAM_MODE_SEND;
+                       rtp_media->direction = STREAM_DIRECTION_SEND;
                        break;
                case sdp_recvonly:
-                       rtp_media->mode = STREAM_MODE_RECEIVE;
+                       rtp_media->direction = STREAM_DIRECTION_RECEIVE;
                        break;
                case sdp_sendrecv:
-                       rtp_media->mode = STREAM_MODE_SEND_RECEIVE;
+                       rtp_media->direction = STREAM_DIRECTION_DUPLEX;
                        break;
        }
 
        if(sdp_media->m_connections) {
-               apt_string_assign(&rtp_media->base.ip,sdp_media->m_connections->c_address,pool);
+               apt_string_assign(&rtp_media->ip,sdp_media->m_connections->c_address,pool);
        }
        else {
-               rtp_media->base.ip = *ip;
+               rtp_media->ip = *ip;
        }
        if(sdp_media->m_port) {
-               rtp_media->base.port = (apr_port_t)sdp_media->m_port;
-               rtp_media->base.state = MPF_MEDIA_ENABLED;
+               rtp_media->port = (apr_port_t)sdp_media->m_port;
+               rtp_media->state = MPF_MEDIA_ENABLED;
        }
        else {
-               rtp_media->base.state = MPF_MEDIA_DISABLED;
+               rtp_media->state = MPF_MEDIA_DISABLED;
        }
        return TRUE;
 }
@@ -145,7 +152,7 @@ static mrcp_session_descriptor_t* mrcp_descriptor_generate_by_sdp_session(mrcp_s
                        {
                                mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                                mpf_rtp_media_descriptor_init(media);
-                               media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                               media->id = mrcp_session_audio_media_add(descriptor,media);
                                mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
                                break;
                        }
@@ -153,7 +160,7 @@ static mrcp_session_descriptor_t* mrcp_descriptor_generate_by_sdp_session(mrcp_s
                        {
                                mpf_rtp_media_descriptor_t *media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                                mpf_rtp_media_descriptor_init(media);
-                               media->base.id = mrcp_session_video_media_add(descriptor,media);
+                               media->id = mrcp_session_video_media_add(descriptor,media);
                                mpf_rtp_media_generate(media,sdp_media,&descriptor->ip,pool);
                                break;
                        }
@@ -207,11 +214,11 @@ MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_reques
                        descriptor = mrcp_session_descriptor_create(pool);
                        media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
                        mpf_rtp_media_descriptor_init(media);
-                       media->base.state = MPF_MEDIA_ENABLED;
-                       media->base.id = mrcp_session_audio_media_add(descriptor,media);
+                       media->state = MPF_MEDIA_ENABLED;
+                       media->id = mrcp_session_audio_media_add(descriptor,media);
                        if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) {
-                               media->base.port = request->header.transport.client_port_range.min;
-                               media->base.ip = request->header.transport.destination;
+                               media->port = request->header.transport.client_port_range.min;
+                               media->ip = request->header.transport.destination;
                        }
                }
 
@@ -321,16 +328,16 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_request_generate_by_mrcp_descriptor(const mrc
        count = mrcp_session_media_count_get(descriptor);
        for(i=0; i<count; i++) {
                audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
-               if(audio_media && audio_media->base.id == i) {
+               if(audio_media && audio_media->id == i) {
                        /* generate audio media */
                        audio_index++;
                        offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
-                       request->header.transport.client_port_range.min = audio_media->base.port;
-                       request->header.transport.client_port_range.max = audio_media->base.port+1;
+                       request->header.transport.client_port_range.min = audio_media->port;
+                       request->header.transport.client_port_range.max = audio_media->port+1;
                        continue;
                }
                video_media = mrcp_session_video_media_get(descriptor,video_index);
-               if(video_media && video_media->base.id == i) {
+               if(video_media && video_media->id == i) {
                        /* generate video media */
                        video_index++;
                        offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
@@ -403,17 +410,19 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_response_generate_by_mrcp_descriptor(const rt
                count = mrcp_session_media_count_get(descriptor);
                for(i=0; i<count; i++) {
                        audio_media = mrcp_session_audio_media_get(descriptor,audio_index);
-                       if(audio_media && audio_media->base.id == i) {
+                       if(audio_media && audio_media->id == i) {
                                /* generate audio media */
+                               rtsp_transport_t *transport;
                                audio_index++;
                                offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,audio_media);
-                               response->header.transport.server_port_range.min = audio_media->base.port;
-                               response->header.transport.server_port_range.max = audio_media->base.port+1;
-                               response->header.transport.client_port_range = request->header.transport.client_port_range;
+                               transport = &response->header.transport;
+                               transport->server_port_range.min = audio_media->port;
+                               transport->server_port_range.max = audio_media->port+1;
+                               transport->client_port_range = request->header.transport.client_port_range;
                                continue;
                        }
                        video_media = mrcp_session_video_media_get(descriptor,video_index);
-                       if(video_media && video_media->base.id == i) {
+                       if(video_media && video_media->id == i) {
                                /* generate video media */
                                video_index++;
                                offset += sdp_rtp_media_generate(buffer+offset,size-offset,descriptor,video_media);
@@ -453,7 +462,7 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_request_generate(
        return request;
 }
 
-/** Generate resource descovery descriptor by RTSP response */
+/** Generate resource discovery descriptor by RTSP response */
 MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_generate(
                                                                                        const rtsp_message_t *request, 
                                                                                        const rtsp_message_t *response,
@@ -525,18 +534,15 @@ MRCP_DECLARE(rtsp_message_t*) rtsp_resource_discovery_response_generate(
                        "s=-\r\n"
                        "c=IN IP4 %s\r\n"
                        "t=0 0\r\n"
-                       "m=audio 0 RTP/AVP 0 8\r\n"
+                       "m=audio 0 RTP/AVP 0 8 96 101\r\n"
                        "a=rtpmap:0 PCMU/8000\r\n"
-                       "a=rtpmap:8 PCMA/8000\r\n",
+                       "a=rtpmap:8 PCMA/8000\r\n"
+                       "a=rtpmap:96 L16/8000\r\n"
+                       "a=rtpmap:101 telephone-event/8000\r\n",
                        origin,
                        ip,
                        ip);
                
-               response->header.transport.protocol = RTSP_TRANSPORT_RTP;
-               response->header.transport.profile = RTSP_PROFILE_AVP;
-               response->header.transport.delivery = RTSP_DELIVERY_UNICAST;
-               rtsp_header_property_add(&response->header.property_set,RTSP_HEADER_FIELD_TRANSPORT);
-
                if(offset) {
                        apt_string_assign_n(&response->body,buffer,offset,pool);
                        response->header.content_type = RTSP_CONTENT_TYPE_SDP;
index 12de96a741892b402699cd05f60194b47f522e45..a29a68c1278af2fac18bf6de1463bae120a0202e 100644 (file)
@@ -355,6 +355,9 @@ static apt_bool_t mrcp_unirtsp_on_session_control(mrcp_session_t *mrcp_session,
        else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
                /* send RTSP announce */
                rtsp_message = rtsp_request_create(mrcp_session->pool);
+               rtsp_message->start_line.common.request_line.resource_name = rtsp_name_get_by_mrcp_name(
+                                                                       agent->config->resource_map,
+                                                                       mrcp_message->channel_id.resource_name.buf);
                rtsp_message->start_line.common.request_line.method_id = RTSP_METHOD_ANNOUNCE;
        }
 
index a14c5001d3925d0d26939fe53005c41ff584fe03..98677b46c9bfbfa8b3f422d22fc92122165334ac 100644 (file)
@@ -1,4 +1,4 @@
-#define uni_version "0.6.0"
+#define uni_version "0.8.0"
 
 AppName=UniMRCP
 AppVerName=UniMRCP-{#= uni_version}
index d6ce93d131ce2c7c5b245a17377e601e2eb36182..7d0fb6dfd5d897c81813387a5506a38bc73095a7 100644 (file)
@@ -1,4 +1,6 @@
 MAINTAINERCLEANFILES   = Makefile.in
 
 SUBDIRS                = libunimrcp-server unimrcp-server \
-                         libunimrcp-client unimrcp-client
+                         libunimrcp-client unimrcp-client \
+                         libasr-client asr-client \
+                         umc
diff --git a/libs/unimrcp/platforms/asr-client/Makefile.am b/libs/unimrcp/platforms/asr-client/Makefile.am
new file mode 100644 (file)
index 0000000..02f6a0a
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+INCLUDES               = -Iinclude \
+                         -I$(top_srcdir)/platforms/libasr-client/include \
+                         -I$(top_srcdir)/platforms/libunimrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-signaling/include \
+                         -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                         -I$(top_srcdir)/libs/mrcp/include \
+                         -I$(top_srcdir)/libs/mrcp/message/include \
+                         -I$(top_srcdir)/libs/mrcp/control/include \
+                         -I$(top_srcdir)/libs/mrcp/resources/include \
+                         -I$(top_srcdir)/libs/mpf/include \
+                         -I$(top_srcdir)/libs/apr-toolkit/include \
+                         $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+bin_PROGRAMS           = asrclient
+asrclient_SOURCES      = src/main.c 
+                         
+asrclient_LDADD        = $(top_builddir)/platforms/libasr-client/libasrclient.la
+
+if ISMAC
+asrclient_LDFLAGS      = -framework CoreFoundation -framework SystemConfiguration
+endif
diff --git a/libs/unimrcp/platforms/asr-client/asrclient.vcproj b/libs/unimrcp/platforms/asr-client/asrclient.vcproj
new file mode 100644 (file)
index 0000000..cee6a32
--- /dev/null
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="asrclient"
+       ProjectGUID="{6B83AC6D-01CE-4E1C-81CE-02AD8116C684}"
+       RootNamespace="asrclient"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unidebug.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include;&quot;..\libasr-client\include&quot;"
+                               RuntimeLibrary="3"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libasrclient.lib libapr-1.lib"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unirelease.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include;&quot;..\libasr-client\include&quot;"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="libasrclient.lib libapr-1.lib"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\main.c"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/platforms/asr-client/src/main.c b/libs/unimrcp/platforms/asr-client/src/main.c
new file mode 100644 (file)
index 0000000..0861bf4
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <apr_getopt.h>
+#include <apr_file_info.h>
+#include <apr_thread_proc.h>
+#include "asr_engine.h"
+
+typedef struct {
+       const char        *root_dir_path;
+       apt_log_priority_e log_priority;
+       apt_log_output_e   log_output;
+       apr_pool_t        *pool;
+} client_options_t;
+
+typedef struct {
+       asr_engine_t      *engine;
+       const char        *grammar_file;
+       const char        *input_file;
+       const char        *profile;
+       
+       apr_thread_t      *thread;
+       apr_pool_t        *pool;
+} asr_params_t;
+
+/** Thread function to run ASR scenario in */
+static void* APR_THREAD_FUNC asr_session_run(apr_thread_t *thread, void *data)
+{
+       asr_params_t *params = data;
+       asr_session_t *session = asr_session_create(params->engine,params->profile);
+       if(session) {
+               const char *result = asr_session_recognize(session,params->grammar_file,params->input_file);
+               if(result) {
+                       printf("Recog Result [%s]",result);
+               }
+
+               asr_session_destroy(session);
+       }
+
+       /* destroy pool params allocated from */
+       apr_pool_destroy(params->pool);
+       return NULL;
+}
+
+/** Launch demo ASR session */
+static apt_bool_t asr_session_launch(asr_engine_t *engine, const char *grammar_file, const char *input_file, const char *profile)
+{
+       apr_pool_t *pool;
+       asr_params_t *params;
+       
+       /* create pool to allocate params from */
+       apr_pool_create(&pool,NULL);
+       params = apr_palloc(pool,sizeof(asr_params_t));
+       params->pool = pool;
+       params->engine = engine;
+
+       if(grammar_file) {
+               params->grammar_file = apr_pstrdup(pool,grammar_file);
+       }
+       else {
+               params->grammar_file = "grammar.xml";
+       }
+
+       if(input_file) {
+               params->input_file = apr_pstrdup(pool,input_file);
+       }
+       else {
+               params->input_file = "one-8kHz.pcm";
+       }
+       
+       if(profile) {
+               params->profile = apr_pstrdup(pool,profile);
+       }
+       else {
+               params->profile = "MRCPv2-Default";
+       }
+
+       /* Launch a thread to run demo ASR session in */
+       if(apr_thread_create(&params->thread,NULL,asr_session_run,params,pool) != APR_SUCCESS) {
+               apr_pool_destroy(pool);
+               return FALSE;
+       }
+       
+       return TRUE;
+}
+
+static apt_bool_t cmdline_process(asr_engine_t *engine, char *cmdline)
+{
+       apt_bool_t running = TRUE;
+       char *name;
+       char *last;
+       name = apr_strtok(cmdline, " ", &last);
+
+       if(strcasecmp(name,"run") == 0) {
+               char *grammar = apr_strtok(NULL, " ", &last);
+               char *input = apr_strtok(NULL, " ", &last);
+               char *profile = apr_strtok(NULL, " ", &last);
+               asr_session_launch(engine,grammar,input,profile);
+       }
+       else if(strcasecmp(name,"loglevel") == 0) {
+               char *priority = apr_strtok(NULL, " ", &last);
+               if(priority) {
+                       asr_engine_log_priority_set(atol(priority));
+               }
+       }
+       else if(strcasecmp(name,"exit") == 0 || strcmp(name,"quit") == 0) {
+               running = FALSE;
+       }
+       else if(strcasecmp(name,"help") == 0) {
+               printf("usage:\n"
+                       "\n- run [grammar_file] [audio_input_file] [profile_name] (run demo asr client)\n"
+                       "       grammar_file is the name of grammar file, (path is relative to data dir)\n"
+                       "       audio_input_file is the name of audio file, (path is relative to data dir)\n"
+                       "       profile_name is one of 'MRCPv2-Default', 'MRCPv1-Default', ...\n"
+                       "\n       examples: \n"
+                       "           run\n"
+                       "           run grammar.xml one.pcm\n"
+                       "           run grammar.xml one.pcm MRCPv1-Default\n"
+                   "\n- loglevel [level] (set loglevel, one of 0,1...7)\n"
+                   "\n- quit, exit\n");
+       }
+       else {
+               printf("unknown command: %s (input help for usage)\n",name);
+       }
+       return running;
+}
+
+static apt_bool_t cmdline_run(asr_engine_t *engine)
+{
+       apt_bool_t running = TRUE;
+       char cmdline[1024];
+       int i;
+       do {
+               printf(">");
+               memset(&cmdline, 0, sizeof(cmdline));
+               for(i = 0; i < sizeof(cmdline); i++) {
+                       cmdline[i] = (char) getchar();
+                       if(cmdline[i] == '\n') {
+                               cmdline[i] = '\0';
+                               break;
+                       }
+               }
+               if(*cmdline) {
+                       running = cmdline_process(engine,cmdline);
+               }
+       }
+       while(running != 0);
+       return TRUE;
+}
+
+static void usage()
+{
+       printf(
+               "\n"
+               "Usage:\n"
+               "\n"
+               "  asrclient [options]\n"
+               "\n"
+               "  Available options:\n"
+               "\n"
+               "   -r [--root-dir] path     : Set the project root directory path.\n"
+               "\n"
+               "   -l [--log-prio] priority : Set the log priority.\n"
+               "                              (0-emergency, ..., 7-debug)\n"
+               "\n"
+               "   -o [--log-output] mode   : Set the log output mode.\n"
+               "                              (0-none, 1-console only, 2-file only, 3-both)\n"
+               "\n"
+               "   -h [--help]              : Show the help.\n"
+               "\n");
+}
+
+static void options_destroy(client_options_t *options)
+{
+       if(options->pool) {
+               apr_pool_destroy(options->pool);
+       }
+}
+
+static client_options_t* options_load(int argc, const char * const *argv)
+{
+       apr_status_t rv;
+       apr_getopt_t *opt = NULL;
+       int optch;
+       const char *optarg;
+       apr_pool_t *pool;
+       client_options_t *options;
+
+       const apr_getopt_option_t opt_option[] = {
+               /* long-option, short-option, has-arg flag, description */
+               { "root-dir",    'r', TRUE,  "path to root dir" },  /* -r arg or --root-dir arg */
+               { "log-prio",    'l', TRUE,  "log priority" },      /* -l arg or --log-prio arg */
+               { "log-output",  'o', TRUE,  "log output mode" },   /* -o arg or --log-output arg */
+               { "help",        'h', FALSE, "show help" },         /* -h or --help */
+               { NULL, 0, 0, NULL },                               /* end */
+       };
+
+       /* create APR pool to allocate options from */
+       apr_pool_create(&pool,NULL);
+       if(!pool) {
+               return NULL;
+       }
+       options = apr_palloc(pool,sizeof(client_options_t));
+       options->pool = pool;
+       /* set the default options */
+       options->root_dir_path = "../";
+       options->log_priority = APT_PRIO_INFO;
+       options->log_output = APT_LOG_OUTPUT_CONSOLE;
+
+
+       rv = apr_getopt_init(&opt, pool , argc, argv);
+       if(rv != APR_SUCCESS) {
+               options_destroy(options);
+               return NULL;
+       }
+
+       while((rv = apr_getopt_long(opt, opt_option, &optch, &optarg)) == APR_SUCCESS) {
+               switch(optch) {
+                       case 'r':
+                               options->root_dir_path = optarg;
+                               break;
+                       case 'l':
+                               if(optarg) {
+                                       options->log_priority = atoi(optarg);
+                               }
+                               break;
+                       case 'o':
+                               if(optarg) {
+                                       options->log_output = atoi(optarg);
+                               }
+                               break;
+                       case 'h':
+                               usage();
+                               return FALSE;
+               }
+       }
+
+       if(rv != APR_EOF) {
+               usage();
+               options_destroy(options);
+               return NULL;
+       }
+
+       return options;
+}
+
+int main(int argc, const char * const *argv)
+{
+       client_options_t *options;
+       asr_engine_t *engine;
+
+       /* APR global initialization */
+       if(apr_initialize() != APR_SUCCESS) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* load options */
+       options = options_load(argc,argv);
+       if(!options) {
+               apr_terminate();
+               return 0;
+       }
+
+       /* create asr engine */
+       engine = asr_engine_create(
+                               options->root_dir_path,
+                               options->log_priority,
+                               options->log_output);
+       if(engine) {
+               /* run command line  */
+               cmdline_run(engine);
+               /* destroy demo framework */
+               asr_engine_destroy(engine);
+       }
+
+       /* destroy options */
+       options_destroy(options);
+
+       /* APR global termination */
+       apr_terminate();
+       return 0;
+}
diff --git a/libs/unimrcp/platforms/libasr-client/Makefile.am b/libs/unimrcp/platforms/libasr-client/Makefile.am
new file mode 100644 (file)
index 0000000..468846b
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES       = Makefile.in
+
+INCLUDES                    = -Iinclude \
+                              -I$(top_srcdir)/platforms/libunimrcp-client/include \
+                              -I$(top_srcdir)/libs/mrcp-client/include \
+                              -I$(top_srcdir)/libs/mrcp-signaling/include \
+                              -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                              -I$(top_srcdir)/libs/mrcp/include \
+                              -I$(top_srcdir)/libs/mrcp/message/include \
+                              -I$(top_srcdir)/libs/mrcp/control/include \
+                              -I$(top_srcdir)/libs/mrcp/resources/include \
+                              -I$(top_srcdir)/libs/mpf/include \
+                              -I$(top_srcdir)/libs/apr-toolkit/include \
+                              $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+lib_LTLIBRARIES             = libasrclient.la
+
+include_HEADERS             = include/asr_engine.h
+
+libasrclient_la_SOURCES     = src/asr_engine.c
+
+libasrclient_la_LIBADD      = $(top_builddir)/platforms/libunimrcp-client/libunimrcpclient.la
+                              
+libasrclient_la_LDFLAGS     = $(UNI_LT_VERSION)
diff --git a/libs/unimrcp/platforms/libasr-client/include/asr_engine.h b/libs/unimrcp/platforms/libasr-client/include/asr_engine.h
new file mode 100644 (file)
index 0000000..6a9e62f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#ifndef __ASR_ENGINE_H__
+#define __ASR_ENGINE_H__
+
+/**
+ * @file asr_engine.h
+ * @brief Basic ASR engine on top of UniMRCP client library
+ */ 
+
+#include "apt_log.h"
+
+/** Lib export/import defines (win32) */
+#ifdef WIN32
+#ifdef ASR_CLIENT_STATIC_LIB
+#define ASR_CLIENT_DECLARE(type)   type __stdcall
+#else
+#ifdef ASR_CLIENT_LIB_EXPORT
+#define ASR_CLIENT_DECLARE(type)   __declspec(dllexport) type __stdcall
+#else
+#define ASR_CLIENT_DECLARE(type)   __declspec(dllimport) type __stdcall
+#endif
+#endif
+#else
+#define ASR_CLIENT_DECLARE(type) type
+#endif
+
+APT_BEGIN_EXTERN_C
+
+/** Opaque ASR engine */
+typedef struct asr_engine_t asr_engine_t;
+
+/** Opaque ASR session */
+typedef struct asr_session_t asr_session_t;
+
+
+/**
+ * Create ASR engine.
+ * @param root_dir_path the path to root directory
+ * @param log_priority the log priority level
+ * @param log_output the log output mode
+ */
+ASR_CLIENT_DECLARE(asr_engine_t*) asr_engine_create(
+                                                                       const char *root_dir_path,
+                                                                       apt_log_priority_e log_priority,
+                                                                       apt_log_output_e log_output);
+
+/**
+ * Destroy ASR engine.
+ * @param engine the engine to destroy
+ */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_destroy(asr_engine_t *engine);
+
+
+
+/**
+ * Create ASR session.
+ * @param engine the engine session belongs to
+ * @param profile the name of UniMRCP profile to use
+ */
+ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, const char *profile);
+
+/**
+ * Initiate recognition.
+ * @param session the session to run recognition in the scope of
+ * @param grammar_file the name of the grammar file to use (path is relative to data dir)
+ * @param input_file the name of the audio input file to use (path is relative to data dir)
+ * @return the recognition result (input element of NLSML content)
+ */
+ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *session, const char *grammar_file, const char *input_file);
+
+/**
+ * Destroy ASR session.
+ * @param session the session to destroy
+ */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_session_destroy(asr_session_t *session);
+
+
+/**
+ * Set log priority.
+ * @param priority the priority to set
+ */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_log_priority_set(apt_log_priority_e log_priority);
+
+
+APT_END_EXTERN_C
+
+#endif /*__ASR_ENGINE_H__*/
diff --git a/libs/unimrcp/platforms/libasr-client/libasrclient.vcproj b/libs/unimrcp/platforms/libasr-client/libasrclient.vcproj
new file mode 100644 (file)
index 0000000..98fee3b
--- /dev/null
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="libasrclient"\r
+       ProjectGUID="{272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}"\r
+       RootNamespace="libasrclient"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unidebug.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="include"\r
+                               PreprocessorDefinitions="ASR_CLIENT_LIB_EXPORT"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="$(UniMRCPClientLibs)"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unirelease.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="include"\r
+                               PreprocessorDefinitions="ASR_CLIENT_LIB_EXPORT"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="$(UniMRCPClientLibs)"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="include"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\include\asr_engine.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="src"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\src\asr_engine.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/libs/unimrcp/platforms/libasr-client/src/asr_engine.c b/libs/unimrcp/platforms/libasr-client/src/asr_engine.c
new file mode 100644 (file)
index 0000000..491faaf
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * 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 <stdlib.h>
+
+/* APR includes */
+#include <apr_thread_cond.h>
+#include <apr_thread_proc.h>
+
+/* common includes */
+#include "unimrcp_client.h"
+#include "mrcp_application.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+/* recognizer includes */
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+/* APT includes */
+#include "apt_nlsml_doc.h"
+#include "apt_log.h"
+#include "apt_pool.h"
+
+#include "asr_engine.h"
+
+
+/** ASR engine on top of UniMRCP client stack */
+struct asr_engine_t {
+       /** MRCP client stack */
+       mrcp_client_t      *mrcp_client;
+       /** MRCP client stack */
+       mrcp_application_t *mrcp_app;
+       /** Memory pool */
+       apr_pool_t         *pool;
+};
+
+
+/** ASR session on top of UniMRCP session/channel */
+struct asr_session_t {
+       /** Back pointer to engine */
+       asr_engine_t       *engine;
+       /** MRCP session */
+       mrcp_session_t     *mrcp_session;
+       /** MRCP channel */
+       mrcp_channel_t     *mrcp_channel;
+       /** RECOGNITION-COMPLETE message  */
+       mrcp_message_t     *recog_complete;
+
+       /** File to read audio stream from */
+       FILE               *audio_in;
+       /** Streaming is in-progress */
+       apt_bool_t          streaming;
+
+       /** Conditional wait object */
+       apr_thread_cond_t  *wait_object;
+       /** Mutex of the wait object */
+       apr_thread_mutex_t *mutex;
+
+       /** Message sent from client stack */
+       const mrcp_app_message_t *app_message;
+};
+
+
+/** Declaration of recognizer audio stream methods */
+static apt_bool_t asr_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       NULL,
+       NULL,
+       NULL,
+       asr_stream_read,
+       NULL,
+       NULL,
+       NULL
+};
+
+static apt_bool_t app_message_handler(const mrcp_app_message_t *app_message);
+
+
+/** Create ASR engine */
+ASR_CLIENT_DECLARE(asr_engine_t*) asr_engine_create(
+                                                                       const char *root_dir_path,
+                                                                       apt_log_priority_e log_priority,
+                                                                       apt_log_output_e log_output)
+{
+       apr_pool_t *pool = NULL;
+       apt_dir_layout_t *dir_layout;
+       asr_engine_t *engine;
+       mrcp_client_t *mrcp_client;
+       mrcp_application_t *mrcp_app;
+
+       /* create APR pool */
+       pool = apt_pool_create();
+       if(!pool) {
+               return NULL;
+       }
+
+       /* create the structure of default directories layout */
+       dir_layout = apt_default_dir_layout_create(root_dir_path,pool);
+       /* create singleton logger */
+       apt_log_instance_create(log_output,log_priority,pool);
+
+       if((log_output & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) {
+               /* open the log file */
+               apt_log_file_open(dir_layout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool);
+       }
+
+       engine = apr_palloc(pool,sizeof(asr_engine_t));
+       engine->pool = pool;
+       engine->mrcp_client = NULL;
+       engine->mrcp_app = NULL;
+
+       /* create UniMRCP client stack */
+       mrcp_client = unimrcp_client_create(dir_layout);
+       if(!mrcp_client) {
+               apt_log_instance_destroy();
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+       
+       /* create an application */
+       mrcp_app = mrcp_application_create(
+                                                               app_message_handler,
+                                                               engine,
+                                                               pool);
+       if(!mrcp_app) {
+               mrcp_client_destroy(mrcp_client);
+               apt_log_instance_destroy();
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       /* register application in client stack */
+       mrcp_client_application_register(mrcp_client,mrcp_app,"ASRAPP");
+
+       /* start client stack */
+       if(mrcp_client_start(mrcp_client) != TRUE) {
+               mrcp_client_destroy(mrcp_client);
+               apt_log_instance_destroy();
+               apr_pool_destroy(pool);
+               return NULL;
+       }
+
+       engine->mrcp_client = mrcp_client;
+       engine->mrcp_app = mrcp_app;
+       return engine;
+}
+
+/** Destroy ASR engine */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_destroy(asr_engine_t *engine)
+{
+       if(engine->mrcp_client) {
+               /* shutdown client stack */
+               mrcp_client_shutdown(engine->mrcp_client);
+               /* destroy client stack */
+               mrcp_client_destroy(engine->mrcp_client);
+               engine->mrcp_client = NULL;
+               engine->mrcp_app = NULL;
+       }
+
+       /* destroy singleton logger */
+       apt_log_instance_destroy();
+       /* destroy APR pool */
+       apr_pool_destroy(engine->pool);
+       return TRUE;
+}
+
+
+
+/** Destroy ASR session */
+static apt_bool_t asr_session_destroy_ex(asr_session_t *asr_session, apt_bool_t terminate)
+{
+       if(terminate == TRUE) {
+               apr_thread_mutex_lock(asr_session->mutex);
+               if(mrcp_application_session_terminate(asr_session->mrcp_session) == TRUE) {
+                       apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex);
+                       /* the response must be checked to be the valid one */
+               }
+               apr_thread_mutex_unlock(asr_session->mutex);
+       }
+
+       if(asr_session->audio_in) {
+               fclose(asr_session->audio_in);
+               asr_session->audio_in = NULL;
+       }
+
+       if(asr_session->mutex) {
+               apr_thread_mutex_destroy(asr_session->mutex);
+               asr_session->mutex = NULL;
+       }
+       if(asr_session->wait_object) {
+               apr_thread_cond_destroy(asr_session->wait_object);
+               asr_session->wait_object = NULL;
+       }
+       if(asr_session->mrcp_session) {
+               mrcp_application_session_destroy(asr_session->mrcp_session);
+               asr_session->mrcp_session = NULL;
+       }
+       free(asr_session);
+       return TRUE;
+}
+
+/** Open audio input file */
+static apt_bool_t asr_input_file_open(asr_session_t *asr_session, const char *input_file)
+{
+       const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(asr_session->engine->mrcp_app);
+       apr_pool_t *pool = mrcp_application_session_pool_get(asr_session->mrcp_session);
+       char *input_file_path = apt_datadir_filepath_get(dir_layout,input_file,pool);
+       if(!input_file_path) {
+               return FALSE;
+       }
+       
+       if(asr_session->audio_in) {
+               fclose(asr_session->audio_in);
+               asr_session->audio_in = NULL;
+       }
+
+       asr_session->audio_in = fopen(input_file_path,"rb");
+       if(!asr_session->audio_in) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Open [%s]",input_file_path);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/** MPF callback to read audio frame */
+static apt_bool_t asr_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame)
+{
+       asr_session_t *asr_session = stream->obj;
+       if(asr_session && asr_session->streaming == TRUE) {
+               if(asr_session->audio_in) {
+                       if(fread(frame->codec_frame.buffer,1,frame->codec_frame.size,asr_session->audio_in) == frame->codec_frame.size) {
+                               /* normal read */
+                               frame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       }
+                       else {
+                               /* file is over */
+                               asr_session->streaming = FALSE;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+/** Create DEFINE-GRAMMAR request */
+static mrcp_message_t* define_grammar_message_create(asr_session_t *asr_session, const char *grammar_file)
+{
+       /* create MRCP message */
+       mrcp_message_t *mrcp_message = mrcp_application_message_create(
+                                               asr_session->mrcp_session,
+                                               asr_session->mrcp_channel,
+                                               RECOGNIZER_DEFINE_GRAMMAR);
+       if(mrcp_message) {
+               mrcp_generic_header_t *generic_header;
+
+               /* set message body */
+               const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(asr_session->engine->mrcp_app);
+               apr_pool_t *pool = mrcp_application_session_pool_get(asr_session->mrcp_session);
+               char *grammar_file_path = apt_datadir_filepath_get(dir_layout,grammar_file,pool);
+               if(grammar_file_path) {
+                       char text[1024];
+                       apr_size_t size;
+                       FILE *grammar = fopen(grammar_file_path,"r");
+                       if(!grammar) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot Open [%s]",grammar_file_path);
+                               return NULL;
+                       }
+
+                       size = fread(text,1,sizeof(text),grammar);
+                       apt_string_assign_n(&mrcp_message->body,text,size,mrcp_message->pool);
+                       fclose(grammar);
+               }
+
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(mrcp_message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       if(mrcp_message->start_line.version == MRCP_VERSION_2) {
+                               apt_string_assign(&generic_header->content_type,"application/srgs+xml",mrcp_message->pool);
+                       }
+                       else {
+                               apt_string_assign(&generic_header->content_type,"application/grammar+xml",mrcp_message->pool);
+                       }
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE);
+                       apt_string_assign(&generic_header->content_id,"demo-grammar",mrcp_message->pool);
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_ID);
+               }
+       }
+       return mrcp_message;
+}
+
+/** Create RECOGNIZE request */
+static mrcp_message_t* recognize_message_create(asr_session_t *asr_session)
+{
+       /* create MRCP message */
+       mrcp_message_t *mrcp_message = mrcp_application_message_create(
+                                                                               asr_session->mrcp_session,
+                                                                               asr_session->mrcp_channel,
+                                                                               RECOGNIZER_RECOGNIZE);
+       if(mrcp_message) {
+               mrcp_recog_header_t *recog_header;
+               mrcp_generic_header_t *generic_header;
+               /* get/allocate generic header */
+               generic_header = mrcp_generic_header_prepare(mrcp_message);
+               if(generic_header) {
+                       /* set generic header fields */
+                       apt_string_assign(&generic_header->content_type,"text/uri-list",mrcp_message->pool);
+                       mrcp_generic_header_property_add(mrcp_message,GENERIC_HEADER_CONTENT_TYPE);
+                       /* set message body */
+                       apt_string_assign(&mrcp_message->body,"session:demo-grammar",mrcp_message->pool);
+               }
+               /* get/allocate recognizer header */
+               recog_header = mrcp_resource_header_prepare(mrcp_message);
+               if(recog_header) {
+                       if(mrcp_message->start_line.version == MRCP_VERSION_2) {
+                               /* set recognizer header fields */
+                               recog_header->cancel_if_queue = FALSE;
+                               mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_CANCEL_IF_QUEUE);
+                       }
+                       recog_header->no_input_timeout = 5000;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT);
+                       recog_header->recognition_timeout = 10000;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_RECOGNITION_TIMEOUT);
+                       recog_header->start_input_timers = TRUE;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_START_INPUT_TIMERS);
+                       recog_header->confidence_threshold = 0.87f;
+                       mrcp_resource_header_property_add(mrcp_message,RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD);
+               }
+       }
+       return mrcp_message;
+}
+
+/** Get NLSML input result */
+static const char* nlsml_input_get(mrcp_message_t *message)
+{
+       apr_xml_elem *interpret;
+       apr_xml_elem *instance;
+       apr_xml_elem *input;
+       apr_xml_doc *doc = nlsml_doc_load(&message->body,message->pool);
+       if(!doc) {
+               return NULL;
+       }
+       
+       /* get interpreted result */
+       interpret = nlsml_first_interpret_get(doc);
+       if(!interpret) {
+               return NULL;
+       }
+       /* get instance and input */
+       nlsml_interpret_results_get(interpret,&instance,&input);
+       if(!input || !input->first_cdata.first) {
+               return NULL;
+       }
+       
+       /* return input */
+       return input->first_cdata.first->text;
+}
+
+
+/** Application message handler */
+static apt_bool_t app_message_handler(const mrcp_app_message_t *app_message)
+{
+       if((app_message->message_type == MRCP_APP_MESSAGE_TYPE_SIGNALING && 
+               app_message->sig_message.message_type == MRCP_SIG_MESSAGE_TYPE_RESPONSE) ||
+               app_message->message_type == MRCP_APP_MESSAGE_TYPE_CONTROL) {
+
+               asr_session_t *asr_session = mrcp_application_session_object_get(app_message->session);
+               if(asr_session) {
+                       apr_thread_mutex_lock(asr_session->mutex);
+                       asr_session->app_message = app_message;
+                       apr_thread_cond_signal(asr_session->wait_object);
+                       apr_thread_mutex_unlock(asr_session->mutex);
+               }
+       }
+       return TRUE;
+}
+
+/** Check signaling response */
+static apt_bool_t sig_response_check(const mrcp_app_message_t *app_message)
+{
+       if(!app_message || app_message->message_type != MRCP_APP_MESSAGE_TYPE_SIGNALING) {
+               return FALSE;
+       }
+
+       return (app_message->sig_message.status == MRCP_SIG_STATUS_CODE_SUCCESS) ? TRUE : FALSE;
+}
+
+/** Check MRCP response */
+static apt_bool_t mrcp_response_check(const mrcp_app_message_t *app_message, mrcp_request_state_e state)
+{
+       mrcp_message_t *mrcp_message = NULL;
+       if(app_message && app_message->message_type == MRCP_APP_MESSAGE_TYPE_CONTROL) {
+               mrcp_message = app_message->control_message;
+       }
+
+       if(!mrcp_message || mrcp_message->start_line.message_type != MRCP_MESSAGE_TYPE_RESPONSE ) {
+               return FALSE;
+       }
+       return (mrcp_message->start_line.request_state == state) ? TRUE : FALSE;
+}
+
+/** Get MRCP event */
+static mrcp_message_t* mrcp_event_get(const mrcp_app_message_t *app_message)
+{
+       mrcp_message_t *mrcp_message = NULL;
+       if(app_message && app_message->message_type == MRCP_APP_MESSAGE_TYPE_CONTROL) {
+               mrcp_message = app_message->control_message;
+       }
+
+       if(!mrcp_message || mrcp_message->start_line.message_type != MRCP_MESSAGE_TYPE_EVENT) {
+               return NULL;
+       }
+       return mrcp_message;
+}
+
+/** Create ASR session */
+ASR_CLIENT_DECLARE(asr_session_t*) asr_session_create(asr_engine_t *engine, const char *profile)
+{
+       mpf_termination_t *termination;
+       mrcp_channel_t *channel;
+       mrcp_session_t *session;
+       const mrcp_app_message_t *app_message;
+       apr_pool_t *pool;
+
+       asr_session_t *asr_session = malloc(sizeof(asr_session_t));
+
+       /* create session */
+       session = mrcp_application_session_create(engine->mrcp_app,profile,asr_session);
+       if(!session) {
+               free(asr_session);
+               return NULL;
+       }
+       pool = mrcp_application_session_pool_get(session);
+       
+       termination = mrcp_application_source_termination_create(
+                       session,                   /* session, termination belongs to */
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       NULL,                      /* codec descriptor of audio stream (NULL by default) */
+                       asr_session);              /* object to associate */
+       
+       channel = mrcp_application_channel_create(
+                       session,                   /* session, channel belongs to */
+                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                       termination,               /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       asr_session);              /* object to associate */
+
+       if(!channel) {
+               mrcp_application_session_destroy(session);
+               free(asr_session);
+               return NULL;
+       }
+       
+       asr_session->engine = engine;
+       asr_session->mrcp_session = session;
+       asr_session->mrcp_channel = channel;
+       asr_session->recog_complete = NULL;
+       asr_session->streaming = FALSE;
+       asr_session->audio_in = NULL;
+       asr_session->mutex = NULL;
+       asr_session->wait_object = NULL;
+       asr_session->app_message = NULL;
+
+       /* Create cond wait object and mutex */
+       apr_thread_mutex_create(&asr_session->mutex,APR_THREAD_MUTEX_DEFAULT,pool);
+       apr_thread_cond_create(&asr_session->wait_object,pool);
+
+       /* Send add channel request and wait for the response */
+       apr_thread_mutex_lock(asr_session->mutex);
+       app_message = NULL;
+       if(mrcp_application_channel_add(asr_session->mrcp_session,asr_session->mrcp_channel) == TRUE) {
+               apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex);
+               app_message = asr_session->app_message;
+               asr_session->app_message = NULL;
+       }
+       apr_thread_mutex_unlock(asr_session->mutex);
+
+       if(sig_response_check(app_message) == FALSE) {
+               asr_session_destroy_ex(asr_session,TRUE);
+               return NULL;
+       }
+       return asr_session;
+}
+
+/** Initiate recognition */
+ASR_CLIENT_DECLARE(const char*) asr_session_recognize(asr_session_t *asr_session, const char *grammar_file, const char *input_file)
+{
+       const mrcp_app_message_t *app_message;
+       mrcp_message_t *mrcp_message;
+
+       app_message = NULL;
+       mrcp_message = define_grammar_message_create(asr_session,grammar_file);
+       if(!mrcp_message) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create DEFINE-GRAMMAR Request");
+               return NULL;
+       }
+
+       /* Send DEFINE-GRAMMAR request and wait for the response */
+       apr_thread_mutex_lock(asr_session->mutex);
+       if(mrcp_application_message_send(asr_session->mrcp_session,asr_session->mrcp_channel,mrcp_message) == TRUE) {
+               apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex);
+               app_message = asr_session->app_message;
+               asr_session->app_message = NULL;
+       }
+       apr_thread_mutex_unlock(asr_session->mutex);
+
+       if(mrcp_response_check(app_message,MRCP_REQUEST_STATE_COMPLETE) == FALSE) {
+               return NULL;
+       }
+
+       /* Reset prev recog result (if any) */
+       asr_session->recog_complete = NULL;
+
+       app_message = NULL;
+       mrcp_message = recognize_message_create(asr_session);
+       if(!mrcp_message) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create RECOGNIZE Request");
+               return NULL;
+       }
+
+       /* Send RECOGNIZE request and wait for the response */
+       apr_thread_mutex_lock(asr_session->mutex);
+       if(mrcp_application_message_send(asr_session->mrcp_session,asr_session->mrcp_channel,mrcp_message) == TRUE) {
+               apr_thread_cond_wait(asr_session->wait_object,asr_session->mutex);
+               app_message = asr_session->app_message;
+               asr_session->app_message = NULL;
+       }
+       apr_thread_mutex_unlock(asr_session->mutex);
+
+       if(mrcp_response_check(app_message,MRCP_REQUEST_STATE_INPROGRESS) == FALSE) {
+               return NULL;
+       }
+       
+       /* Open input file and start streaming */
+       if(asr_input_file_open(asr_session,input_file) == FALSE) {
+               return NULL;
+       }
+       asr_session->streaming = TRUE;
+
+       /* Wait for events either START-OF-INPUT or RECOGNITION-COMPLETE */
+       do {
+               apr_thread_mutex_lock(asr_session->mutex);
+               app_message = NULL;
+               if(apr_thread_cond_timedwait(asr_session->wait_object,asr_session->mutex, 60 * 1000000) != APR_SUCCESS) {
+                       apr_thread_mutex_unlock(asr_session->mutex);
+                       return NULL;
+               }
+               app_message = asr_session->app_message;
+               asr_session->app_message = NULL;
+               apr_thread_mutex_unlock(asr_session->mutex);
+
+               mrcp_message = mrcp_event_get(app_message);
+               if(mrcp_message && mrcp_message->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) {
+                       asr_session->recog_complete = mrcp_message;
+               }
+       }
+       while(!asr_session->recog_complete);
+
+       /* Get results */
+       return nlsml_input_get(asr_session->recog_complete);
+}
+
+/** Destroy ASR session */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_session_destroy(asr_session_t *asr_session)
+{
+       return asr_session_destroy_ex(asr_session,TRUE);
+}
+
+/** Set log priority */
+ASR_CLIENT_DECLARE(apt_bool_t) asr_engine_log_priority_set(apt_log_priority_e log_priority)
+{
+       return apt_log_priority_set(log_priority);
+}
index a21f667de3a820dbf7d70aa043f1a0a64b8a5ed0..f1cbd3fe576602f6c511f53d10044f0db12c7ffd 100644 (file)
@@ -29,6 +29,6 @@ libunimrcpclient_la_LIBADD  = $(top_builddir)/modules/mrcp-sofiasip/libmrcpsofia
                               $(top_builddir)/libs/mrcp/libmrcp.la \
                               $(top_builddir)/libs/mpf/libmpf.la \
                               $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
-                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS)
+                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS) -lm
                               
 libunimrcpclient_la_LDFLAGS = $(UNI_LT_VERSION)
index e3f945a5dd46128d8ffdd9246ac2ab319fd550f5..d159582886ea70eb0f662bd02daa923cb382e1b1 100644 (file)
@@ -18,7 +18,7 @@
 #include <apr_xml.h>
 #include "unimrcp_client.h"
 #include "uni_version.h"
-#include "mrcp_default_factory.h"
+#include "mrcp_resource_loader.h"
 #include "mpf_engine.h"
 #include "mpf_codec_manager.h"
 #include "mpf_rtp_termination_factory.h"
@@ -52,8 +52,6 @@ MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout)
 {
        apr_pool_t *pool;
        apr_xml_doc *doc;
-       mrcp_resource_factory_t *resource_factory;
-       mpf_codec_manager_t *codec_manager;
        mrcp_client_t *client;
 
        if(!dir_layout) {
@@ -71,16 +69,6 @@ MRCP_DECLARE(mrcp_client_t*) unimrcp_client_create(apt_dir_layout_t *dir_layout)
                return NULL;
        }
 
-       resource_factory = mrcp_default_factory_create(pool);
-       if(resource_factory) {
-               mrcp_client_resource_factory_register(client,resource_factory);
-       }
-
-       codec_manager = mpf_engine_codec_manager_create(pool);
-       if(codec_manager) {
-               mrcp_client_codec_manager_register(client,codec_manager);
-       }
-
        doc = unimrcp_client_config_parse(dir_layout->conf_dir_path,pool);
        if(doc) {
                unimrcp_client_config_load(client,doc,pool);
@@ -118,7 +106,7 @@ static apr_xml_doc* unimrcp_client_config_parse(const char *dir_path, apr_pool_t
        rv = apr_xml_parse_file(pool,&parser,&doc,fd,XML_FILE_BUFFER_LENGTH);
        if(rv != APR_SUCCESS) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",file_path);
-               return NULL;
+               doc = NULL;
        }
 
        apr_file_close(fd);
@@ -419,6 +407,18 @@ static mpf_termination_factory_t* unimrcp_client_rtp_factory_load(mrcp_client_t
                                else if(strcasecmp(attr_name->value,"ptime") == 0) {
                                        rtp_config->ptime = (apr_uint16_t)atol(attr_value->value);
                                }
+                               else if(strcasecmp(attr_name->value,"rtcp") == 0) {
+                                       rtp_config->rtcp = atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-bye") == 0) {
+                                       rtp_config->rtcp_bye_policy = atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-tx-interval") == 0) {
+                                       rtp_config->rtcp_tx_interval = (apr_uint16_t)atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-rx-resolution") == 0) {
+                                       rtp_config->rtcp_rx_resolution = (apr_uint16_t)atol(attr_value->value);
+                               }
                                else {
                                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
                                }
@@ -436,22 +436,33 @@ static mpf_termination_factory_t* unimrcp_client_rtp_factory_load(mrcp_client_t
 static apt_bool_t unimrcp_client_media_engines_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
 {
        const apr_xml_elem *elem;
+
+       /* create codec manager first */
+       mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(pool);
+       if(codec_manager) {
+               mrcp_client_codec_manager_register(client,codec_manager);
+       }
+
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines");
        for(elem = root->first_child; elem; elem = elem->next) {
                if(strcasecmp(elem->name,"engine") == 0) {
                        mpf_engine_t *media_engine;
+                       unsigned long rate = 1;
                        const char *name = NULL;
                        const apr_xml_attr *attr;
                        for(attr = elem->attr; attr; attr = attr->next) {
                                if(strcasecmp(attr->name,"name") == 0) {
                                        name = apr_pstrdup(pool,attr->value);
                                }
+                               else if(strcasecmp(attr->name,"rate") == 0) {
+                                       rate = atol(attr->value);
+                               }
                                else {
                                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
                                }
                        }
                        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine");
-                       media_engine = mpf_engine_create(pool);
+                       media_engine = mpf_engine_create(rate,pool);
                        if(media_engine) {
                                mrcp_client_media_engine_register(client,media_engine,name);
                        }
@@ -480,6 +491,57 @@ static apt_bool_t unimrcp_client_media_engines_load(mrcp_client_t *client, const
        return TRUE;
 }
 
+/** Load resource */
+static apt_bool_t unimrcp_client_resource_load(mrcp_client_t *client, mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       apt_str_t resource_class;
+       apt_bool_t resource_enabled = TRUE;
+       const apr_xml_attr *attr;
+       apt_string_reset(&resource_class);
+       for(attr = root->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"class") == 0) {
+                       apt_string_set(&resource_class,attr->value);
+               }
+               else if(strcasecmp(attr->name,"enable") == 0) {
+                       resource_enabled = atoi(attr->value);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+               }
+       }
+
+       if(!resource_class.buf || !resource_enabled) {
+               return FALSE;
+       }
+
+       return mrcp_resource_load(resource_loader,&resource_class);
+}
+
+/** Load resources */
+static apt_bool_t unimrcp_client_resources_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       mrcp_resource_factory_t *resource_factory;
+       mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,pool);
+       if(!resource_loader) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"resource") == 0) {
+                       unimrcp_client_resource_load(client,resource_loader,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       
+       resource_factory = mrcp_resource_factory_get(resource_loader);
+       mrcp_client_resource_factory_register(client,resource_factory);
+       return TRUE;
+}
+
 /** Load settings */
 static apt_bool_t unimrcp_client_settings_load(mrcp_client_t *client, const apr_xml_elem *root, apr_pool_t *pool)
 {
@@ -582,7 +644,10 @@ static apt_bool_t unimrcp_client_config_load(mrcp_client_t *client, const apr_xm
                return FALSE;
        }
        for(elem = root->first_child; elem; elem = elem->next) {
-               if(strcasecmp(elem->name,"settings") == 0) {
+               if(strcasecmp(elem->name,"resources") == 0) {
+                       unimrcp_client_resources_load(client,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"settings") == 0) {
                        unimrcp_client_settings_load(client,elem,pool);
                }
                else if(strcasecmp(elem->name,"profiles") == 0) {
index a67510ee4921c3b6916aa89690da940766622ac3..b20402b015dfa7c1aa39b848c8037e2c14811ebd 100644 (file)
@@ -31,6 +31,6 @@ libunimrcpserver_la_LIBADD  = $(top_builddir)/modules/mrcp-sofiasip/libmrcpsofia
                               $(top_builddir)/libs/mrcp/libmrcp.la \
                               $(top_builddir)/libs/mpf/libmpf.la \
                               $(top_builddir)/libs/apr-toolkit/libaprtoolkit.la \
-                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS)
+                              $(UNIMRCP_APR_LIBS) $(UNIMRCP_APU_LIBS) $(UNIMRCP_SOFIA_LIBS) -lm
 
 libunimrcpserver_la_LDFLAGS = $(UNI_LT_VERSION)
index 46d3ef4059fe4391d65730b42291aa6ca24fd4f4..bf51ef16b0866dcb44596943ff1b4049bdcfbebc 100644 (file)
@@ -18,7 +18,7 @@
 #include <apr_xml.h>
 #include "unimrcp_server.h"
 #include "uni_version.h"
-#include "mrcp_default_factory.h"
+#include "mrcp_resource_loader.h"
 #include "mpf_engine.h"
 #include "mpf_codec_manager.h"
 #include "mpf_rtp_termination_factory.h"
@@ -57,8 +57,6 @@ MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout)
 {
        apr_pool_t *pool;
        apr_xml_doc *doc;
-       mrcp_resource_factory_t *resource_factory;
-       mpf_codec_manager_t *codec_manager;
        mrcp_server_t *server;
 
        if(!dir_layout) {
@@ -76,16 +74,6 @@ MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout)
                return NULL;
        }
 
-       resource_factory = mrcp_default_factory_create(pool);
-       if(resource_factory) {
-               mrcp_server_resource_factory_register(server,resource_factory);
-       }
-
-       codec_manager = mpf_engine_codec_manager_create(pool);
-       if(codec_manager) {
-               mrcp_server_codec_manager_register(server,codec_manager);
-       }
-
        doc = unimrcp_server_config_parse(dir_layout->conf_dir_path,pool);
        if(doc) {
                unimrcp_server_config_load(server,dir_layout->plugin_dir_path,doc,pool);
@@ -134,7 +122,7 @@ static apr_xml_doc* unimrcp_server_config_parse(const char *dir_path, apr_pool_t
        rv = apr_xml_parse_file(pool,&parser,&doc,fd,XML_FILE_BUFFER_LENGTH);
        if(rv != APR_SUCCESS) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",file_path);
-               return NULL;
+               doc = NULL;
        }
 
        apr_file_close(fd);
@@ -452,6 +440,18 @@ static mpf_termination_factory_t* unimrcp_server_rtp_factory_load(mrcp_server_t
                                else if(strcasecmp(attr_name->value,"own-preference") == 0) {
                                        rtp_config->own_preferrence = atoi(attr_value->value);
                                }
+                               else if(strcasecmp(attr_name->value,"rtcp") == 0) {
+                                       rtp_config->rtcp = atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-bye") == 0) {
+                                       rtp_config->rtcp_bye_policy = atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-tx-interval") == 0) {
+                                       rtp_config->rtcp_tx_interval = (apr_uint16_t)atoi(attr_value->value);
+                               }
+                               else if(strcasecmp(attr_name->value,"rtcp-rx-resolution") == 0) {
+                                       rtp_config->rtcp_rx_resolution = (apr_uint16_t)atol(attr_value->value);
+                               }
                                else {
                                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr_name->value);
                                }
@@ -469,22 +469,33 @@ static mpf_termination_factory_t* unimrcp_server_rtp_factory_load(mrcp_server_t
 static apt_bool_t unimrcp_server_media_engines_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
 {
        const apr_xml_elem *elem;
+
+       /* create codec manager first */
+       mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(pool);
+       if(codec_manager) {
+               mrcp_server_codec_manager_register(server,codec_manager);
+       }
+
        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engines");
        for(elem = root->first_child; elem; elem = elem->next) {
                if(strcasecmp(elem->name,"engine") == 0) {
                        mpf_engine_t *media_engine;
+                       unsigned long rate = 1;
                        const char *name = NULL;
                        const apr_xml_attr *attr;
                        for(attr = elem->attr; attr; attr = attr->next) {
                                if(strcasecmp(attr->name,"name") == 0) {
                                        name = apr_pstrdup(pool,attr->value);
                                }
+                               else if(strcasecmp(attr->name,"rate") == 0) {
+                                       rate = atol(attr->value);
+                               }
                                else {
                                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
                                }
                        }
                        apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine");
-                       media_engine = mpf_engine_create(pool);
+                       media_engine = mpf_engine_create(rate,pool);
                        if(media_engine) {
                                mrcp_server_media_engine_register(server,media_engine,name);
                        }
@@ -513,18 +524,70 @@ static apt_bool_t unimrcp_server_media_engines_load(mrcp_server_t *server, const
        return TRUE;
 }
 
+/** Load resource */
+static apt_bool_t unimrcp_server_resource_load(mrcp_server_t *server, mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       apt_str_t resource_class;
+       apt_bool_t resource_enabled = TRUE;
+       const apr_xml_attr *attr;
+       apt_string_reset(&resource_class);
+       for(attr = root->attr; attr; attr = attr->next) {
+               if(strcasecmp(attr->name,"class") == 0) {
+                       apt_string_set(&resource_class,attr->value);
+               }
+               else if(strcasecmp(attr->name,"enable") == 0) {
+                       resource_enabled = atoi(attr->value);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
+               }
+       }
+
+       if(!resource_class.buf || !resource_enabled) {
+               return FALSE;
+       }
+
+       return mrcp_resource_load(resource_loader,&resource_class);
+}
+
+/** Load resources */
+static apt_bool_t unimrcp_server_resources_load(mrcp_server_t *server, const apr_xml_elem *root, apr_pool_t *pool)
+{
+       const apr_xml_elem *elem;
+       mrcp_resource_factory_t *resource_factory;
+       mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,pool);
+       if(!resource_loader) {
+               return FALSE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources");
+       for(elem = root->first_child; elem; elem = elem->next) {
+               if(strcasecmp(elem->name,"resource") == 0) {
+                       unimrcp_server_resource_load(server,resource_loader,elem,pool);
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name);
+               }
+       }    
+       
+       resource_factory = mrcp_resource_factory_get(resource_loader);
+       mrcp_server_resource_factory_register(server,resource_factory);
+       return TRUE;
+}
+
 /** Load plugin */
 static apt_bool_t unimrcp_server_plugin_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_elem *root, apr_pool_t *pool)
 {
-       const char *plugin_name = NULL;
+       mrcp_engine_config_t *config;
        const char *plugin_class = NULL;
        const char *plugin_ext = NULL;
        const char *plugin_path = NULL;
        apt_bool_t plugin_enabled = TRUE;
        const apr_xml_attr *attr;
+       config = mrcp_engine_config_alloc(pool);
        for(attr = root->attr; attr; attr = attr->next) {
                if(strcasecmp(attr->name,"name") == 0) {
-                       plugin_name = apr_pstrdup(pool,attr->value);
+                       config->name = apr_pstrdup(pool,attr->value);
                }
                else if(strcasecmp(attr->name,"class") == 0) {
                        plugin_class = attr->value;
@@ -535,6 +598,9 @@ static apt_bool_t unimrcp_server_plugin_load(mrcp_server_t *server, const char *
                else if(strcasecmp(attr->name,"enable") == 0) {
                        plugin_enabled = atoi(attr->value);
                }
+               else if(strcasecmp(attr->name,"max-channel-count") == 0) {
+                       config->max_channel_count = atol(attr->value);
+               }
                else {
                        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name);
                }
@@ -557,14 +623,31 @@ static apt_bool_t unimrcp_server_plugin_load(mrcp_server_t *server, const char *
                plugin_path = apr_psprintf(pool,"%s/%s.%s",plugin_dir_path,plugin_class,plugin_ext);
        }
 
-       return mrcp_server_plugin_register(server,plugin_path,plugin_name);
+       /* load optional name/value params */
+       if(root->first_child){
+               const apr_xml_attr *attr_name;
+               const apr_xml_attr *attr_value;
+               const apr_xml_elem *elem;
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Engine Params");
+               config->params = apr_table_make(pool,1);
+               for(elem = root->first_child; elem; elem = elem->next) {
+                       if(strcasecmp(elem->name,"param") == 0) {
+                               if(param_name_value_get(elem,&attr_name,&attr_value) == TRUE) {
+                                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value);
+                                       apr_table_set(config->params,attr_name->value,attr_value->value);
+                               }
+                       }
+               }
+       }
+
+       return mrcp_server_plugin_register(server,plugin_path,config);
 }
 
 /** Load plugins */
 static apt_bool_t unimrcp_server_plugins_load(mrcp_server_t *server, const char *plugin_dir_path, const apr_xml_elem *root, apr_pool_t *pool)
 {
        const apr_xml_elem *elem;
-       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugins (Resource Engines)");
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Engine Plugins");
        for(elem = root->first_child; elem; elem = elem->next) {
                if(strcasecmp(elem->name,"engine") == 0) {
                        unimrcp_server_plugin_load(server,plugin_dir_path,elem,pool);
@@ -687,7 +770,10 @@ static apt_bool_t unimrcp_server_config_load(mrcp_server_t *server, const char *
                return FALSE;
        }
        for(elem = root->first_child; elem; elem = elem->next) {
-               if(strcasecmp(elem->name,"settings") == 0) {
+               if(strcasecmp(elem->name,"resources") == 0) {
+                       unimrcp_server_resources_load(server,elem,pool);
+               }
+               else if(strcasecmp(elem->name,"settings") == 0) {
                        unimrcp_server_settings_load(server,plugin_dir_path,elem,pool);
                }
                else if(strcasecmp(elem->name,"profiles") == 0) {
diff --git a/libs/unimrcp/platforms/umc/Makefile.am b/libs/unimrcp/platforms/umc/Makefile.am
new file mode 100644 (file)
index 0000000..4071490
--- /dev/null
@@ -0,0 +1,34 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+INCLUDES               = -Iinclude \
+                         -I$(top_srcdir)/platforms/libunimrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-client/include \
+                         -I$(top_srcdir)/libs/mrcp-signaling/include \
+                         -I$(top_srcdir)/libs/mrcpv2-transport/include \
+                         -I$(top_srcdir)/libs/mrcp/include \
+                         -I$(top_srcdir)/libs/mrcp/message/include \
+                         -I$(top_srcdir)/libs/mrcp/control/include \
+                         -I$(top_srcdir)/libs/mrcp/resources/include \
+                         -I$(top_srcdir)/libs/mpf/include \
+                         -I$(top_srcdir)/libs/apr-toolkit/include \
+                         $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+bin_PROGRAMS           = umc
+umc_SOURCES            = src/main.cpp \
+                         src/umcconsole.cpp \
+                         src/umcframework.cpp \
+                         src/umcscenario.cpp \
+                         src/umcsession.cpp \
+                         src/synthscenario.cpp \
+                         src/synthsession.cpp \
+                         src/recogscenario.cpp \
+                         src/recogsession.cpp \
+                         src/recorderscenario.cpp \
+                         src/recordersession.cpp \
+                         src/dtmfscenario.cpp \
+                         src/dtmfsession.cpp
+umc_LDADD              = $(top_builddir)/platforms/libunimrcp-client/libunimrcpclient.la
+
+if ISMAC
+umc_LDFLAGS            = -framework CoreFoundation -framework SystemConfiguration
+endif
diff --git a/libs/unimrcp/platforms/umc/include/dtmfscenario.h b/libs/unimrcp/platforms/umc/include/dtmfscenario.h
new file mode 100644 (file)
index 0000000..63aab62
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 __DTMF_SCENARIO_H__
+#define __DTMF_SCENARIO_H__
+
+/**
+ * @file dtmfscenario.h
+ * @brief DTMF Recognition Scenario
+ */ 
+
+#include "umcscenario.h"
+
+class DtmfScenario : public UmcScenario
+{
+public:
+/* ============================ CREATORS =================================== */
+       DtmfScenario();
+       virtual ~DtmfScenario();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual void Destroy();
+
+       virtual UmcSession* CreateSession();
+
+/* ============================ ACCESSORS ================================== */
+       const char* GetContentType() const;
+       const char* GetGrammar() const;
+       const char* GetDigits() const;
+
+/* ============================ INQUIRIES ================================== */
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+       bool LoadRecognize(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+/* ============================ DATA ======================================= */
+       const char* m_ContentType;
+       const char* m_Grammar;
+       const char* m_Digits;
+};
+
+/* ============================ INLINE METHODS ============================= */
+inline const char* DtmfScenario::GetContentType() const
+{
+       return m_ContentType;
+}
+
+inline const char* DtmfScenario::GetGrammar() const
+{
+       return m_Grammar;
+}
+
+inline const char* DtmfScenario::GetDigits() const
+{
+       return m_Digits;
+}
+
+
+#endif /*__DTMF_SCENARIO_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/dtmfsession.h b/libs/unimrcp/platforms/umc/include/dtmfsession.h
new file mode 100644 (file)
index 0000000..6dcc70e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 __DTMF_SESSION_H__
+#define __DTMF_SESSION_H__
+
+/**
+ * @file dtmfsession.h
+ * @brief DTMF Recognition Session
+ */ 
+
+#include "umcsession.h"
+
+class DtmfScenario;
+struct RecogChannel;
+
+class DtmfSession : public UmcSession
+{
+public:
+/* ============================ CREATORS =================================== */
+       DtmfSession(const DtmfScenario* pScenario);
+       virtual ~DtmfSession();
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Start();
+
+       RecogChannel* CreateRecogChannel();
+       bool StartRecognition(mrcp_channel_t* pMrcpChannel);
+
+       mrcp_message_t* CreateRecognizeRequest(mrcp_channel_t* pMrcpChannel);
+
+       bool ParseNLSMLResult(mrcp_message_t* pMrcpMessage) const;
+
+/* ============================ HANDLERS =================================== */
+       virtual bool OnSessionTerminate(mrcp_sig_status_code_e status);
+       virtual bool OnChannelAdd(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnChannelRemove(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnMessageReceive(mrcp_channel_t* channel, mrcp_message_t* message);
+
+/* ============================ ACCESSORS ================================== */
+       const DtmfScenario* GetScenario() const;
+
+private:
+/* ============================ DATA ======================================= */
+       RecogChannel*         m_pRecogChannel;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline const DtmfScenario* DtmfSession::GetScenario() const
+{
+       return (DtmfScenario*)m_pScenario;
+}
+
+#endif /*__DTMF_SESSION_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/recogscenario.h b/libs/unimrcp/platforms/umc/include/recogscenario.h
new file mode 100644 (file)
index 0000000..1be4d73
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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 __RECOG_SCENARIO_H__
+#define __RECOG_SCENARIO_H__
+
+/**
+ * @file recogscenario.h
+ * @brief Recognizer Scenario
+ */ 
+
+#include "umcscenario.h"
+
+class RecogScenario : public UmcScenario
+{
+public:
+/* ============================ CREATORS =================================== */
+       RecogScenario();
+       virtual ~RecogScenario();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual void Destroy();
+
+       virtual UmcSession* CreateSession();
+
+/* ============================ ACCESSORS ================================== */
+       const char* GetContentType() const;
+       const char* GetContent() const;
+       const char* GetAudioSource() const;
+
+/* ============================ INQUIRIES ================================== */
+       bool IsDefineGrammarEnabled() const;
+       bool IsRecognizeEnabled() const;
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+       bool LoadRecognize(const apr_xml_elem* pElem, apr_pool_t* pool);
+       bool LoadDefineGrammar(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+/* ============================ DATA ======================================= */
+       bool        m_DefineGrammar;
+       bool        m_Recognize;
+       const char* m_ContentType;
+       const char* m_Content;
+       const char* m_AudioSource;
+};
+
+/* ============================ INLINE METHODS ============================= */
+inline const char* RecogScenario::GetContentType() const
+{
+       return m_ContentType;
+}
+
+inline const char* RecogScenario::GetContent() const
+{
+       return m_Content;
+}
+
+inline const char* RecogScenario::GetAudioSource() const
+{
+       return m_AudioSource;
+}
+
+inline bool RecogScenario::IsDefineGrammarEnabled() const
+{
+       return m_DefineGrammar;
+}
+
+inline bool RecogScenario::IsRecognizeEnabled() const
+{
+       return m_Recognize;
+}
+
+#endif /*__RECOG_SCENARIO_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/recogsession.h b/libs/unimrcp/platforms/umc/include/recogsession.h
new file mode 100644 (file)
index 0000000..a31b864
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 __RECOG_SESSION_H__
+#define __RECOG_SESSION_H__
+
+/**
+ * @file recogsession.h
+ * @brief Recognizer Session
+ */ 
+
+#include "umcsession.h"
+
+class RecogScenario;
+struct RecogChannel;
+
+class RecogSession : public UmcSession
+{
+public:
+/* ============================ CREATORS =================================== */
+       RecogSession(const RecogScenario* pScenario);
+       virtual ~RecogSession();
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Start();
+
+       RecogChannel* CreateRecogChannel();
+       bool StartRecognition(mrcp_channel_t* pMrcpChannel);
+       bool OnDefineGrammar(mrcp_channel_t* pMrcpChannel);
+
+       mrcp_message_t* CreateDefineGrammarRequest(mrcp_channel_t* pMrcpChannel);
+       mrcp_message_t* CreateRecognizeRequest(mrcp_channel_t* pMrcpChannel);
+
+       bool ParseNLSMLResult(mrcp_message_t* pMrcpMessage) const;
+       FILE* GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const;
+
+/* ============================ HANDLERS =================================== */
+       virtual bool OnSessionTerminate(mrcp_sig_status_code_e status);
+       virtual bool OnChannelAdd(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnChannelRemove(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnMessageReceive(mrcp_channel_t* channel, mrcp_message_t* message);
+
+/* ============================ ACCESSORS ================================== */
+       const RecogScenario* GetScenario() const;
+
+private:
+/* ============================ DATA ======================================= */
+       RecogChannel* m_pRecogChannel;
+       const char*   m_ContentId;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline const RecogScenario* RecogSession::GetScenario() const
+{
+       return (RecogScenario*)m_pScenario;
+}
+
+#endif /*__RECOG_SESSION_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/recorderscenario.h b/libs/unimrcp/platforms/umc/include/recorderscenario.h
new file mode 100644 (file)
index 0000000..9648fd3
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 __RECORDER_SCENARIO_H__
+#define __RECORDER_SCENARIO_H__
+
+/**
+ * @file recorderscenario.h
+ * @brief Recorder Scenario
+ */ 
+
+#include "umcscenario.h"
+
+class RecorderScenario : public UmcScenario
+{
+public:
+/* ============================ CREATORS =================================== */
+       RecorderScenario();
+       virtual ~RecorderScenario();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual void Destroy();
+
+       virtual UmcSession* CreateSession();
+
+/* ============================ ACCESSORS ================================== */
+       const char* GetAudioSource() const;
+
+/* ============================ INQUIRIES ================================== */
+       bool IsRecordEnabled() const;
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+       bool LoadRecord(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+/* ============================ DATA ======================================= */
+       bool        m_Record;
+       const char* m_AudioSource;
+};
+
+/* ============================ INLINE METHODS ============================= */
+inline const char* RecorderScenario::GetAudioSource() const
+{
+       return m_AudioSource;
+}
+
+inline bool RecorderScenario::IsRecordEnabled() const
+{
+       return m_Record;
+}
+
+#endif /*__RECORDER_SCENARIO_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/recordersession.h b/libs/unimrcp/platforms/umc/include/recordersession.h
new file mode 100644 (file)
index 0000000..338592a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 __RECORDER_SESSION_H__
+#define __RECORDER_SESSION_H__
+
+/**
+ * @file recordersession.h
+ * @brief Recorder Session
+ */ 
+
+#include "umcsession.h"
+
+class RecorderScenario;
+struct RecorderChannel;
+
+class RecorderSession : public UmcSession
+{
+public:
+/* ============================ CREATORS =================================== */
+       RecorderSession(const RecorderScenario* pScenario);
+       virtual ~RecorderSession();
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Start();
+
+       RecorderChannel* CreateRecorderChannel();
+       bool StartRecorder(mrcp_channel_t* pMrcpChannel);
+
+       mrcp_message_t* CreateRecordRequest(mrcp_channel_t* pMrcpChannel);
+
+       FILE* GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const;
+
+/* ============================ HANDLERS =================================== */
+       virtual bool OnSessionTerminate(mrcp_sig_status_code_e status);
+       virtual bool OnChannelAdd(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnChannelRemove(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnMessageReceive(mrcp_channel_t* channel, mrcp_message_t* message);
+
+/* ============================ ACCESSORS ================================== */
+       const RecorderScenario* GetScenario() const;
+
+private:
+/* ============================ DATA ======================================= */
+       RecorderChannel* m_pRecorderChannel;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline const RecorderScenario* RecorderSession::GetScenario() const
+{
+       return (RecorderScenario*)m_pScenario;
+}
+
+#endif /*__RECORDER_SESSION_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/synthscenario.h b/libs/unimrcp/platforms/umc/include/synthscenario.h
new file mode 100644 (file)
index 0000000..fd5aa95
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 __SYNTH_SCENARIO_H__
+#define __SYNTH_SCENARIO_H__
+
+/**
+ * @file synthscenario.h
+ * @brief Synthesizer Scenario
+ */ 
+
+#include "umcscenario.h"
+
+class SynthScenario : public UmcScenario
+{
+public:
+/* ============================ CREATORS =================================== */
+       SynthScenario();
+       virtual ~SynthScenario();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual void Destroy();
+
+       virtual UmcSession* CreateSession();
+
+/* ============================ ACCESSORS ================================== */
+       const char* GetContentType() const;
+       const char* GetContent() const;
+
+/* ============================ INQUIRIES ================================== */
+       bool IsSpeakEnabled() const;
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+       bool LoadSpeak(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+/* ============================ DATA ======================================= */
+       bool        m_Speak;
+       const char* m_ContentType;
+       const char* m_Content;
+};
+
+/* ============================ INLINE METHODS ============================= */
+inline const char* SynthScenario::GetContentType() const
+{
+       return m_ContentType;
+}
+
+inline const char* SynthScenario::GetContent() const
+{
+       return m_Content;
+}
+
+inline bool SynthScenario::IsSpeakEnabled() const
+{
+       return m_Speak;
+}
+
+#endif /*__SYNTH_SCENARIO_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/synthsession.h b/libs/unimrcp/platforms/umc/include/synthsession.h
new file mode 100644 (file)
index 0000000..3b45d50
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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 __SYNTH_SESSION_H__
+#define __SYNTH_SESSION_H__
+
+/**
+ * @file synthsession.h
+ * @brief Synthesizer Session
+ */ 
+
+#include "umcsession.h"
+
+class SynthScenario;
+struct SynthChannel;
+
+class SynthSession : public UmcSession
+{
+public:
+/* ============================ CREATORS =================================== */
+       SynthSession(const SynthScenario* pScenario);
+       virtual ~SynthSession();
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Start();
+
+       SynthChannel* CreateSynthChannel();
+
+       mrcp_message_t* CreateSpeakRequest(mrcp_channel_t* pMrcpChannel);
+       FILE* GetAudioOut(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const;
+
+/* ============================ HANDLERS =================================== */
+       virtual bool OnSessionTerminate(mrcp_sig_status_code_e status);
+       virtual bool OnChannelAdd(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnChannelRemove(mrcp_channel_t* channel, mrcp_sig_status_code_e status);
+       virtual bool OnMessageReceive(mrcp_channel_t* channel, mrcp_message_t* message);
+
+/* ============================ ACCESSORS ================================== */
+       const SynthScenario* GetScenario() const;
+       
+private:
+/* ============================ DATA ======================================= */
+       SynthChannel* m_pSynthChannel;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline const SynthScenario* SynthSession::GetScenario() const
+{
+       return (SynthScenario*)m_pScenario;
+}
+
+#endif /*__SYNTH_SESSION_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/umcconsole.h b/libs/unimrcp/platforms/umc/include/umcconsole.h
new file mode 100644 (file)
index 0000000..c8bd7c6
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 __UMC_CONSOLE_H__
+#define __UMC_CONSOLE_H__
+
+/**
+ * @file umcconsole.h
+ * @brief UMC Application Console
+ */ 
+
+#include "apt_log.h"
+
+class UmcFramework;
+
+class UmcConsole
+{
+public:
+/* ============================ CREATORS =================================== */
+       UmcConsole();
+       ~UmcConsole();
+
+/* ============================ MANIPULATORS =============================== */
+       bool Run(int argc, const char * const *argv);
+
+protected:
+       bool LoadOptions(int argc, const char * const *argv, apr_pool_t *pool);
+       bool RunCmdLine();
+       bool ProcessCmdLine(char* pCmdLine);
+       void Usage() const;
+
+private:
+/* ============================ DATA ======================================= */
+       struct UmcOptions
+       {
+               const char*        m_RootDirPath;
+               apt_log_priority_e m_LogPriority;
+               apt_log_output_e   m_LogOutput;
+       };
+
+       UmcOptions    m_Options;
+       UmcFramework* m_pFramework;
+};
+
+#endif /*__UMC_CONSOLE_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/umcframework.h b/libs/unimrcp/platforms/umc/include/umcframework.h
new file mode 100644 (file)
index 0000000..36f8082
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 __UMC_FRAMEWORK_H__
+#define __UMC_FRAMEWORK_H__
+
+/**
+ * @file umcframework.h
+ * @brief UMC Application Framework
+ */ 
+
+#include <apr_xml.h>
+#include <apr_hash.h>
+#include "mrcp_application.h"
+#include "apt_consumer_task.h"
+
+class UmcSession;
+class UmcScenario;
+
+class UmcFramework
+{
+public:
+/* ============================ CREATORS =================================== */
+       UmcFramework();
+       ~UmcFramework();
+
+/* ============================ MANIPULATORS =============================== */
+       bool Create(apt_dir_layout_t* pDirLayout, apr_pool_t* pool);
+       void Destroy();
+
+       void RunSession(const char* pScenarioName, const char* pProfileName);
+       void KillSession(const char* id);
+
+       void ShowScenarios();
+       void ShowSessions();
+
+protected:
+       bool CreateMrcpClient();
+       void DestroyMrcpClient();
+
+       bool CreateTask();
+       void DestroyTask();
+
+       UmcScenario* CreateScenario(const char* pType);
+       apr_xml_doc* LoadDocument();
+
+       bool LoadScenarios();
+       void DestroyScenarios();
+
+       bool ProcessRunRequest(const char* pScenarioName, const char* pProfileName);
+       void ProcessKillRequest(const char* id);
+       void ProcessShowScenarios();
+       void ProcessShowSessions();
+
+       bool AddSession(UmcSession* pSession);
+       bool RemoveSession(UmcSession* pSession);
+
+/* ============================ HANDLERS =================================== */
+       friend apt_bool_t UmcProcessMsg(apt_task_t* pTask, apt_task_msg_t* pMsg);
+       friend void UmcOnStartComplete(apt_task_t* pTask);
+       friend void UmcOnTerminateComplete(apt_task_t* pTask);
+
+       friend apt_bool_t AppMessageHandler(const mrcp_app_message_t* pAppMessage);
+       friend apt_bool_t AppOnReady(mrcp_application_t* pMrcpApplication, mrcp_sig_status_code_e status);
+       friend apt_bool_t AppOnSessionTerminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status);
+
+private:
+/* ============================ DATA ======================================= */
+       apr_pool_t*          m_pPool;
+       apt_dir_layout_t*    m_pDirLayout;
+       apt_consumer_task_t* m_pTask;
+
+       mrcp_client_t*       m_pMrcpClient;
+       mrcp_application_t*  m_pMrcpApplication;
+
+       bool                 m_Ready;
+
+       apr_hash_t*          m_pScenarioTable;
+       apr_hash_t*          m_pSessionTable;
+};
+
+#endif /*__UMC_FRAMEWORK_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/umcscenario.h b/libs/unimrcp/platforms/umc/include/umcscenario.h
new file mode 100644 (file)
index 0000000..712eb66
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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 __UMC_SCENARIO_H__
+#define __UMC_SCENARIO_H__
+
+/**
+ * @file umcscenario.h
+ * @brief UMC Scenario
+ */ 
+
+#include <apr_xml.h>
+#include "mrcp_application.h"
+
+class UmcSession;
+
+class UmcScenario
+{
+public:
+/* ============================ CREATORS =================================== */
+       UmcScenario();
+       virtual ~UmcScenario();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Load(const apr_xml_elem* pElem, apr_pool_t* pool);
+       virtual void Destroy();
+
+       virtual UmcSession* CreateSession() = 0;
+
+       void SetDirLayout(apt_dir_layout_t* pDirLayout);
+       void SetName(const char* pName);
+       void SetMrcpProfile(const char* pMrcpProfile);
+
+       bool InitCapabilities(mpf_stream_capabilities_t* pCapabilities) const;
+
+/* ============================ ACCESSORS ================================== */
+       apt_dir_layout_t* GetDirLayout() const;
+       const char* GetName() const;
+       const char* GetMrcpProfile() const;
+
+/* ============================ INQUIRIES ================================== */
+       bool IsDiscoveryEnabled() const;
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool);
+       
+       bool LoadDiscovery(const apr_xml_elem* pElem, apr_pool_t* pool);
+       bool LoadTermination(const apr_xml_elem* pElem, apr_pool_t* pool);
+       bool LoadCapabilities(const apr_xml_elem* pElem, apr_pool_t* pool);
+       bool LoadRtpTermination(const apr_xml_elem* pElem, apr_pool_t* pool);
+
+       const char* LoadFileContent(const char* pFileName, apr_pool_t* pool) const;
+       int ParseRates(const char* pStr, apr_pool_t* pool) const;
+
+/* ============================ INQUIRIES ================================== */
+       bool IsElementEnabled(const apr_xml_elem* pElem) const;
+
+/* ============================ DATA ======================================= */
+       const char*                       m_pName;
+       const char*                       m_pMrcpProfile;
+       apt_dir_layout_t*                 m_pDirLayout;
+
+       bool                              m_ResourceDiscovery;
+       mpf_codec_capabilities_t*         m_pCapabilities;
+       mpf_rtp_termination_descriptor_t* m_pRtpDescriptor;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline void UmcScenario::SetDirLayout(apt_dir_layout_t* pDirLayout)
+{
+       m_pDirLayout = pDirLayout;
+}
+
+inline apt_dir_layout_t* UmcScenario::GetDirLayout() const
+{
+       return m_pDirLayout;
+}
+
+inline void UmcScenario::SetName(const char* pName)
+{
+       m_pName = pName;
+}
+
+inline const char* UmcScenario::GetName() const
+{
+       return m_pName;
+}
+
+inline void UmcScenario::SetMrcpProfile(const char* pMrcpProfile)
+{
+       m_pMrcpProfile = pMrcpProfile;
+}
+
+inline const char* UmcScenario::GetMrcpProfile() const
+{
+       return m_pMrcpProfile;
+}
+
+inline bool UmcScenario::IsDiscoveryEnabled() const
+{
+       return m_ResourceDiscovery;
+}
+
+
+#endif /*__UMC_SCENARIO_H__*/
diff --git a/libs/unimrcp/platforms/umc/include/umcsession.h b/libs/unimrcp/platforms/umc/include/umcsession.h
new file mode 100644 (file)
index 0000000..2c2f729
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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 __UMC_SESSION_H__
+#define __UMC_SESSION_H__
+
+/**
+ * @file umcsession.h
+ * @brief UMC Session
+ */ 
+
+#include "mrcp_application.h"
+
+class UmcScenario;
+
+class UmcSession
+{
+public:
+/* ============================ CREATORS =================================== */
+       UmcSession(const UmcScenario* pScenario);
+       virtual ~UmcSession();
+
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Run();
+       virtual bool Terminate();
+
+       void SetMrcpProfile(const char* pMrcpProfile);
+       void SetMrcpApplication(mrcp_application_t* pMrcpApplication);
+
+/* ============================ HANDLERS =================================== */
+       virtual bool OnSessionTerminate(mrcp_sig_status_code_e status);
+       virtual bool OnSessionUpdate(mrcp_sig_status_code_e status);
+       virtual bool OnChannelAdd(mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+       virtual bool OnChannelRemove(mrcp_channel_t *channel, mrcp_sig_status_code_e status);
+       virtual bool OnMessageReceive(mrcp_channel_t *channel, mrcp_message_t *message);
+       virtual bool OnTerminateEvent(mrcp_channel_t *channel);
+       virtual bool OnResourceDiscover(mrcp_session_descriptor_t* descriptor, mrcp_sig_status_code_e status);
+
+/* ============================ ACCESSORS ================================== */
+       const UmcScenario* GetScenario() const;
+
+       const char* GetId() const;
+
+protected:
+/* ============================ MANIPULATORS =============================== */
+       virtual bool Start() = 0;
+
+       bool CreateMrcpSession(const char* pProfileName);
+       bool DestroyMrcpSession();
+
+       bool AddMrcpChannel(mrcp_channel_t* pMrcpChannel);
+       bool RemoveMrcpChannel(mrcp_channel_t* pMrcpChannel);
+       bool SendMrcpRequest(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage);
+       bool ResourceDiscover();
+
+       mrcp_channel_t* CreateMrcpChannel(
+                       mrcp_resource_id resource_id, 
+                       mpf_termination_t* pTermination, 
+                       mpf_rtp_termination_descriptor_t* pRtpDescriptor, 
+                       void* pObj);
+       mpf_termination_t* CreateAudioTermination(
+                       const mpf_audio_stream_vtable_t* pStreamVtable,
+                       mpf_stream_capabilities_t* pCapabilities,
+                       void* pObj);
+       mrcp_message_t* CreateMrcpMessage(
+                       mrcp_channel_t* pMrcpChannel, 
+                       mrcp_method_id method_id);
+
+/* ============================ ACCESSORS ================================== */
+       apr_pool_t* GetSessionPool() const;
+       const char* GetMrcpSessionId() const;
+
+/* ============================ DATA ======================================= */
+       const UmcScenario*  m_pScenario;
+       const char*         m_pMrcpProfile;
+       char                m_Id[10];
+
+private:
+/* ============================ DATA ======================================= */
+       mrcp_application_t* m_pMrcpApplication;
+       mrcp_session_t*     m_pMrcpSession;
+       bool                m_Running;
+       bool                m_Terminating;
+};
+
+
+/* ============================ INLINE METHODS ============================= */
+inline const UmcScenario* UmcSession::GetScenario() const
+{
+       return m_pScenario;
+}
+
+inline const char* UmcSession::GetId() const
+{
+       return m_Id;
+}
+
+inline void UmcSession::SetMrcpApplication(mrcp_application_t* pMrcpApplication)
+{
+       m_pMrcpApplication = pMrcpApplication;
+}
+
+inline void UmcSession::SetMrcpProfile(const char* pMrcpProfile)
+{
+       m_pMrcpProfile = pMrcpProfile;
+}
+
+#endif /*__UMC_SESSION_H__*/
diff --git a/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp b/libs/unimrcp/platforms/umc/src/dtmfscenario.cpp
new file mode 100644 (file)
index 0000000..ca644b3
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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 <stdlib.h>
+#include "dtmfscenario.h"
+#include "dtmfsession.h"
+#include "apt_log.h"
+
+DtmfScenario::DtmfScenario() :
+       m_ContentType(NULL),
+       m_Grammar(NULL),
+       m_Digits(NULL)
+{
+}
+
+DtmfScenario::~DtmfScenario()
+{
+}
+
+void DtmfScenario::Destroy()
+{
+}
+
+bool DtmfScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(UmcScenario::LoadElement(pElem,pool))
+               return true;
+       
+       if(strcasecmp(pElem->name,"recognize") == 0)
+       {
+               LoadRecognize(pElem,pool);
+               return true;
+       }
+               
+       return false;
+}
+
+bool DtmfScenario::LoadRecognize(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"content-type") == 0)
+               {
+                       m_ContentType = pAttr->value;
+               }
+               else if(strcasecmp(pAttr->name,"grammar") == 0)
+               {
+                       m_Grammar = pAttr->value;
+               }
+               else if(strcasecmp(pAttr->name,"digits") == 0)
+               {
+                       m_Digits = pAttr->value;
+               }
+       }
+
+       return true;
+}
+
+
+UmcSession* DtmfScenario::CreateSession()
+{
+       return new DtmfSession(this);
+}
diff --git a/libs/unimrcp/platforms/umc/src/dtmfsession.cpp b/libs/unimrcp/platforms/umc/src/dtmfsession.cpp
new file mode 100644 (file)
index 0000000..38c85cf
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 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 "dtmfsession.h"
+#include "dtmfscenario.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+#include "mpf_dtmf_generator.h"
+#include "apt_nlsml_doc.h"
+#include "apt_log.h"
+
+struct RecogChannel
+{
+       /** MRCP control channel */
+       mrcp_channel_t*       m_pMrcpChannel;
+       /** DTMF generator */
+       mpf_dtmf_generator_t* m_pDtmfGenerator;
+       /** Audio stream */
+       mpf_audio_stream_t*   m_pStream;
+       /** Streaming is in-progress */
+       bool                  m_Streaming;
+};
+
+DtmfSession::DtmfSession(const DtmfScenario* pScenario) :
+       UmcSession(pScenario),
+       m_pRecogChannel(NULL)
+{
+}
+
+DtmfSession::~DtmfSession()
+{
+}
+
+bool DtmfSession::Start()
+{
+       /* create channel and associate all the required data */
+       m_pRecogChannel = CreateRecogChannel();
+       if(!m_pRecogChannel) 
+               return false;
+
+       /* add channel to session (send asynchronous request) */
+       if(!AddMrcpChannel(m_pRecogChannel->m_pMrcpChannel))
+       {
+               delete m_pRecogChannel;
+               m_pRecogChannel = NULL;
+               return false;
+       }
+       return true;
+}
+
+bool DtmfSession::OnSessionTerminate(mrcp_sig_status_code_e status)
+{
+       if(m_pRecogChannel)
+       {
+               if(m_pRecogChannel->m_pDtmfGenerator)
+               {
+                       mpf_dtmf_generator_destroy(m_pRecogChannel->m_pDtmfGenerator);
+                       m_pRecogChannel->m_pDtmfGenerator = NULL;
+               }
+               
+               delete m_pRecogChannel;
+               m_pRecogChannel = NULL;
+       }
+       return UmcSession::OnSessionTerminate(status);
+}
+
+static apt_bool_t OpenStream(mpf_audio_stream_t* pStream, mpf_codec_t *codec)
+{
+       RecogChannel* pRecogChannel = (RecogChannel*) pStream->obj;
+       pRecogChannel->m_pStream = pStream;
+       return TRUE;
+}
+
+static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame)
+{
+       RecogChannel* pRecogChannel = (RecogChannel*) pStream->obj;
+       if(pRecogChannel && pRecogChannel->m_Streaming) 
+       {
+               if(pRecogChannel->m_pDtmfGenerator) 
+               {
+                       mpf_dtmf_generator_put_frame(pRecogChannel->m_pDtmfGenerator,pFrame);
+               }
+       }
+       return TRUE;
+}
+
+RecogChannel* DtmfSession::CreateRecogChannel()
+{
+       mrcp_channel_t* pChannel;
+       mpf_termination_t* pTermination;
+       mpf_stream_capabilities_t* pCapabilities;
+       apr_pool_t* pool = GetSessionPool();
+
+       /* create channel */
+       RecogChannel *pRecogChannel = new RecogChannel;
+       pRecogChannel->m_pMrcpChannel = NULL;
+       pRecogChannel->m_pDtmfGenerator = NULL;
+       pRecogChannel->m_pStream = NULL;
+       pRecogChannel->m_Streaming = false;
+
+       /* create source stream capabilities */
+       pCapabilities = mpf_source_stream_capabilities_create(pool);
+       GetScenario()->InitCapabilities(pCapabilities);
+
+       static const mpf_audio_stream_vtable_t audio_stream_vtable = 
+       {
+               NULL,
+               OpenStream,
+               NULL,
+               ReadStream,
+               NULL,
+               NULL,
+               NULL
+       };
+
+       pTermination = CreateAudioTermination(
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       pCapabilities,             /* capabilities of audio stream */
+                       pRecogChannel);            /* object to associate */
+
+       pChannel = CreateMrcpChannel(
+                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                       pTermination,              /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       pRecogChannel);            /* object to associate */
+       if(!pChannel)
+       {
+               delete pRecogChannel;
+               return NULL;
+       }
+       
+       pRecogChannel->m_pMrcpChannel = pChannel;
+       return pRecogChannel;
+}
+
+bool DtmfSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
+               return false;
+
+       if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
+       {
+               /* error case, just terminate the demo */
+               return Terminate();
+       }
+
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pRecogChannel)
+       {
+               pRecogChannel->m_pDtmfGenerator = mpf_dtmf_generator_create(pRecogChannel->m_pStream,GetSessionPool());
+       }
+
+       return StartRecognition(pMrcpChannel);
+}
+
+bool DtmfSession::OnChannelRemove(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelRemove(pMrcpChannel,status))
+               return false;
+
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pRecogChannel)
+       {
+               if(pRecogChannel->m_pDtmfGenerator)
+               {
+                       mpf_dtmf_generator_destroy(pRecogChannel->m_pDtmfGenerator);
+                       pRecogChannel->m_pDtmfGenerator = NULL;
+               }
+       }
+       
+       /* terminate the demo */
+       return Terminate();
+}
+
+bool DtmfSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
+{
+       if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
+               return false;
+
+       const DtmfScenario* pScenario = GetScenario();
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) 
+       {
+               if(pMrcpMessage->start_line.method_id == RECOGNIZER_RECOGNIZE)
+               {
+                       /* received the response to RECOGNIZE request */
+                       if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS)
+                       {
+                               /* start to stream the DTMFs to recognize */
+                               if(pRecogChannel && pRecogChannel->m_pDtmfGenerator)
+                               {
+                                       const char* digits = pScenario->GetDigits();
+                                       if(digits)
+                                       {
+                                               mpf_dtmf_generator_enqueue(pRecogChannel->m_pDtmfGenerator,digits);
+                                               pRecogChannel->m_Streaming = true;
+                                       }
+                               }
+                       }
+                       else 
+                       {
+                               /* received unexpected response, remove channel */
+                               RemoveMrcpChannel(pMrcpChannel);
+                       }
+               }
+               else 
+               {
+                       /* received unexpected response */
+               }
+       }
+       else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) 
+       {
+               if(pMrcpMessage->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) 
+               {
+                       ParseNLSMLResult(pMrcpMessage);
+                       if(pRecogChannel) 
+                       {
+                               pRecogChannel->m_Streaming = false;
+                       }
+                       RemoveMrcpChannel(pMrcpChannel);
+               }
+               else if(pMrcpMessage->start_line.method_id == RECOGNIZER_START_OF_INPUT) 
+               {
+                       /* received start-of-input, do whatever you need here */
+               }
+       }
+       return true;
+}
+
+bool DtmfSession::StartRecognition(mrcp_channel_t* pMrcpChannel)
+{
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       /* create and send RECOGNIZE request */
+       mrcp_message_t* pMrcpMessage = CreateRecognizeRequest(pMrcpChannel);
+       if(pMrcpMessage)
+       {
+               SendMrcpRequest(pRecogChannel->m_pMrcpChannel,pMrcpMessage);
+       }
+
+       return true;
+}
+
+mrcp_message_t* DtmfSession::CreateRecognizeRequest(mrcp_channel_t* pMrcpChannel)
+{
+       mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,RECOGNIZER_RECOGNIZE);
+       if(!pMrcpMessage)
+               return NULL;
+
+       const DtmfScenario* pScenario = GetScenario();
+
+       mrcp_generic_header_t* pGenericHeader;
+       mrcp_recog_header_t* pRecogHeader;
+
+       /* get/allocate generic header */
+       pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pMrcpMessage);
+       if(pGenericHeader)
+       {
+               apt_string_assign(&pGenericHeader->content_type,pScenario->GetContentType(),pMrcpMessage->pool);
+               mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_TYPE);
+               /* set message body */
+               if(pScenario->GetGrammar())
+                       apt_string_assign(&pMrcpMessage->body,pScenario->GetGrammar(),pMrcpMessage->pool);
+       }
+       /* get/allocate recognizer header */
+       pRecogHeader = (mrcp_recog_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
+       if(pRecogHeader)
+       {
+               /* set recognizer header fields */
+               if(pMrcpMessage->start_line.version == MRCP_VERSION_2)
+               {
+                       pRecogHeader->cancel_if_queue = FALSE;
+                       mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_CANCEL_IF_QUEUE);
+               }
+       }
+       return pMrcpMessage;
+}
+
+bool DtmfSession::ParseNLSMLResult(mrcp_message_t* pMrcpMessage) const
+{
+       apr_xml_elem* pInterpret;
+       apr_xml_elem* pInstance;
+       apr_xml_elem* pInput;
+       apr_xml_doc* pDoc = nlsml_doc_load(&pMrcpMessage->body,pMrcpMessage->pool);
+       if(!pDoc)
+               return false;
+       
+       /* walk through interpreted results */
+       pInterpret = nlsml_first_interpret_get(pDoc);
+       for(; pInterpret; pInterpret = nlsml_next_interpret_get(pInterpret)) 
+       {
+               /* get instance and input */
+               nlsml_interpret_results_get(pInterpret,&pInstance,&pInput);
+               if(pInstance) 
+               {
+                       /* process instance */
+                       if(pInstance->first_cdata.first) 
+                       {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Interpreted Instance [%s]",pInstance->first_cdata.first->text);
+                       }
+               }
+               if(pInput) 
+               {
+                       /* process input */
+                       if(pInput->first_cdata.first)
+                       {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Interpreted Input [%s]",pInput->first_cdata.first->text);
+                       }
+               }
+       }
+       return true;
+}
diff --git a/libs/unimrcp/platforms/umc/src/main.cpp b/libs/unimrcp/platforms/umc/src/main.cpp
new file mode 100644 (file)
index 0000000..089dee3
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 "umcconsole.h"
+
+int main(int argc, const char * const *argv)
+{
+       UmcConsole console;
+       console.Run(argc,argv);
+       return 0;
+}
diff --git a/libs/unimrcp/platforms/umc/src/recogscenario.cpp b/libs/unimrcp/platforms/umc/src/recogscenario.cpp
new file mode 100644 (file)
index 0000000..c7cfbcb
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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 <stdlib.h>
+#include "recogscenario.h"
+#include "recogsession.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+#include "apt_log.h"
+
+RecogScenario::RecogScenario() :
+       m_DefineGrammar(true),
+       m_Recognize(true),
+       m_ContentType("application/srgs+xml"),
+       m_Content(NULL),
+       m_AudioSource(NULL)
+{
+}
+
+RecogScenario::~RecogScenario()
+{
+}
+
+void RecogScenario::Destroy()
+{
+}
+
+bool RecogScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(UmcScenario::LoadElement(pElem,pool))
+               return true;
+       
+       if(strcasecmp(pElem->name,"define-grammar") == 0)
+       {
+               LoadDefineGrammar(pElem,pool);
+               return true;
+       }
+       else if(strcasecmp(pElem->name,"recognize") == 0)
+       {
+               LoadRecognize(pElem,pool);
+               return true;
+       }
+               
+       return false;
+}
+
+bool RecogScenario::LoadRecognize(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"enable") == 0)
+               {
+                       m_Recognize = atoi(pAttr->value) > 0;
+               }
+               else if(strcasecmp(pAttr->name,"content-type") == 0)
+               {
+                       m_ContentType = pAttr->value;
+               }
+               else if(strcasecmp(pAttr->name,"content-location") == 0)
+               {
+                       m_Content = LoadFileContent(pAttr->value,pool);
+               }
+               else if(strcasecmp(pAttr->name,"audio-source") == 0)
+               {
+                       m_AudioSource = pAttr->value;
+               }
+       }
+
+       return true;
+}
+
+bool RecogScenario::LoadDefineGrammar(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"enable") == 0)
+               {
+                       m_DefineGrammar = atoi(pAttr->value) > 0;
+               }
+               else if(strcasecmp(pAttr->name,"content-type") == 0)
+               {
+                       m_ContentType = pAttr->value;
+               }
+               else if(strcasecmp(pAttr->name,"content-location") == 0)
+               {
+                       m_Content = LoadFileContent(pAttr->value,pool);
+               }
+       }
+       return true;
+}
+
+
+UmcSession* RecogScenario::CreateSession()
+{
+       return new RecogSession(this);
+}
diff --git a/libs/unimrcp/platforms/umc/src/recogsession.cpp b/libs/unimrcp/platforms/umc/src/recogsession.cpp
new file mode 100644 (file)
index 0000000..b519429
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * 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 "recogsession.h"
+#include "recogscenario.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recog_header.h"
+#include "mrcp_recog_resource.h"
+#include "apt_nlsml_doc.h"
+#include "apt_log.h"
+
+struct RecogChannel
+{
+       /** MRCP control channel */
+       mrcp_channel_t* m_pMrcpChannel;
+       /** Streaming is in-progress */
+       bool            m_Streaming;
+       /** File to read audio stream from */
+       FILE*           m_pAudioIn;
+       /** Estimated time to complete (used if no audio_in available) */
+       apr_size_t      m_TimeToComplete;
+};
+
+RecogSession::RecogSession(const RecogScenario* pScenario) :
+       UmcSession(pScenario),
+       m_pRecogChannel(NULL),
+       m_ContentId("request1@form-level")
+{
+}
+
+RecogSession::~RecogSession()
+{
+}
+
+bool RecogSession::Start()
+{
+       const RecogScenario* pScenario = GetScenario();
+       if(!pScenario->IsDefineGrammarEnabled() && !pScenario->IsRecognizeEnabled())
+               return false;
+       
+       /* create channel and associate all the required data */
+       m_pRecogChannel = CreateRecogChannel();
+       if(!m_pRecogChannel) 
+               return false;
+
+       /* add channel to session (send asynchronous request) */
+       if(!AddMrcpChannel(m_pRecogChannel->m_pMrcpChannel))
+       {
+               delete m_pRecogChannel;
+               m_pRecogChannel = NULL;
+               return false;
+       }
+       return true;
+}
+
+bool RecogSession::OnSessionTerminate(mrcp_sig_status_code_e status)
+{
+       if(m_pRecogChannel)
+       {
+               FILE* pAudioIn = m_pRecogChannel->m_pAudioIn;
+               if(pAudioIn)
+               {
+                       m_pRecogChannel->m_pAudioIn = NULL;
+                       fclose(pAudioIn);
+               }
+               
+               delete m_pRecogChannel;
+               m_pRecogChannel = NULL;
+       }
+       return UmcSession::OnSessionTerminate(status);
+}
+
+static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame)
+{
+       RecogChannel* pRecogChannel = (RecogChannel*) pStream->obj;
+       if(pRecogChannel && pRecogChannel->m_Streaming) 
+       {
+               if(pRecogChannel->m_pAudioIn) 
+               {
+                       if(fread(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pRecogChannel->m_pAudioIn) == pFrame->codec_frame.size) 
+                       {
+                               /* normal read */
+                               pFrame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       }
+                       else 
+                       {
+                               /* file is over */
+                               pRecogChannel->m_Streaming = false;
+                       }
+               }
+               else 
+               {
+                       /* fill with silence in case no file available */
+                       if(pRecogChannel->m_TimeToComplete >= CODEC_FRAME_TIME_BASE) 
+                       {
+                               pFrame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                               memset(pFrame->codec_frame.buffer,0,pFrame->codec_frame.size);
+                               pRecogChannel->m_TimeToComplete -= CODEC_FRAME_TIME_BASE;
+                       }
+                       else 
+                       {
+                               pRecogChannel->m_Streaming = false;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+RecogChannel* RecogSession::CreateRecogChannel()
+{
+       mrcp_channel_t* pChannel;
+       mpf_termination_t* pTermination;
+       mpf_stream_capabilities_t* pCapabilities;
+       apr_pool_t* pool = GetSessionPool();
+
+       /* create channel */
+       RecogChannel *pRecogChannel = new RecogChannel;
+       pRecogChannel->m_pMrcpChannel = NULL;
+       pRecogChannel->m_Streaming = false;
+       pRecogChannel->m_pAudioIn = NULL;
+       pRecogChannel->m_TimeToComplete = 0;
+
+       /* create source stream capabilities */
+       pCapabilities = mpf_source_stream_capabilities_create(pool);
+       GetScenario()->InitCapabilities(pCapabilities);
+
+       static const mpf_audio_stream_vtable_t audio_stream_vtable = 
+       {
+               NULL,
+               NULL,
+               NULL,
+               ReadStream,
+               NULL,
+               NULL,
+               NULL
+       };
+
+       pTermination = CreateAudioTermination(
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       pCapabilities,             /* capabilities of audio stream */
+                       pRecogChannel);            /* object to associate */
+
+       pChannel = CreateMrcpChannel(
+                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                       pTermination,              /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       pRecogChannel);            /* object to associate */
+       if(!pChannel)
+       {
+               delete pRecogChannel;
+               return NULL;
+       }
+       
+       pRecogChannel->m_pMrcpChannel = pChannel;
+       return pRecogChannel;
+}
+
+bool RecogSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
+               return false;
+
+       if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
+       {
+               /* error case, just terminate the demo */
+               return Terminate();
+       }
+
+       if(GetScenario()->IsDefineGrammarEnabled())
+       {
+               mrcp_message_t* pMrcpMessage = CreateDefineGrammarRequest(pMrcpChannel);
+               if(pMrcpMessage)
+                       SendMrcpRequest(pMrcpChannel,pMrcpMessage);
+               return true;
+       }
+
+       return StartRecognition(pMrcpChannel);
+}
+
+bool RecogSession::OnChannelRemove(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelRemove(pMrcpChannel,status))
+               return false;
+
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pRecogChannel)
+       {
+               FILE* pAudioIn = pRecogChannel->m_pAudioIn;
+               if(pAudioIn)
+               {
+                       pRecogChannel->m_pAudioIn = NULL;
+                       fclose(pAudioIn);
+               }
+       }
+       
+       /* terminate the demo */
+       return Terminate();
+}
+
+bool RecogSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
+{
+       if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
+               return false;
+
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) 
+       {
+               /* received MRCP response */
+               if(pMrcpMessage->start_line.method_id == RECOGNIZER_DEFINE_GRAMMAR) 
+               {
+                       /* received the response to DEFINE-GRAMMAR request */
+                       if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) 
+                       {
+                               OnDefineGrammar(pMrcpChannel);
+                       }
+                       else 
+                       {
+                               /* received unexpected response, remove channel */
+                               RemoveMrcpChannel(pMrcpChannel);
+                       }
+               }
+               else if(pMrcpMessage->start_line.method_id == RECOGNIZER_RECOGNIZE)
+               {
+                       /* received the response to RECOGNIZE request */
+                       if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS)
+                       {
+                               /* start to stream the speech to recognize */
+                               if(pRecogChannel) 
+                               {
+                                       pRecogChannel->m_Streaming = true;
+                               }
+                       }
+                       else 
+                       {
+                               /* received unexpected response, remove channel */
+                               RemoveMrcpChannel(pMrcpChannel);
+                       }
+               }
+               else 
+               {
+                       /* received unexpected response */
+               }
+       }
+       else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) 
+       {
+               if(pMrcpMessage->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) 
+               {
+                       ParseNLSMLResult(pMrcpMessage);
+                       if(pRecogChannel) 
+                       {
+                               pRecogChannel->m_Streaming = false;
+                       }
+                       RemoveMrcpChannel(pMrcpChannel);
+               }
+               else if(pMrcpMessage->start_line.method_id == RECOGNIZER_START_OF_INPUT) 
+               {
+                       /* received start-of-input, do whatever you need here */
+               }
+       }
+       return true;
+}
+
+bool RecogSession::OnDefineGrammar(mrcp_channel_t* pMrcpChannel)
+{
+       if(GetScenario()->IsRecognizeEnabled())
+       {
+               return StartRecognition(pMrcpChannel);
+       }
+
+       return Terminate();
+}
+
+bool RecogSession::StartRecognition(mrcp_channel_t* pMrcpChannel)
+{
+       RecogChannel* pRecogChannel = (RecogChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       /* create and send RECOGNIZE request */
+       mrcp_message_t* pMrcpMessage = CreateRecognizeRequest(pMrcpChannel);
+       if(pMrcpMessage)
+       {
+               SendMrcpRequest(pRecogChannel->m_pMrcpChannel,pMrcpMessage);
+       }
+
+       const mpf_codec_descriptor_t* pDescriptor = mrcp_application_source_descriptor_get(pMrcpChannel);
+       pRecogChannel->m_pAudioIn = GetAudioIn(pDescriptor,GetSessionPool());
+       if(!pRecogChannel->m_pAudioIn)
+       {
+               /* no audio input availble, set some estimated time to complete instead */
+               pRecogChannel->m_TimeToComplete = 5000; // 5 sec
+       }
+       return true;
+}
+
+mrcp_message_t* RecogSession::CreateDefineGrammarRequest(mrcp_channel_t* pMrcpChannel)
+{
+       mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,RECOGNIZER_DEFINE_GRAMMAR);
+       if(!pMrcpMessage)
+               return NULL;
+
+       const RecogScenario* pScenario = GetScenario();
+
+       mrcp_generic_header_t* pGenericHeader;
+       /* get/allocate generic header */
+       pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pMrcpMessage);
+       if(pGenericHeader) 
+       {
+               /* set generic header fields */
+               if(pScenario->GetContentType())
+               {
+                       apt_string_assign(&pGenericHeader->content_type,pScenario->GetContentType(),pMrcpMessage->pool);
+                       mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_TYPE);
+               }
+               apt_string_assign(&pGenericHeader->content_id,m_ContentId,pMrcpMessage->pool);
+               mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_ID);
+       }
+
+       /* set message body */
+       if(pScenario->GetContent())
+               apt_string_assign(&pMrcpMessage->body,pScenario->GetContent(),pMrcpMessage->pool);
+       return pMrcpMessage;
+}
+
+mrcp_message_t* RecogSession::CreateRecognizeRequest(mrcp_channel_t* pMrcpChannel)
+{
+       mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,RECOGNIZER_RECOGNIZE);
+       if(!pMrcpMessage)
+               return NULL;
+
+       const RecogScenario* pScenario = GetScenario();
+
+       mrcp_generic_header_t* pGenericHeader;
+       mrcp_recog_header_t* pRecogHeader;
+
+       /* get/allocate generic header */
+       pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pMrcpMessage);
+       if(pGenericHeader)
+       {
+               /* set generic header fields */
+               if(pScenario->IsDefineGrammarEnabled())
+               {
+                       apt_string_assign(&pGenericHeader->content_type,"text/uri-list",pMrcpMessage->pool);
+                       /* set message body */
+                       const char* pContent = apr_pstrcat(pMrcpMessage->pool,"session:",m_ContentId,NULL);
+                       apt_string_set(&pMrcpMessage->body,pContent);
+               }
+               else
+               {
+                       apt_string_assign(&pGenericHeader->content_type,pScenario->GetContentType(),pMrcpMessage->pool);
+                       /* set content-id */
+                       apt_string_assign(&pGenericHeader->content_id,m_ContentId,pMrcpMessage->pool);
+                       mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_ID);
+                       /* set message body */
+                       if(pScenario->GetContent())
+                               apt_string_assign(&pMrcpMessage->body,pScenario->GetContent(),pMrcpMessage->pool);
+               }
+               mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_TYPE);
+       }
+       /* get/allocate recognizer header */
+       pRecogHeader = (mrcp_recog_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
+       if(pRecogHeader)
+       {
+               /* set recognizer header fields */
+               if(pMrcpMessage->start_line.version == MRCP_VERSION_2)
+               {
+                       pRecogHeader->cancel_if_queue = FALSE;
+                       mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_CANCEL_IF_QUEUE);
+               }
+               pRecogHeader->no_input_timeout = 5000;
+               mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT);
+               pRecogHeader->recognition_timeout = 10000;
+               mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_RECOGNITION_TIMEOUT);
+               pRecogHeader->start_input_timers = TRUE;
+               mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_START_INPUT_TIMERS);
+               pRecogHeader->confidence_threshold = 0.87f;
+               mrcp_resource_header_property_add(pMrcpMessage,RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD);
+       }
+       return pMrcpMessage;
+}
+
+bool RecogSession::ParseNLSMLResult(mrcp_message_t* pMrcpMessage) const
+{
+       apr_xml_elem* pInterpret;
+       apr_xml_elem* pInstance;
+       apr_xml_elem* pInput;
+       apr_xml_doc* pDoc = nlsml_doc_load(&pMrcpMessage->body,pMrcpMessage->pool);
+       if(!pDoc)
+               return false;
+       
+       /* walk through interpreted results */
+       pInterpret = nlsml_first_interpret_get(pDoc);
+       for(; pInterpret; pInterpret = nlsml_next_interpret_get(pInterpret)) 
+       {
+               /* get instance and input */
+               nlsml_interpret_results_get(pInterpret,&pInstance,&pInput);
+               if(pInstance) 
+               {
+                       /* process instance */
+                       if(pInstance->first_cdata.first) 
+                       {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Interpreted Instance [%s]",pInstance->first_cdata.first->text);
+                       }
+               }
+               if(pInput) 
+               {
+                       /* process input */
+                       if(pInput->first_cdata.first)
+                       {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Interpreted Input [%s]",pInput->first_cdata.first->text);
+                       }
+               }
+       }
+       return true;
+}
+
+FILE* RecogSession::GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const
+{
+       const char* pFileName = GetScenario()->GetAudioSource();
+       if(!pFileName)
+       {
+               pFileName = apr_psprintf(pool,"one-%dkHz.pcm",
+                       pDescriptor ? pDescriptor->sampling_rate/1000 : 8);
+       }
+       apt_dir_layout_t* pDirLayout = GetScenario()->GetDirLayout();
+       const char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool);
+       if(!pFilePath)
+               return NULL;
+       
+       FILE* pFile = fopen(pFilePath,"rb");
+       if(!pFile)
+       {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cannot Find [%s]",pFilePath);
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",pFilePath);
+       return pFile;
+}
diff --git a/libs/unimrcp/platforms/umc/src/recorderscenario.cpp b/libs/unimrcp/platforms/umc/src/recorderscenario.cpp
new file mode 100644 (file)
index 0000000..398fc57
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 <stdlib.h>
+#include "recorderscenario.h"
+#include "recordersession.h"
+
+RecorderScenario::RecorderScenario() :
+       m_Record(true),
+       m_AudioSource(NULL)
+{
+}
+
+RecorderScenario::~RecorderScenario()
+{
+}
+
+void RecorderScenario::Destroy()
+{
+}
+
+bool RecorderScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(UmcScenario::LoadElement(pElem,pool))
+               return true;
+       
+       if(strcasecmp(pElem->name,"record") == 0)
+       {
+               LoadRecord(pElem,pool);
+               return true;
+       }
+               
+       return false;
+}
+
+bool RecorderScenario::LoadRecord(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"enable") == 0)
+               {
+                       m_Record = atoi(pAttr->value) > 0;
+               }
+               else if(strcasecmp(pAttr->name,"audio-source") == 0)
+               {
+                       m_AudioSource = pAttr->value;
+               }
+       }
+
+       return true;
+}
+
+UmcSession* RecorderScenario::CreateSession()
+{
+       return new RecorderSession(this);
+}
diff --git a/libs/unimrcp/platforms/umc/src/recordersession.cpp b/libs/unimrcp/platforms/umc/src/recordersession.cpp
new file mode 100644 (file)
index 0000000..9e0030c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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 "recordersession.h"
+#include "recorderscenario.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_recorder_header.h"
+#include "mrcp_recorder_resource.h"
+#include "apt_log.h"
+
+struct RecorderChannel
+{
+       /** MRCP control channel */
+       mrcp_channel_t* m_pMrcpChannel;
+       /** Streaming is in-progress */
+       bool            m_Streaming;
+       /** File to read audio stream from */
+       FILE*           m_pAudioIn;
+};
+
+RecorderSession::RecorderSession(const RecorderScenario* pScenario) :
+       UmcSession(pScenario),
+       m_pRecorderChannel(NULL)
+{
+}
+
+RecorderSession::~RecorderSession()
+{
+}
+
+bool RecorderSession::Start()
+{
+       const RecorderScenario* pScenario = GetScenario();
+       if(!pScenario->IsRecordEnabled())
+               return false;
+       
+       /* create channel and associate all the required data */
+       m_pRecorderChannel = CreateRecorderChannel();
+       if(!m_pRecorderChannel) 
+               return false;
+
+       /* add channel to session (send asynchronous request) */
+       if(!AddMrcpChannel(m_pRecorderChannel->m_pMrcpChannel))
+       {
+               delete m_pRecorderChannel;
+               m_pRecorderChannel = NULL;
+               return false;
+       }
+       return true;
+}
+
+bool RecorderSession::OnSessionTerminate(mrcp_sig_status_code_e status)
+{
+       if(m_pRecorderChannel)
+       {
+               FILE* pAudioIn = m_pRecorderChannel->m_pAudioIn;
+               if(pAudioIn)
+               {
+                       m_pRecorderChannel->m_pAudioIn = NULL;
+                       fclose(pAudioIn);
+               }
+               
+               delete m_pRecorderChannel;
+               m_pRecorderChannel = NULL;
+       }
+       return UmcSession::OnSessionTerminate(status);
+}
+
+static apt_bool_t ReadStream(mpf_audio_stream_t* pStream, mpf_frame_t* pFrame)
+{
+       RecorderChannel* pRecorderChannel = (RecorderChannel*) pStream->obj;
+       if(pRecorderChannel && pRecorderChannel->m_Streaming) 
+       {
+               if(pRecorderChannel->m_pAudioIn) 
+               {
+                       if(fread(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pRecorderChannel->m_pAudioIn) == pFrame->codec_frame.size) 
+                       {
+                               /* normal read */
+                               pFrame->type |= MEDIA_FRAME_TYPE_AUDIO;
+                       }
+                       else 
+                       {
+                               /* file is over */
+                               pRecorderChannel->m_Streaming = false;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+RecorderChannel* RecorderSession::CreateRecorderChannel()
+{
+       mrcp_channel_t* pChannel;
+       mpf_termination_t* pTermination;
+       mpf_stream_capabilities_t* pCapabilities;
+       apr_pool_t* pool = GetSessionPool();
+
+       /* create channel */
+       RecorderChannel *pRecorderChannel = new RecorderChannel;
+       pRecorderChannel->m_pMrcpChannel = NULL;
+       pRecorderChannel->m_Streaming = false;
+       pRecorderChannel->m_pAudioIn = NULL;
+
+       /* create source stream capabilities */
+       pCapabilities = mpf_source_stream_capabilities_create(pool);
+       GetScenario()->InitCapabilities(pCapabilities);
+
+       static const mpf_audio_stream_vtable_t audio_stream_vtable = 
+       {
+               NULL,
+               NULL,
+               NULL,
+               ReadStream,
+               NULL,
+               NULL,
+               NULL
+       };
+
+       pTermination = CreateAudioTermination(
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       pCapabilities,             /* capabilities of audio stream */
+                       pRecorderChannel);         /* object to associate */
+
+       pChannel = CreateMrcpChannel(
+                       MRCP_RECORDER_RESOURCE,    /* MRCP resource identifier */
+                       pTermination,              /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       pRecorderChannel);         /* object to associate */
+       if(!pChannel)
+       {
+               delete pRecorderChannel;
+               return NULL;
+       }
+       
+       pRecorderChannel->m_pMrcpChannel = pChannel;
+       return pRecorderChannel;
+}
+
+bool RecorderSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
+               return false;
+
+       if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
+       {
+               /* error case, just terminate the demo */
+               return Terminate();
+       }
+
+       return StartRecorder(pMrcpChannel);
+}
+
+bool RecorderSession::OnChannelRemove(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelRemove(pMrcpChannel,status))
+               return false;
+
+       RecorderChannel* pRecorderChannel = (RecorderChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pRecorderChannel)
+       {
+               FILE* pAudioIn = pRecorderChannel->m_pAudioIn;
+               if(pAudioIn)
+               {
+                       pRecorderChannel->m_pAudioIn = NULL;
+                       fclose(pAudioIn);
+               }
+       }
+       
+       /* terminate the demo */
+       return Terminate();
+}
+
+bool RecorderSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
+{
+       if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
+               return false;
+
+       RecorderChannel* pRecorderChannel = (RecorderChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) 
+       {
+               /* received MRCP response */
+               if(pMrcpMessage->start_line.method_id == RECORDER_RECORD)
+               {
+                       /* received the response to RECORD request */
+                       if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS)
+                       {
+                               /* start to stream the speech to record */
+                               if(pRecorderChannel)
+                               {
+                                       pRecorderChannel->m_Streaming = true;
+                               }
+                       }
+                       else 
+                       {
+                               /* received unexpected response, remove channel */
+                               RemoveMrcpChannel(pMrcpChannel);
+                       }
+               }
+               else 
+               {
+                       /* received unexpected response */
+               }
+       }
+       else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) 
+       {
+               if(pMrcpMessage->start_line.method_id == RECORDER_RECORD_COMPLETE) 
+               {
+                       if(pRecorderChannel) 
+                       {
+                               pRecorderChannel->m_Streaming = false;
+                       }
+                       RemoveMrcpChannel(pMrcpChannel);
+               }
+               else if(pMrcpMessage->start_line.method_id == RECORDER_START_OF_INPUT) 
+               {
+                       /* received start-of-input, do whatever you need here */
+               }
+       }
+       return true;
+}
+
+bool RecorderSession::StartRecorder(mrcp_channel_t* pMrcpChannel)
+{
+       RecorderChannel* pRecorderChannel = (RecorderChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       /* create and send RECORD request */
+       mrcp_message_t* pMrcpMessage = CreateRecordRequest(pMrcpChannel);
+       if(pMrcpMessage)
+       {
+               SendMrcpRequest(pRecorderChannel->m_pMrcpChannel,pMrcpMessage);
+       }
+
+       const mpf_codec_descriptor_t* pDescriptor = mrcp_application_source_descriptor_get(pMrcpChannel);
+       pRecorderChannel->m_pAudioIn = GetAudioIn(pDescriptor,GetSessionPool());
+       return true;
+}
+
+mrcp_message_t* RecorderSession::CreateRecordRequest(mrcp_channel_t* pMrcpChannel)
+{
+       mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,RECORDER_RECORD);
+       if(!pMrcpMessage)
+               return NULL;
+
+       mrcp_recorder_header_t* pRecorderHeader;
+
+       /* get/allocate recorder header */
+       pRecorderHeader = (mrcp_recorder_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
+       if(pRecorderHeader)
+       {
+               /* set recorder header fields */
+               pRecorderHeader->no_input_timeout = 5000;
+               mrcp_resource_header_property_add(pMrcpMessage,RECORDER_HEADER_NO_INPUT_TIMEOUT);
+
+               pRecorderHeader->final_silence = 300;
+               mrcp_resource_header_property_add(pMrcpMessage,RECORDER_HEADER_FINAL_SILENCE);
+
+               pRecorderHeader->max_time = 10000;
+               mrcp_resource_header_property_add(pMrcpMessage,RECORDER_HEADER_MAX_TIME);
+       }
+       return pMrcpMessage;
+}
+
+FILE* RecorderSession::GetAudioIn(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const
+{
+       const char* pFileName = GetScenario()->GetAudioSource();
+       if(!pFileName)
+       {
+               pFileName = apr_psprintf(pool,"demo-%dkHz.pcm",
+                       pDescriptor ? pDescriptor->sampling_rate/1000 : 8);
+       }
+       apt_dir_layout_t* pDirLayout = GetScenario()->GetDirLayout();
+       const char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool);
+       if(!pFilePath)
+               return NULL;
+       
+       FILE* pFile = fopen(pFilePath,"rb");
+       if(!pFile)
+       {
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Cannot Find [%s]",pFilePath);
+               return NULL;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set [%s] as Speech Source",pFilePath);
+       return pFile;
+}
diff --git a/libs/unimrcp/platforms/umc/src/synthscenario.cpp b/libs/unimrcp/platforms/umc/src/synthscenario.cpp
new file mode 100644 (file)
index 0000000..37c9d66
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 <stdlib.h>
+#include "synthscenario.h"
+#include "synthsession.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+
+
+SynthScenario::SynthScenario() :
+       m_Speak(true),
+       m_ContentType("application/synthesis+ssml"),
+       m_Content(NULL)
+{
+}
+
+SynthScenario::~SynthScenario()
+{
+}
+
+void SynthScenario::Destroy()
+{
+}
+
+bool SynthScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(UmcScenario::LoadElement(pElem,pool))
+               return true;
+       
+       if(strcasecmp(pElem->name,"speak") == 0)
+       {
+               LoadSpeak(pElem,pool);
+               return true;
+       }
+               
+       return false;
+}
+
+bool SynthScenario::LoadSpeak(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"enable") == 0)
+               {
+                       m_Speak = atoi(pAttr->value) > 0;
+               }
+               else if(strcasecmp(pAttr->name,"content-type") == 0)
+               {
+                       m_ContentType = pAttr->value;
+               }
+               else if(strcasecmp(pAttr->name,"content-location") == 0)
+               {
+                       m_Content = LoadFileContent(pAttr->value,pool);
+               }
+       }
+
+       return true;
+}
+
+UmcSession* SynthScenario::CreateSession()
+{
+       return new SynthSession(this);
+}
diff --git a/libs/unimrcp/platforms/umc/src/synthsession.cpp b/libs/unimrcp/platforms/umc/src/synthsession.cpp
new file mode 100644 (file)
index 0000000..c5a2fad
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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 "synthsession.h"
+#include "synthscenario.h"
+#include "mrcp_message.h"
+#include "mrcp_generic_header.h"
+#include "mrcp_synth_header.h"
+#include "mrcp_synth_resource.h"
+
+struct SynthChannel
+{
+       mrcp_channel_t* m_pMrcpChannel;
+       /** File to write audio stream to */
+       FILE*           m_pAudioOut;
+};
+
+SynthSession::SynthSession(const SynthScenario* pScenario) :
+       UmcSession(pScenario),
+       m_pSynthChannel(NULL)
+{
+}
+
+SynthSession::~SynthSession()
+{
+}
+
+bool SynthSession::Start()
+{
+       if(!GetScenario()->IsSpeakEnabled())
+               return false;
+       
+       /* create channel and associate all the required data */
+       m_pSynthChannel = CreateSynthChannel();
+       if(!m_pSynthChannel) 
+               return false;
+
+       /* add channel to session (send asynchronous request) */
+       if(!AddMrcpChannel(m_pSynthChannel->m_pMrcpChannel))
+       {
+               delete m_pSynthChannel;
+               m_pSynthChannel = NULL;
+               return false;
+       }
+       return true;
+}
+
+bool SynthSession::OnSessionTerminate(mrcp_sig_status_code_e status)
+{
+       if(m_pSynthChannel)
+       {
+               FILE* pAudioOut = m_pSynthChannel->m_pAudioOut;
+               if(pAudioOut) 
+               {
+                       m_pSynthChannel->m_pAudioOut = NULL;
+                       fclose(pAudioOut);
+               }
+
+               delete m_pSynthChannel;
+               m_pSynthChannel = NULL;
+       }
+       return UmcSession::OnSessionTerminate(status);
+}
+
+static apt_bool_t WriteStream(mpf_audio_stream_t* pStream, const mpf_frame_t* pFrame)
+{
+       SynthChannel* pSynthChannel = (SynthChannel*) pStream->obj;
+       if(pSynthChannel && pSynthChannel->m_pAudioOut) 
+       {
+               fwrite(pFrame->codec_frame.buffer,1,pFrame->codec_frame.size,pSynthChannel->m_pAudioOut);
+       }
+       return TRUE;
+}
+
+SynthChannel* SynthSession::CreateSynthChannel()
+{
+       mrcp_channel_t* pChannel;
+       mpf_termination_t* pTermination;
+       mpf_stream_capabilities_t* pCapabilities;
+       apr_pool_t* pool = GetSessionPool();
+
+       /* create channel */
+       SynthChannel *pSynthChannel = new SynthChannel;
+       pSynthChannel->m_pMrcpChannel = NULL;
+
+       /* create sink stream capabilities */
+       pCapabilities = mpf_sink_stream_capabilities_create(pool);
+       GetScenario()->InitCapabilities(pCapabilities);
+
+       static const mpf_audio_stream_vtable_t audio_stream_vtable = 
+       {
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               WriteStream
+       };
+
+       pTermination = CreateAudioTermination(
+                       &audio_stream_vtable,      /* virtual methods table of audio stream */
+                       pCapabilities,             /* capabilities of audio stream */
+                       pSynthChannel);            /* object to associate */
+       
+       pChannel = CreateMrcpChannel(
+                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                       pTermination,              /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       pSynthChannel);            /* object to associate */
+       if(!pChannel)
+       {
+               delete pSynthChannel;
+               return NULL;
+       }
+
+       pSynthChannel->m_pMrcpChannel = pChannel;
+       pSynthChannel->m_pAudioOut = NULL;
+       return pSynthChannel;
+}
+
+bool SynthSession::OnChannelAdd(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelAdd(pMrcpChannel,status))
+               return false;
+
+       SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(status != MRCP_SIG_STATUS_CODE_SUCCESS)
+       {
+               /* error case, just terminate the demo */
+               return Terminate();
+       }
+
+       /* create MRCP message */
+       mrcp_message_t* pMrcpMessage = CreateSpeakRequest(pMrcpChannel);
+       if(pMrcpMessage) 
+       {
+               SendMrcpRequest(pSynthChannel->m_pMrcpChannel,pMrcpMessage);
+       }
+
+       const mpf_codec_descriptor_t* pDescriptor = mrcp_application_sink_descriptor_get(pMrcpChannel);
+       pSynthChannel->m_pAudioOut = GetAudioOut(pDescriptor,GetSessionPool());
+       return true;
+}
+
+bool SynthSession::OnChannelRemove(mrcp_channel_t* pMrcpChannel, mrcp_sig_status_code_e status)
+{
+       if(!UmcSession::OnChannelRemove(pMrcpChannel,status))
+               return false;
+
+       SynthChannel* pSynthChannel = (SynthChannel*) mrcp_application_channel_object_get(pMrcpChannel);
+       if(pSynthChannel) 
+       {
+               FILE* pAudioOut = pSynthChannel->m_pAudioOut;
+               if(pAudioOut) 
+               {
+                       pSynthChannel->m_pAudioOut = NULL;
+                       fclose(pAudioOut);
+               }
+       }
+
+       /* terminate the demo */
+       return Terminate();
+}
+
+bool SynthSession::OnMessageReceive(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
+{
+       if(!UmcSession::OnMessageReceive(pMrcpChannel,pMrcpMessage))
+               return false;
+
+       if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) 
+       {
+               /* received MRCP response */
+               if(pMrcpMessage->start_line.method_id == SYNTHESIZER_SPEAK) 
+               {
+                       /* received the response to SPEAK request */
+                       if(pMrcpMessage->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) 
+                       {
+                               /* waiting for SPEAK-COMPLETE event */
+                       }
+                       else 
+                       {
+                               /* received unexpected response, remove channel */
+                               RemoveMrcpChannel(pMrcpChannel);
+                       }
+               }
+               else 
+               {
+                       /* received unexpected response */
+               }
+       }
+       else if(pMrcpMessage->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) 
+       {
+               /* received MRCP event */
+               if(pMrcpMessage->start_line.method_id == SYNTHESIZER_SPEAK_COMPLETE) 
+               {
+                       /* received SPEAK-COMPLETE event, remove channel */
+                       RemoveMrcpChannel(pMrcpChannel);
+               }
+       }
+       return true;
+}
+
+mrcp_message_t* SynthSession::CreateSpeakRequest(mrcp_channel_t* pMrcpChannel)
+{
+       mrcp_message_t* pMrcpMessage = CreateMrcpMessage(pMrcpChannel,SYNTHESIZER_SPEAK);
+       if(!pMrcpMessage)
+               return NULL;
+
+       const SynthScenario* pScenario = GetScenario();
+
+       mrcp_generic_header_t* pGenericHeader;
+       mrcp_synth_header_t* pSynthHeader;
+       /* get/allocate generic header */
+       pGenericHeader = (mrcp_generic_header_t*) mrcp_generic_header_prepare(pMrcpMessage);
+       if(pGenericHeader) 
+       {
+               /* set generic header fields */
+               apt_string_assign(&pGenericHeader->content_type,pScenario->GetContentType(),pMrcpMessage->pool);
+               mrcp_generic_header_property_add(pMrcpMessage,GENERIC_HEADER_CONTENT_TYPE);
+
+               /* set message body */
+               if(pScenario->GetContent())
+                       apt_string_assign(&pMrcpMessage->body,pScenario->GetContent(),pMrcpMessage->pool);
+       }
+       /* get/allocate synthesizer header */
+       pSynthHeader = (mrcp_synth_header_t*) mrcp_resource_header_prepare(pMrcpMessage);
+       if(pSynthHeader) 
+       {
+               /* set synthesizer header fields */
+               pSynthHeader->voice_param.age = 28;
+               mrcp_resource_header_property_add(pMrcpMessage,SYNTHESIZER_HEADER_VOICE_AGE);
+       }
+
+       return pMrcpMessage;
+}
+
+FILE* SynthSession::GetAudioOut(const mpf_codec_descriptor_t* pDescriptor, apr_pool_t* pool) const
+{
+       char* pFileName = apr_psprintf(pool,"synth-%dkHz-%s.pcm",
+               pDescriptor ? pDescriptor->sampling_rate/1000 : 8, GetMrcpSessionId());
+       apt_dir_layout_t* pDirLayout = GetScenario()->GetDirLayout();
+       char* pFilePath = apt_datadir_filepath_get(pDirLayout,pFileName,pool);
+       if(!pFilePath) 
+               return NULL;
+
+       return fopen(pFilePath,"wb");
+}
diff --git a/libs/unimrcp/platforms/umc/src/umcconsole.cpp b/libs/unimrcp/platforms/umc/src/umcconsole.cpp
new file mode 100644 (file)
index 0000000..0881e40
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <apr_getopt.h>
+#include "umcconsole.h"
+#include "umcframework.h"
+#include "apt_pool.h"
+
+
+UmcConsole::UmcConsole() :
+       m_pFramework(NULL)
+{
+       m_pFramework = new UmcFramework;
+}
+
+UmcConsole::~UmcConsole()
+{
+       delete m_pFramework;
+}
+
+bool UmcConsole::Run(int argc, const char * const *argv)
+{
+       apr_pool_t* pool = NULL;
+       apt_dir_layout_t* pDirLayout = NULL;
+
+       /* APR global initialization */
+       if(apr_initialize() != APR_SUCCESS) 
+       {
+               apr_terminate();
+               return false;
+       }
+
+       /* create APR pool */
+       pool = apt_pool_create();
+       if(!pool) 
+       {
+               apr_terminate();
+               return false;
+       }
+
+       /* load options */
+       if(!LoadOptions(argc,argv,pool))
+       {
+               apr_pool_destroy(pool);
+               apr_terminate();
+               return false;
+       }
+
+       /* create the structure of default directories layout */
+       pDirLayout = apt_default_dir_layout_create(m_Options.m_RootDirPath,pool);
+       /* create singleton logger */
+       apt_log_instance_create(m_Options.m_LogOutput,m_Options.m_LogPriority,pool);
+
+       if((m_Options.m_LogOutput & APT_LOG_OUTPUT_FILE) == APT_LOG_OUTPUT_FILE) 
+       {
+               /* open the log file */
+               apt_log_file_open(pDirLayout->log_dir_path,"unimrcpclient",MAX_LOG_FILE_SIZE,MAX_LOG_FILE_COUNT,pool);
+       }
+
+       /* create demo framework */
+       if(m_pFramework->Create(pDirLayout,pool))
+       {
+               /* run command line  */
+               RunCmdLine();
+               /* destroy demo framework */
+               m_pFramework->Destroy();
+       }
+
+       /* destroy singleton logger */
+       apt_log_instance_destroy();
+       /* destroy APR pool */
+       apr_pool_destroy(pool);
+       /* APR global termination */
+       apr_terminate();
+       return true;
+}
+
+bool UmcConsole::ProcessCmdLine(char* pCmdLine)
+{
+       bool running = true;
+       char *name;
+       char *last;
+       name = apr_strtok(pCmdLine, " ", &last);
+
+       if(strcasecmp(name,"run") == 0)
+       {
+               char* pScenarioName = apr_strtok(NULL, " ", &last);
+               if(pScenarioName) 
+               {
+                       char* pProfileName = apr_strtok(NULL, " ", &last);
+                       if(!pProfileName) 
+                       {
+                               pProfileName = "MRCPv2-Default";
+                       }
+                       m_pFramework->RunSession(pScenarioName,pProfileName);
+               }
+       }
+       else if(strcasecmp(name,"kill") == 0)
+       {
+               char* pID = apr_strtok(NULL, " ", &last);
+               if(pID) 
+               {
+                       m_pFramework->KillSession(pID);
+               }
+       }
+       else if(strcasecmp(name,"show") == 0)
+       {
+               char* pWhat = apr_strtok(NULL, " ", &last);
+               if(pWhat) 
+               {
+                       if(strcasecmp(pWhat,"sessions") == 0)
+                               m_pFramework->ShowSessions();
+                       else if(strcasecmp(pWhat,"scenarios") == 0)
+                               m_pFramework->ShowScenarios();
+               }
+       }
+       else if(strcasecmp(name,"loglevel") == 0) 
+       {
+               char* pPriority = apr_strtok(NULL, " ", &last);
+               if(pPriority) 
+               {
+                       apt_log_priority_set((apt_log_priority_e)atol(pPriority));
+               }
+       }
+       else if(strcasecmp(name,"exit") == 0 || strcmp(name,"quit") == 0) 
+       {
+               running = false;
+       }
+       else if(strcasecmp(name,"help") == 0) 
+       {
+               printf("usage:\n"
+                      "\n- run [scenario] [profile] (run new session)\n"
+                          "       scenario is one of 'synth', 'recog', ... (use 'show scenarios')\n"
+                          "       profile is one of 'MRCPv2-Default', 'MRCPv1-Default', ... (see unimrcpclient.xml)\n"
+                          "\n       examples: \n"
+                          "           run synth\n"
+                          "           run recog\n"
+                          "           run synth MRCPv1-Default\n"
+                          "           run recog MRCPv1-Default\n"
+                      "\n- kill [id] (kill session)\n"
+                          "       id is a session identifier: 1, 2, ... (use 'show sessions')\n"
+                          "\n       example: \n"
+                          "           kill 1\n"
+                      "\n- show [what] (show either available scenarios or in-progress sessions)\n"
+                          "\n       examples: \n"
+                          "           show scenarios\n"
+                          "           show sessions\n"
+                      "\n- loglevel [level] (set loglevel, one of 0,1...7)\n"
+                      "\n- quit, exit\n");
+       }
+       else 
+       {
+               printf("unknown command: %s (input help for usage)\n",name);
+       }
+       return running;
+}
+
+bool UmcConsole::RunCmdLine()
+{
+       apt_bool_t running = true;
+       char cmdline[1024];
+       int i;
+       do 
+       {
+               printf(">");
+               memset(&cmdline, 0, sizeof(cmdline));
+               for(i = 0; i < sizeof(cmdline); i++) 
+               {
+                       cmdline[i] = (char) getchar();
+                       if(cmdline[i] == '\n') 
+                       {
+                               cmdline[i] = '\0';
+                               break;
+                       }
+               }
+               if(*cmdline) 
+               {
+                       running = ProcessCmdLine(cmdline);
+               }
+       }
+       while(running != 0);
+       return true;
+}
+
+void UmcConsole::Usage() const
+{
+       printf(
+               "\n"
+               "Usage:\n"
+               "\n"
+               "  umc [options]\n"
+               "\n"
+               "  Available options:\n"
+               "\n"
+               "   -r [--root-dir] path     : Set the project root directory path.\n"
+               "\n"
+               "   -l [--log-prio] priority : Set the log priority.\n"
+               "                              (0-emergency, ..., 7-debug)\n"
+               "\n"
+               "   -o [--log-output] mode   : Set the log output mode.\n"
+               "                              (0-none, 1-console only, 2-file only, 3-both)\n"
+               "\n"
+               "   -h [--help]              : Show the help.\n"
+               "\n");
+}
+
+bool UmcConsole::LoadOptions(int argc, const char * const *argv, apr_pool_t *pool)
+{
+       apr_status_t rv;
+       apr_getopt_t* opt = NULL;
+       int optch;
+       const char* optarg;
+
+       const apr_getopt_option_t opt_option[] = 
+       {
+               /* long-option, short-option, has-arg flag, description */
+               { "root-dir",    'r', TRUE,  "path to root dir" },  /* -r arg or --root-dir arg */
+               { "log-prio",    'l', TRUE,  "log priority" },      /* -l arg or --log-prio arg */
+               { "log-output",  'o', TRUE,  "log output mode" },   /* -o arg or --log-output arg */
+               { "help",        'h', FALSE, "show help" },         /* -h or --help */
+               { NULL, 0, 0, NULL },                               /* end */
+       };
+
+       /* set the default options */
+       m_Options.m_RootDirPath = "../";
+       m_Options.m_LogPriority = APT_PRIO_INFO;
+       m_Options.m_LogOutput = APT_LOG_OUTPUT_CONSOLE;
+
+       rv = apr_getopt_init(&opt, pool , argc, argv);
+       if(rv != APR_SUCCESS)
+               return false;
+
+       while((rv = apr_getopt_long(opt, opt_option, &optch, &optarg)) == APR_SUCCESS) 
+       {
+               switch(optch) 
+               {
+                       case 'r':
+                               m_Options.m_RootDirPath = optarg;
+                               break;
+                       case 'l':
+                               if(optarg) 
+                               {
+                                       m_Options.m_LogPriority = (apt_log_priority_e) atoi(optarg);
+                               }
+                               break;
+                       case 'o':
+                               if(optarg) 
+                               {
+                                       m_Options.m_LogOutput = (apt_log_output_e) atoi(optarg);
+                               }
+                               break;
+                       case 'h':
+                               Usage();
+                               return FALSE;
+               }
+       }
+
+       if(rv != APR_EOF) 
+       {
+               Usage();
+               return false;
+       }
+
+       return true;
+}
diff --git a/libs/unimrcp/platforms/umc/src/umcframework.cpp b/libs/unimrcp/platforms/umc/src/umcframework.cpp
new file mode 100644 (file)
index 0000000..aa9b9ed
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * 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 "umcframework.h"
+#include "umcsession.h"
+#include "synthscenario.h"
+#include "recogscenario.h"
+#include "recorderscenario.h"
+#include "dtmfscenario.h"
+#include "unimrcp_client.h"
+#include "apt_log.h"
+
+typedef struct
+{
+       char                      m_SessionId[10];
+       char                      m_ScenarioName[128];
+       char                      m_ProfileName[128];
+       const mrcp_app_message_t* m_pAppMessage;
+} UmcTaskMsg;
+
+enum UmcTaskMsgType
+{
+       UMC_TASK_CLIENT_MSG,
+       UMC_TASK_RUN_SESSION_MSG,
+       UMC_TASK_KILL_SESSION_MSG,
+       UMC_TASK_SHOW_SCENARIOS_MSG,
+       UMC_TASK_SHOW_SESSIONS_MSG
+};
+
+apt_bool_t UmcProcessMsg(apt_task_t* pTask, apt_task_msg_t* pMsg);
+void UmcOnStartComplete(apt_task_t* pTask);
+void UmcOnTerminateComplete(apt_task_t* pTask);
+apt_bool_t AppMessageHandler(const mrcp_app_message_t* pAppMessage);
+
+
+UmcFramework::UmcFramework() :
+       m_pPool(NULL),
+       m_pDirLayout(NULL),
+       m_pTask(NULL),
+       m_pMrcpClient(NULL),
+       m_pMrcpApplication(NULL),
+       m_Ready(false),
+       m_pScenarioTable(NULL),
+       m_pSessionTable(NULL)
+{
+}
+
+UmcFramework::~UmcFramework()
+{
+}
+
+bool UmcFramework::Create(apt_dir_layout_t* pDirLayout, apr_pool_t* pool)
+{
+       m_pDirLayout = pDirLayout;
+       m_pPool = pool;
+
+       m_pSessionTable = apr_hash_make(m_pPool);
+       m_pScenarioTable = apr_hash_make(m_pPool);
+       if(!CreateTask())
+               return false;
+
+       /* wait for READY state,
+          preferably cond wait object should be used */
+       int attempts = 0;
+       while(!m_Ready && attempts < 10)
+       {
+               attempts++;
+               apr_sleep(500000);
+       }
+
+       return true;
+}
+
+void UmcFramework::Destroy()
+{
+       DestroyTask();
+
+       m_pScenarioTable = NULL;
+       m_pSessionTable = NULL;
+}
+
+bool UmcFramework::CreateMrcpClient()
+{
+       /* create MRCP client stack first */
+       m_pMrcpClient = unimrcp_client_create(m_pDirLayout);
+       if(!m_pMrcpClient)
+               return false;
+
+       /* create MRCP application to send/get requests to/from MRCP client stack */
+       m_pMrcpApplication = mrcp_application_create(AppMessageHandler,this,m_pPool);
+       if(!m_pMrcpApplication)
+       {
+               mrcp_client_destroy(m_pMrcpClient);
+               m_pMrcpClient = NULL;
+               return false;
+       }
+
+       /* register MRCP application to MRCP client */
+       mrcp_client_application_register(m_pMrcpClient,m_pMrcpApplication,"UMC");
+       /* start MRCP client stack processing */
+       if(mrcp_client_start(m_pMrcpClient) == FALSE)
+       {
+               mrcp_client_destroy(m_pMrcpClient);
+               m_pMrcpClient = NULL;
+               m_pMrcpApplication = NULL;
+               return false;
+       }
+       return true;
+}
+
+void UmcFramework::DestroyMrcpClient()
+{
+       if(m_pMrcpClient)
+       {
+               /* shutdown MRCP client stack processing first (blocking call) */
+               mrcp_client_shutdown(m_pMrcpClient);
+               /* destroy MRCP client stack */
+               mrcp_client_destroy(m_pMrcpClient);
+               m_pMrcpClient = NULL;
+               m_pMrcpApplication = NULL;
+       }
+}
+
+bool UmcFramework::CreateTask()
+{
+       apt_task_t* pTask;
+       apt_task_vtable_t* pVtable;
+       apt_task_msg_pool_t* pMsgPool;
+
+       pMsgPool = apt_task_msg_pool_create_dynamic(sizeof(UmcTaskMsg),m_pPool);
+       m_pTask = apt_consumer_task_create(this,pMsgPool,m_pPool);
+       if(!m_pTask)
+               return false;
+
+       pTask = apt_consumer_task_base_get(m_pTask);
+       apt_task_name_set(pTask,"Framework Task");
+       pVtable = apt_consumer_task_vtable_get(m_pTask);
+       if(pVtable) 
+       {
+               pVtable->process_msg = UmcProcessMsg;
+               pVtable->on_start_complete = UmcOnStartComplete;
+               pVtable->on_terminate_complete = UmcOnTerminateComplete;
+       }
+
+       m_Ready = false;
+       apt_task_start(pTask);
+       return true;
+}
+
+void UmcFramework::DestroyTask()
+{
+       if(m_pTask)
+       {
+               apt_task_t* pTask = apt_consumer_task_base_get(m_pTask);
+               if(pTask)
+               {
+                       apt_task_terminate(pTask,TRUE);
+                       apt_task_destroy(pTask);
+               }
+               m_pTask = NULL;
+       }
+}
+
+UmcScenario* UmcFramework::CreateScenario(const char* pType)
+{
+       if(pType)
+       {
+               if(strcasecmp(pType,"Synthesizer") == 0)
+                       return new SynthScenario();
+               else if(strcasecmp(pType,"Recognizer") == 0)
+                       return new RecogScenario();
+               else if(strcasecmp(pType,"Recorder") == 0)
+                       return new RecorderScenario();
+               else if(strcasecmp(pType,"DtmfRecognizer") == 0)
+                       return new DtmfScenario();
+       }
+       return NULL;
+}
+
+apr_xml_doc* UmcFramework::LoadDocument()
+{
+       apr_xml_parser* pParser = NULL;
+       apr_xml_doc* pDoc = NULL;
+       apr_file_t* pFD = NULL;
+       apr_status_t rv;
+       const char* pFilePath;
+
+       pFilePath = apr_psprintf(m_pPool,"%s/%s",m_pDirLayout->conf_dir_path,"umcscenarios.xml");
+
+       apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Open Config File [%s]",pFilePath);
+       rv = apr_file_open(&pFD,pFilePath,APR_READ|APR_BINARY,0,m_pPool);
+       if(rv != APR_SUCCESS) 
+       {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Config File [%s]",pFilePath);
+               return NULL;
+       }
+
+       rv = apr_xml_parse_file(m_pPool,&pParser,&pDoc,pFD,2000);
+       if(rv != APR_SUCCESS) 
+       {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",pFilePath);
+               pDoc = NULL;
+       }
+
+       apr_file_close(pFD);
+       return pDoc;
+}
+
+bool UmcFramework::LoadScenarios()
+{
+       apr_xml_doc* pDoc = LoadDocument();
+       if(!pDoc)
+               return false;
+
+       const apr_xml_attr* pAttr;
+       const apr_xml_elem* pElem;
+       const apr_xml_elem* pRoot = pDoc->root;
+       if(!pRoot || strcasecmp(pRoot->name,"umcscenarios") != 0)
+       {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document");
+               return FALSE;
+       }
+       for(pElem = pRoot->first_child; pElem; pElem = pElem->next)
+       {
+               if(strcasecmp(pElem->name,"scenario") != 0)
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",pElem->name);
+                       continue;
+               }
+               
+               const char* pName = NULL;
+               const char* pClass = NULL;
+               const char* pMrcpProfile = NULL;
+               for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+               {
+                       if(strcasecmp(pAttr->name,"name") == 0) 
+                       {
+                               pName = pAttr->value;
+                       }
+                       else if(strcasecmp(pAttr->name,"class") == 0) 
+                       {
+                               pClass = pAttr->value;
+                       }
+                       else if(strcasecmp(pAttr->name,"profile") == 0) 
+                       {
+                               pMrcpProfile = pAttr->value;
+                       }
+               }
+
+               if(pName && pClass)
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Load Scenario name [%s] class [%s]",pName,pClass);
+                       UmcScenario* pScenario = CreateScenario(pClass);
+                       if(pScenario)
+                       {
+                               pScenario->SetDirLayout(m_pDirLayout);
+                               pScenario->SetName(pName);
+                               pScenario->SetMrcpProfile(pMrcpProfile);
+                               if(pScenario->Load(pElem,m_pPool))
+                                       apr_hash_set(m_pScenarioTable,pScenario->GetName(),APR_HASH_KEY_STRING,pScenario);
+                               else
+                                       delete pScenario;
+                       }
+                       else
+                       {
+                               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No such scenario <%s>",pClass);
+                       }
+               }
+               else
+               {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing either name or class of the scenario");
+               }
+       }
+       return true;
+}
+
+void UmcFramework::DestroyScenarios()
+{
+       UmcScenario* pScenario;
+       void* pVal;
+       apr_hash_index_t* it = apr_hash_first(m_pPool,m_pScenarioTable);
+       for(; it; it = apr_hash_next(it)) 
+       {
+               apr_hash_this(it,NULL,NULL,&pVal);
+               pScenario = (UmcScenario*) pVal;
+               if(pScenario)
+               {
+                       pScenario->Destroy();
+                       delete pScenario;
+               }
+       }
+       apr_hash_clear(m_pScenarioTable);
+}
+
+bool UmcFramework::AddSession(UmcSession* pSession)
+{
+       if(!pSession)
+               return false;
+
+       apr_hash_set(m_pSessionTable,pSession->GetId(),APR_HASH_KEY_STRING,pSession);
+       return true;
+}
+
+bool UmcFramework::RemoveSession(UmcSession* pSession)
+{
+       if(!pSession)
+               return false;
+
+       apr_hash_set(m_pSessionTable,pSession->GetId(),APR_HASH_KEY_STRING,NULL);
+       return true;
+}
+
+bool UmcFramework::ProcessRunRequest(const char* pScenarioName, const char* pProfileName)
+{
+       UmcScenario* pScenario = (UmcScenario*) apr_hash_get(m_pScenarioTable,pScenarioName,APR_HASH_KEY_STRING);
+       if(!pScenario)
+               return false;
+
+       UmcSession* pSession = pScenario->CreateSession();
+       if(!pSession)
+               return false;
+
+       printf("[%s]\n",pSession->GetId());
+       pSession->SetMrcpProfile(pProfileName);
+       pSession->SetMrcpApplication(m_pMrcpApplication);
+       if(!pSession->Run())
+       {
+               delete pSession;
+               return false;
+       }
+
+       AddSession(pSession);
+       return true;
+}
+
+void UmcFramework::ProcessKillRequest(const char* id)
+{
+       UmcSession* pSession;
+       void* pVal;
+       apr_hash_index_t* it = apr_hash_first(m_pPool,m_pSessionTable);
+       for(; it; it = apr_hash_next(it)) 
+       {
+               apr_hash_this(it,NULL,NULL,&pVal);
+               pSession = (UmcSession*) pVal;
+               if(pSession && strcasecmp(pSession->GetId(),id) == 0)
+               {
+                       /* first, terminate session */
+                       pSession->Terminate();
+                       return;
+               }
+       }
+}
+
+void UmcFramework::ProcessShowScenarios()
+{
+       UmcScenario* pScenario;
+       void* pVal;
+       printf("%d Scenario(s)\n", apr_hash_count(m_pScenarioTable));
+       apr_hash_index_t* it = apr_hash_first(m_pPool,m_pScenarioTable);
+       for(; it; it = apr_hash_next(it))
+       {
+               apr_hash_this(it,NULL,NULL,&pVal);
+               pScenario = (UmcScenario*) pVal;
+               if(pScenario)
+               {
+                       printf("[%s]\n", pScenario->GetName());
+               }
+       }
+}
+
+void UmcFramework::ProcessShowSessions()
+{
+       UmcSession* pSession;
+       void* pVal;
+       printf("%d Session(s)\n", apr_hash_count(m_pSessionTable));
+       apr_hash_index_t* it = apr_hash_first(m_pPool,m_pSessionTable);
+       for(; it; it = apr_hash_next(it)) 
+       {
+               apr_hash_this(it,NULL,NULL,&pVal);
+               pSession = (UmcSession*) pVal;
+               if(pSession)
+               {
+                       printf("[%s] - %s\n", pSession->GetId(), pSession->GetScenario()->GetName());
+               }
+       }
+}
+
+void UmcFramework::RunSession(const char* pScenarioName, const char* pProfileName)
+{
+       apt_task_t* pTask = apt_consumer_task_base_get(m_pTask);
+       apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask);
+       if(!pTaskMsg) 
+               return;
+
+       pTaskMsg->type = TASK_MSG_USER;
+       pTaskMsg->sub_type = UMC_TASK_RUN_SESSION_MSG;
+       UmcTaskMsg* pUmcMsg = (UmcTaskMsg*) pTaskMsg->data;
+       strncpy(pUmcMsg->m_ScenarioName,pScenarioName,sizeof(pUmcMsg->m_ScenarioName)-1);
+       strncpy(pUmcMsg->m_ProfileName,pProfileName,sizeof(pUmcMsg->m_ProfileName)-1);
+       pUmcMsg->m_pAppMessage = NULL;
+       apt_task_msg_signal(pTask,pTaskMsg);
+}
+
+void UmcFramework::KillSession(const char* id)
+{
+       apt_task_t* pTask = apt_consumer_task_base_get(m_pTask);
+       apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask);
+       if(!pTaskMsg) 
+               return;
+
+       pTaskMsg->type = TASK_MSG_USER;
+       pTaskMsg->sub_type = UMC_TASK_KILL_SESSION_MSG;
+       
+       UmcTaskMsg* pUmcMsg = (UmcTaskMsg*) pTaskMsg->data;
+       strncpy(pUmcMsg->m_SessionId,id,sizeof(pUmcMsg->m_SessionId)-1);
+       pUmcMsg->m_pAppMessage = NULL;
+       apt_task_msg_signal(pTask,pTaskMsg);
+}
+
+void UmcFramework::ShowScenarios()
+{
+       apt_task_t* pTask = apt_consumer_task_base_get(m_pTask);
+       apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask);
+       if(!pTaskMsg) 
+               return;
+
+       pTaskMsg->type = TASK_MSG_USER;
+       pTaskMsg->sub_type = UMC_TASK_SHOW_SCENARIOS_MSG;
+       apt_task_msg_signal(pTask,pTaskMsg);
+}
+
+void UmcFramework::ShowSessions()
+{
+       apt_task_t* pTask = apt_consumer_task_base_get(m_pTask);
+       apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask);
+       if(!pTaskMsg) 
+               return;
+
+       pTaskMsg->type = TASK_MSG_USER;
+       pTaskMsg->sub_type = UMC_TASK_SHOW_SESSIONS_MSG;
+       apt_task_msg_signal(pTask,pTaskMsg);
+}
+
+apt_bool_t AppMessageHandler(const mrcp_app_message_t* pMessage)
+{
+       UmcFramework* pFramework = (UmcFramework*) mrcp_application_object_get(pMessage->application);
+       if(!pFramework)
+               return FALSE;
+
+       apt_task_t* pTask = apt_consumer_task_base_get(pFramework->m_pTask);
+       apt_task_msg_t* pTaskMsg = apt_task_msg_get(pTask);
+       if(pTaskMsg) 
+       {
+               pTaskMsg->type = TASK_MSG_USER;
+               pTaskMsg->sub_type = UMC_TASK_CLIENT_MSG;
+               
+               UmcTaskMsg* pUmcMsg = (UmcTaskMsg*) pTaskMsg->data;
+               pUmcMsg->m_pAppMessage = pMessage;
+               apt_task_msg_signal(pTask,pTaskMsg);
+       }
+       
+       return TRUE;
+}
+
+
+apt_bool_t AppOnSessionUpdate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnSessionUpdate(status);
+}
+
+apt_bool_t AppOnSessionTerminate(mrcp_application_t *application, mrcp_session_t *session, mrcp_sig_status_code_e status)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       if(!pSession->OnSessionTerminate(status))
+               return false;
+
+       UmcFramework* pFramework = (UmcFramework*) mrcp_application_object_get(application);
+       pFramework->RemoveSession(pSession);
+       delete pSession;
+       return true;
+}
+
+apt_bool_t AppOnChannelAdd(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnChannelAdd(channel,status);
+}
+
+apt_bool_t AppOnChannelRemove(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnChannelRemove(channel,status);
+}
+
+apt_bool_t AppOnMessageReceive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnMessageReceive(channel,message);
+}
+
+apt_bool_t AppOnTerminateEvent(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnTerminateEvent(channel);
+}
+
+apt_bool_t AppOnResourceDiscover(mrcp_application_t *application, mrcp_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_sig_status_code_e status)
+{
+       UmcSession* pSession = (UmcSession*) mrcp_application_session_object_get(session);
+       return pSession->OnResourceDiscover(descriptor,status);
+}
+
+apt_bool_t AppOnReady(mrcp_application_t *application, mrcp_sig_status_code_e status)
+{
+       UmcFramework* pFramework = (UmcFramework*) mrcp_application_object_get(application);
+       pFramework->m_Ready = true;
+       return TRUE;
+}
+
+void UmcOnStartComplete(apt_task_t* pTask)
+{
+       apt_consumer_task_t* pConsumerTask = (apt_consumer_task_t*) apt_task_object_get(pTask);
+       UmcFramework* pFramework = (UmcFramework*) apt_consumer_task_object_get(pConsumerTask);
+       
+       pFramework->CreateMrcpClient();
+       pFramework->LoadScenarios();
+}
+
+void UmcOnTerminateComplete(apt_task_t* pTask)
+{
+       apt_consumer_task_t* pConsumerTask = (apt_consumer_task_t*) apt_task_object_get(pTask);
+       UmcFramework* pFramework = (UmcFramework*) apt_consumer_task_object_get(pConsumerTask);
+
+       pFramework->DestroyMrcpClient();
+       pFramework->DestroyScenarios();
+}
+
+apt_bool_t UmcProcessMsg(apt_task_t *pTask, apt_task_msg_t *pMsg)
+{
+       if(pMsg->type != TASK_MSG_USER)
+               return FALSE;
+
+       apt_consumer_task_t* pConsumerTask = (apt_consumer_task_t*) apt_task_object_get(pTask);
+       UmcFramework* pFramework = (UmcFramework*) apt_consumer_task_object_get(pConsumerTask);
+       UmcTaskMsg* pUmcMsg = (UmcTaskMsg*) pMsg->data;
+       switch(pMsg->sub_type) 
+       {
+               case UMC_TASK_CLIENT_MSG:
+               {
+                       static const mrcp_app_message_dispatcher_t applicationDispatcher = 
+                       {
+                               AppOnSessionUpdate,
+                               AppOnSessionTerminate,
+                               AppOnChannelAdd,
+                               AppOnChannelRemove,
+                               AppOnMessageReceive,
+                               AppOnReady,
+                               AppOnTerminateEvent,
+                               AppOnResourceDiscover
+                       };
+
+                       mrcp_application_message_dispatch(&applicationDispatcher,pUmcMsg->m_pAppMessage);
+                       break;
+               }
+               case UMC_TASK_RUN_SESSION_MSG:
+               {
+                       if(pFramework->m_Ready)
+                               pFramework->ProcessRunRequest(pUmcMsg->m_ScenarioName,pUmcMsg->m_ProfileName);
+                       break;
+               }
+               case UMC_TASK_KILL_SESSION_MSG:
+               {
+                       if(pFramework->m_Ready)
+                               pFramework->ProcessKillRequest(pUmcMsg->m_SessionId);
+                       break;
+               }
+               case UMC_TASK_SHOW_SCENARIOS_MSG:
+               {
+                       if(pFramework->m_Ready)
+                               pFramework->ProcessShowScenarios();
+                       break;
+               }
+               case UMC_TASK_SHOW_SESSIONS_MSG:
+               {
+                       if(pFramework->m_Ready)
+                               pFramework->ProcessShowSessions();
+                       break;
+               }
+       }
+       return TRUE;
+}
diff --git a/libs/unimrcp/platforms/umc/src/umcscenario.cpp b/libs/unimrcp/platforms/umc/src/umcscenario.cpp
new file mode 100644 (file)
index 0000000..e93c53a
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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 <stdlib.h>
+#include "umcscenario.h"
+
+UmcScenario::UmcScenario() :
+       m_pName(NULL),
+       m_pMrcpProfile("MRCPv2-Default"),
+       m_pDirLayout(NULL),
+       m_ResourceDiscovery(false),
+       m_pCapabilities(NULL),
+       m_pRtpDescriptor(NULL)
+{
+}
+
+UmcScenario::~UmcScenario()
+{
+}
+
+bool UmcScenario::Load(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_elem* pChildElem;
+       /* Load Child Elements */
+       for(pChildElem = pElem->first_child; pChildElem; pChildElem = pChildElem->next)
+       {
+               LoadElement(pChildElem,pool);
+       }
+       return true;
+}
+
+void UmcScenario::Destroy()
+{
+}
+
+bool UmcScenario::LoadElement(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(strcasecmp(pElem->name,"resource-discovery") == 0)
+       {
+               LoadDiscovery(pElem,pool);
+               return true;
+       }
+       else if(strcasecmp(pElem->name,"termination") == 0)
+       {
+               LoadTermination(pElem,pool);
+               return true;
+       }
+       else if(strcasecmp(pElem->name,"rtp-termination") == 0)
+       {
+               LoadRtpTermination(pElem,pool);
+               return true;
+       }
+
+       return false;
+}
+
+bool UmcScenario::LoadDiscovery(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       m_ResourceDiscovery = IsElementEnabled(pElem);
+       return true;
+}
+
+bool UmcScenario::LoadTermination(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       if(!IsElementEnabled(pElem))
+               return true;
+
+       const apr_xml_elem* pChildElem;
+       /* Load Child Elements */
+       for(pChildElem = pElem->first_child; pChildElem; pChildElem = pChildElem->next)
+       {
+               if(strcasecmp(pChildElem->name,"capabilities") == 0)
+                       return LoadCapabilities(pChildElem,pool);
+       }
+       return true;
+}
+
+bool UmcScenario::LoadCapabilities(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       const apr_xml_elem* pChildElem;
+       /* Load Child Elements */
+       m_pCapabilities = (mpf_codec_capabilities_t*) apr_palloc(pool,sizeof(mpf_codec_capabilities_t*));
+       mpf_codec_capabilities_init(m_pCapabilities,1,pool);
+       for(pChildElem = pElem->first_child; pChildElem; pChildElem = pChildElem->next)
+       {
+               if(strcasecmp(pChildElem->name,"codec") != 0)
+                       continue;
+
+               const char* pName = NULL;
+               const char* pRates = NULL; 
+               const apr_xml_attr* pAttr;
+               for(pAttr = pChildElem->attr; pAttr; pAttr = pAttr->next) 
+               {
+                       if(strcasecmp(pAttr->name,"name") == 0)
+                       {
+                               pName = pAttr->value;
+                       }
+                       else if(strcasecmp(pAttr->name,"rates") == 0)
+                       {
+                               pRates = pAttr->value;
+                       }
+               }
+
+               if(pName)
+               {
+                       int rates = ParseRates(pRates,pool);
+                       mpf_codec_capabilities_add(m_pCapabilities,rates,pName);
+               }
+       }
+       return true;
+}
+
+int UmcScenario::ParseRates(const char* pStr, apr_pool_t* pool) const
+{
+       int rates = 0;
+       if(pStr)
+       {
+               char* pRateStr;
+               char* pState;
+               char* pRateListStr = apr_pstrdup(pool,pStr);
+               do 
+               {
+                       pRateStr = apr_strtok(pRateListStr, " ", &pState);
+                       if(pRateStr) 
+                       {
+                               apr_uint16_t rate = (apr_uint16_t)atoi(pRateStr);
+                               rates |= mpf_sample_rate_mask_get(rate);
+                       }
+                       pRateListStr = NULL; /* make sure we pass NULL on subsequent calls of apr_strtok() */
+               } 
+               while(pRateStr);
+       }
+       return rates;
+}
+
+bool UmcScenario::LoadRtpTermination(const apr_xml_elem* pElem, apr_pool_t* pool)
+{
+       return true;
+}
+
+bool UmcScenario::InitCapabilities(mpf_stream_capabilities_t* pCapabilities) const
+{
+       if(m_pCapabilities)
+       {
+               int i;
+               mpf_codec_attribs_t *pAttribs;
+               for(i=0; i<m_pCapabilities->attrib_arr->nelts; i++)
+               {
+                       pAttribs = &APR_ARRAY_IDX(m_pCapabilities->attrib_arr,i,mpf_codec_attribs_t);
+                       mpf_codec_capabilities_add(
+                                       &pCapabilities->codecs,
+                                       pAttribs->sample_rates,
+                                       pAttribs->name.buf);
+               }
+       }
+       else
+       {
+               /* add default codec capabilities (Linear PCM) */
+               mpf_codec_capabilities_add(
+                               &pCapabilities->codecs,
+                               MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                               "LPCM");
+       }
+
+       return true;
+}
+
+bool UmcScenario::IsElementEnabled(const apr_xml_elem* pElem) const
+{
+       const apr_xml_attr* pAttr;
+       for(pAttr = pElem->attr; pAttr; pAttr = pAttr->next) 
+       {
+               if(strcasecmp(pAttr->name,"enable") == 0)
+               {
+                       return atoi(pAttr->value) > 0;
+               }
+       }
+       return true;
+}
+
+const char* UmcScenario::LoadFileContent(const char* pFileName, apr_pool_t* pool) const
+{
+       if(!m_pDirLayout || !pFileName)
+               return NULL;
+
+       char* pFilePath = apt_datadir_filepath_get(m_pDirLayout,pFileName,pool);
+       if(!pFilePath)
+               return NULL;
+
+       FILE* pFile = fopen(pFilePath,"r");
+       if(!pFile)
+               return NULL;
+
+       char text[1024];
+       apr_size_t size;
+       size = fread(text,1,sizeof(text)-1,pFile);
+       text[size] = '\0';
+       fclose(pFile);
+       return apr_pstrdup(pool,text);
+}
diff --git a/libs/unimrcp/platforms/umc/src/umcsession.cpp b/libs/unimrcp/platforms/umc/src/umcsession.cpp
new file mode 100644 (file)
index 0000000..d19be46
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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 "umcsession.h"
+#include "umcscenario.h"
+
+UmcSession::UmcSession(const UmcScenario* pScenario) :
+       m_pScenario(pScenario),
+       m_pMrcpProfile(NULL),
+       m_pMrcpApplication(NULL),
+       m_pMrcpSession(NULL),
+       m_Running(false),
+       m_Terminating(false)
+{
+       static int id = 0;
+       if(id == INT_MAX)
+               id = 0;
+       id++;
+
+       int size = apr_snprintf(m_Id,sizeof(m_Id)-1,"%d",id);
+       m_Id[size] = '\0';
+}
+
+UmcSession::~UmcSession()
+{
+}
+
+bool UmcSession::Run()
+{
+       if(m_Running)
+               return false;
+
+       if(!m_pMrcpProfile)
+               m_pMrcpProfile = m_pScenario->GetMrcpProfile();
+
+       if(!m_pMrcpProfile || !m_pMrcpApplication)
+               return false;
+
+       /* create session */
+       if(!CreateMrcpSession(m_pMrcpProfile))
+               return false;
+       
+       m_Running = true;
+       
+       bool ret = false;
+       if(m_pScenario->IsDiscoveryEnabled())
+               ret = ResourceDiscover();
+       else
+               ret = Start();
+       
+       if(!ret)
+       {
+               m_Running = false;
+               DestroyMrcpSession();
+       }
+       return ret;
+}
+
+bool UmcSession::Terminate()
+{
+       if(m_Terminating)
+               return false;
+
+       m_Running = false;
+       m_Terminating = true;
+       return (mrcp_application_session_terminate(m_pMrcpSession) == TRUE);
+}
+
+bool UmcSession::OnSessionTerminate(mrcp_sig_status_code_e status)
+{
+       if(!m_Terminating)
+               return false;
+
+       m_Terminating = false;
+       return DestroyMrcpSession();
+}
+
+bool UmcSession::OnSessionUpdate(mrcp_sig_status_code_e status) 
+{
+       return m_Running;
+}
+
+bool UmcSession::OnChannelAdd(mrcp_channel_t *channel, mrcp_sig_status_code_e status) 
+{
+       return m_Running;
+}
+
+bool UmcSession::OnChannelRemove(mrcp_channel_t *channel, mrcp_sig_status_code_e status) 
+{
+       return m_Running;
+}
+
+bool UmcSession::OnMessageReceive(mrcp_channel_t *channel, mrcp_message_t *message) 
+{
+       return m_Running;
+}
+
+bool UmcSession::OnTerminateEvent(mrcp_channel_t *channel)
+{
+       if(!m_Running)
+               return false;
+
+       return Terminate();
+}
+
+bool UmcSession::OnResourceDiscover(mrcp_session_descriptor_t* descriptor, mrcp_sig_status_code_e status)
+{
+       if(!m_Running)
+               return false;
+
+       if(!Start())
+               Terminate();
+       return true;
+}
+
+bool UmcSession::CreateMrcpSession(const char* pProfileName)
+{
+       m_pMrcpSession = mrcp_application_session_create(m_pMrcpApplication,pProfileName,this);
+       return (m_pMrcpSession != NULL);
+}
+
+bool UmcSession::DestroyMrcpSession()
+{
+       if(!m_pMrcpSession)
+               return false;
+
+       mrcp_application_session_destroy(m_pMrcpSession);
+       m_pMrcpSession = NULL;
+       return true;
+}
+
+bool UmcSession::AddMrcpChannel(mrcp_channel_t* pMrcpChannel)
+{
+       if(!m_Running)
+               return false;
+
+       return (mrcp_application_channel_add(m_pMrcpSession,pMrcpChannel) == TRUE);
+}
+
+bool UmcSession::RemoveMrcpChannel(mrcp_channel_t* pMrcpChannel)
+{
+       if(!m_Running)
+               return false;
+
+       return (mrcp_application_channel_remove(m_pMrcpSession,pMrcpChannel) == TRUE);
+}
+
+bool UmcSession::SendMrcpRequest(mrcp_channel_t* pMrcpChannel, mrcp_message_t* pMrcpMessage)
+{
+       if(!m_Running)
+               return false;
+
+       return (mrcp_application_message_send(m_pMrcpSession,pMrcpChannel,pMrcpMessage) == TRUE);
+}
+
+bool UmcSession::ResourceDiscover()
+{
+       if(!m_Running)
+               return false;
+
+       return (mrcp_application_resource_discover(m_pMrcpSession) == TRUE);
+}
+
+mrcp_channel_t* UmcSession::CreateMrcpChannel(
+                                               mrcp_resource_id resource_id, 
+                                               mpf_termination_t* pTermination, 
+                                               mpf_rtp_termination_descriptor_t* pRtpDescriptor, 
+                                               void* pObj)
+{
+       return mrcp_application_channel_create(
+                       m_pMrcpSession,            /* session, channel belongs to */
+                       resource_id,               /* MRCP resource identifier */
+                       pTermination,              /* media termination, used to terminate audio stream */
+                       NULL,                      /* RTP descriptor, used to create RTP termination (NULL by default) */
+                       pObj);                     /* object to associate */
+}
+
+mpf_termination_t* UmcSession::CreateAudioTermination(
+                                               const mpf_audio_stream_vtable_t* pStreamVtable,
+                                               mpf_stream_capabilities_t* pCapabilities,
+                                               void* pObj)
+{
+       return mrcp_application_audio_termination_create(
+                       m_pMrcpSession,  /* session, termination belongs to */
+                       pStreamVtable,   /* virtual methods table of audio stream */
+                       pCapabilities,   /* capabilities of audio stream */
+                       pObj);           /* object to associate */
+}
+
+mrcp_message_t* UmcSession::CreateMrcpMessage(
+               mrcp_channel_t* pMrcpChannel, 
+               mrcp_method_id method_id)
+{
+       return mrcp_application_message_create(m_pMrcpSession,pMrcpChannel,method_id);
+}
+
+
+
+apr_pool_t* UmcSession::GetSessionPool() const
+{
+       if(!m_pMrcpSession)
+               return NULL;
+       return mrcp_application_session_pool_get(m_pMrcpSession);
+}
+
+const char* UmcSession::GetMrcpSessionId() const
+{
+       if(!m_pMrcpSession)
+               return NULL;
+
+       const apt_str_t *pId = mrcp_application_session_id_get(m_pMrcpSession);
+       return pId->buf;
+}
diff --git a/libs/unimrcp/platforms/umc/umc.vcproj b/libs/unimrcp/platforms/umc/umc.vcproj
new file mode 100644 (file)
index 0000000..6c6bbac
--- /dev/null
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="umc"
+       ProjectGUID="{CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}"
+       RootNamespace="umc"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unidebug.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPClientLibs)"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="1"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unirelease.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpclient.vsprops"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalDependencies="$(UniMRCPClientLibs)"
+                               LinkTimeCodeGeneration="1"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+                       >
+                       <File
+                               RelativePath=".\src\dtmfscenario.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\dtmfsession.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\main.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\recogscenario.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\recogsession.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\recorderscenario.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\recordersession.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\synthscenario.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\synthsession.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\umcconsole.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\umcframework.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\umcscenario.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\src\umcsession.cpp"
+                               >
+                       </File>
+               </Filter>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+                       <File
+                               RelativePath=".\include\dtmfscenario.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\dtmfsession.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\recogscenario.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\recogsession.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\recorderscenario.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\recordersession.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\synthscenario.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\synthsession.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\umcconsole.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\umcframework.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\umcscenario.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath=".\include\umcsession.h"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
index 639b411c127541372a78bf8d041732d467ebaa14..6a9b660bce8a6a662abcf17d3643c376f63713d7 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "demo_application.h"
 #include "demo_util.h"
-#include "mrcp_session.h"
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
 #include "mrcp_synth_header.h"
@@ -80,9 +79,10 @@ demo_application_t* demo_bypass_application_create(apr_pool_t *pool)
 static mrcp_channel_t* demo_application_channel_create(mrcp_session_t *session)
 {
        mrcp_channel_t *channel;
+       apr_pool_t *pool = mrcp_application_session_pool_get(session);
        /* create channel */
-       demo_app_channel_t *demo_channel = apr_palloc(session->pool,sizeof(demo_app_channel_t));
-       mpf_rtp_termination_descriptor_t *rtp_descriptor = demo_rtp_descriptor_create(session->pool);
+       demo_app_channel_t *demo_channel = apr_palloc(pool,sizeof(demo_app_channel_t));
+       mpf_rtp_termination_descriptor_t *rtp_descriptor = demo_rtp_descriptor_create(pool);
        channel = mrcp_application_channel_create(
                        session,                     /* session, channel belongs to */
                        MRCP_SYNTHESIZER_RESOURCE,   /* MRCP resource identifier */
@@ -163,10 +163,10 @@ static apt_bool_t demo_application_on_channel_add(mrcp_application_t *applicatio
                        mpf_rtp_media_descriptor_t *remote_media = rtp_descriptor->audio.remote;
                        if(local_media && remote_media) {
                                apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Media Attributes: L[%s/%d] R[%s/%d]",
-                                       local_media->base.ip.buf,
-                                       local_media->base.port,
-                                       remote_media->base.ip.buf,
-                                       remote_media->base.port);
+                                       local_media->ip.buf,
+                                       local_media->port,
+                                       remote_media->ip.buf,
+                                       remote_media->port);
                        }
                }
        }
index 2f4815af97304ddd0d16f6cffb4f2ef4fea3f697..3235b2ad863ca6cc9effc2e593a96936da3d95b6 100644 (file)
 
 #include "demo_application.h"
 #include "demo_util.h"
-#include "mrcp_session.h"
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
 #include "mrcp_recog_header.h"
 #include "mrcp_recog_resource.h"
 #include "apt_log.h"
 
-#define DEMO_SPEECH_SOURCE_FILE "one.pcm"
-
 typedef struct recog_app_channel_t recog_app_channel_t;
 
 /** Declaration of recognizer application channel */
@@ -77,7 +74,7 @@ static const mrcp_app_message_dispatcher_t recog_application_dispatcher = {
 
 /** Declaration of recognizer audio stream methods */
 static apt_bool_t recog_app_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t recog_app_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t recog_app_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
@@ -108,27 +105,36 @@ static mrcp_channel_t* recog_application_channel_create(mrcp_session_t *session)
 {
        mrcp_channel_t *channel;
        mpf_termination_t *termination;
-       mpf_codec_descriptor_t *codec_descriptor = NULL;
+       mpf_stream_capabilities_t *capabilities;
+       apr_pool_t *pool = mrcp_application_session_pool_get(session);
 
        /* create channel */
-       recog_app_channel_t *recog_channel = apr_palloc(session->pool,sizeof(recog_app_channel_t));
+       recog_app_channel_t *recog_channel = apr_palloc(pool,sizeof(recog_app_channel_t));
        recog_channel->streaming = FALSE;
        recog_channel->audio_in = NULL;
        recog_channel->time_to_complete = 0;
 
-#if 0 /* in case your audio source isn't in linear PCM, create appropriate codec descriptor below */
-       codec_descriptor = apr_palloc(session->pool,sizeof(mpf_codec_descriptor_t));
-       mpf_codec_descriptor_init(codec_descriptor);
-       codec_descriptor->channel_count = 1;
-       codec_descriptor->payload_type = 0;
-       apt_string_set(&codec_descriptor->name,"PCMU");
-       codec_descriptor->sampling_rate = 8000;
+       /* create source stream capabilities */
+       capabilities = mpf_source_stream_capabilities_create(pool);
+
+       /* add codec capabilities (Linear PCM) */
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
+#if 0
+       /* more capabilities can be added or replaced */
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "PCMU");
 #endif
 
-       termination = mrcp_application_source_termination_create(
+       termination = mrcp_application_audio_termination_create(
                        session,                   /* session, termination belongs to */
                        &audio_stream_vtable,      /* virtual methods table of audio stream */
-                       codec_descriptor,          /* codec descriptor of audio stream (NULL by default) */
+                       capabilities,              /* capabilities of audio stream */
                        recog_channel);            /* object to associate */
        
        channel = mrcp_application_channel_create(
@@ -235,13 +241,17 @@ static apt_bool_t recog_application_on_define_grammar(mrcp_application_t *applic
        recog_app_channel_t *recog_channel = mrcp_application_channel_object_get(channel);
        mrcp_message_t *mrcp_message;
        const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
+       apr_pool_t *pool = mrcp_application_session_pool_get(session);
        /* create and send RECOGNIZE request */
        mrcp_message = demo_recognize_message_create(session,channel,dir_layout);
        if(mrcp_message) {
                mrcp_application_message_send(session,channel,mrcp_message);
        }
        if(recog_channel) {
-               char *file_path = apt_datadir_filepath_get(dir_layout,DEMO_SPEECH_SOURCE_FILE,session->pool);
+               const mpf_codec_descriptor_t *descriptor = mrcp_application_source_descriptor_get(channel);
+               char *file_name = apr_psprintf(pool,"one-%dkHz.pcm",
+                       descriptor ? descriptor->sampling_rate/1000 : 8);
+               char *file_path = apt_datadir_filepath_get(dir_layout,file_name,pool);
                if(file_path) {
                        recog_channel->audio_in = fopen(file_path,"rb");
                        if(recog_channel->audio_in) {
@@ -311,7 +321,7 @@ static apt_bool_t recog_app_stream_destroy(mpf_audio_stream_t *stream)
 }
 
 /** Callback is called from MPF engine context to perform application stream specific action before open */
-static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t recog_app_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
index 9aba1adc8c22d9a708cfeb2a21ccd37633552e6d..4ad6a7d0d5e2979ba050790fc8cbf8d4593fa0d4 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "demo_application.h"
 #include "demo_util.h"
-#include "mrcp_session.h"
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
 #include "mrcp_synth_header.h"
@@ -68,7 +67,7 @@ static const mrcp_app_message_dispatcher_t synth_application_dispatcher = {
 
 /** Declaration of synthesizer audio stream methods */
 static apt_bool_t synth_app_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t synth_app_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t synth_app_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
 
@@ -99,25 +98,34 @@ static mrcp_channel_t* synth_application_channel_create(mrcp_session_t *session)
 {
        mrcp_channel_t *channel;
        mpf_termination_t *termination;
-       mpf_codec_descriptor_t *codec_descriptor = NULL;
+       mpf_stream_capabilities_t *capabilities;
+       apr_pool_t *pool = mrcp_application_session_pool_get(session);
 
        /* create channel */
-       synth_app_channel_t *synth_channel = apr_palloc(session->pool,sizeof(synth_app_channel_t));
+       synth_app_channel_t *synth_channel = apr_palloc(pool,sizeof(synth_app_channel_t));
        synth_channel->audio_out = NULL;
 
+       /* create sink stream capabilities */
+       capabilities = mpf_sink_stream_capabilities_create(pool);
+
+       /* add codec capabilities (Linear PCM) */
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
 #if 0
-       codec_descriptor = apr_palloc(session->pool,sizeof(mpf_codec_descriptor_t));
-       mpf_codec_descriptor_init(codec_descriptor);
-       codec_descriptor->channel_count = 1;
-       codec_descriptor->payload_type = 0;
-       apt_string_set(&codec_descriptor->name,"PCMU");
-       codec_descriptor->sampling_rate = 8000;
+       /* more capabilities can be added or replaced */
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "PCMU");
 #endif
 
-       termination = mrcp_application_sink_termination_create(
+       termination = mrcp_application_audio_termination_create(
                        session,                   /* session, termination belongs to */
                        &audio_stream_vtable,      /* virtual methods table of audio stream */
-                       codec_descriptor,          /* codec descriptor of audio stream (NULL by default) */
+                       capabilities,              /* capabilities of audio stream */
                        synth_channel);            /* object to associate */
        
        channel = mrcp_application_channel_create(
@@ -187,6 +195,7 @@ static apt_bool_t synth_application_on_session_terminate(mrcp_application_t *app
 static apt_bool_t synth_application_on_channel_add(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_sig_status_code_e status)
 {
        synth_app_channel_t *synth_channel = mrcp_application_channel_object_get(channel);
+       apr_pool_t *pool = mrcp_application_session_pool_get(session);
        if(status == MRCP_SIG_STATUS_CODE_SUCCESS) {
                mrcp_message_t *mrcp_message;
                const apt_dir_layout_t *dir_layout = mrcp_application_dir_layout_get(application);
@@ -197,8 +206,12 @@ static apt_bool_t synth_application_on_channel_add(mrcp_application_t *applicati
                }
 
                if(synth_channel && session) {
-                       char *file_name = apr_pstrcat(session->pool,"synth-",session->id.buf,".pcm",NULL);
-                       char *file_path = apt_datadir_filepath_get(dir_layout,file_name,session->pool);
+                       const apt_str_t *id = mrcp_application_session_id_get(session);
+                       const mpf_codec_descriptor_t *descriptor = mrcp_application_sink_descriptor_get(channel);
+                       char *file_name = apr_psprintf(pool,"synth-%dkHz-%s.pcm",
+                               descriptor ? descriptor->sampling_rate/1000 : 8,
+                               id->buf);
+                       char *file_path = apt_datadir_filepath_get(dir_layout,file_name,pool);
                        if(file_path) {
                                synth_channel->audio_out = fopen(file_path,"wb");
                        }
@@ -266,7 +279,7 @@ static apt_bool_t synth_app_stream_destroy(mpf_audio_stream_t *stream)
 }
 
 /** Callback is called from MPF engine context to perform application stream specific action before open */
-static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t synth_app_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
index 75812a125f5bffa5dc38727b582fead947366b55..db873f288ec42b66609745dcdc1fc25ebbd0ffc8 100644 (file)
@@ -16,7 +16,6 @@
 
 #include "demo_util.h"
 /* common includes */
-#include "mrcp_session.h"
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
 /* synthesizer includes */
@@ -183,10 +182,10 @@ mpf_rtp_termination_descriptor_t* demo_rtp_descriptor_create(apr_pool_t *pool)
        /* create rtp local media */
        media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
        mpf_rtp_media_descriptor_init(media);
-       apt_string_assign(&media->base.ip,"127.0.0.1",pool);
-       media->base.port = 6000;
-       media->base.state = MPF_MEDIA_ENABLED;
-       media->mode = STREAM_MODE_RECEIVE;
+       apt_string_assign(&media->ip,"127.0.0.1",pool);
+       media->port = 6000;
+       media->state = MPF_MEDIA_ENABLED;
+       media->direction = STREAM_DIRECTION_RECEIVE;
 
        /* initialize codec list */
        mpf_codec_list_init(&media->codec_list,2,pool);
index 9e370a0bbcbe9fc5a496ef73ef645bb9d9b16357..9bc7eb75c823401d988653b5f830e170e97e84bb 100644 (file)
@@ -10,6 +10,10 @@ if DEMORECOG_PLUGIN
 SUBDIRS               += demo-recog
 endif
 
+if RECORDER_PLUGIN
+SUBDIRS               += mrcp-recorder
+endif
+
 if CEPSTRAL_PLUGIN
 SUBDIRS               += mrcp-cepstral
 endif
index 72a86a5c3e7a566f4ba57819e91cfe44d044d249..5c1e66f38b61c9d76668414543496ca22bcb786c 100644 (file)
  */
 
 /* 
- * Some mandatory rules for plugin implementation.
- * 1. Each plugin MUST contain the following function as an entry point of the plugin
- *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
- * 2. One and only one response MUST be sent back to the received request.
- * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
- *   (asynch response can be sent from the context of other thread)
- * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. Methods (callbacks) of the MPF engine stream MUST not block.
  */
 
-#include "mrcp_resource_engine.h"
-#include "mrcp_recog_resource.h"
-#include "mrcp_recog_header.h"
-#include "mrcp_generic_header.h"
-#include "mrcp_message.h"
+#include "mrcp_recog_engine.h"
 #include "mpf_activity_detector.h"
 #include "apt_consumer_task.h"
 #include "apt_log.h"
@@ -40,10 +39,10 @@ typedef struct demo_recog_channel_t demo_recog_channel_t;
 typedef struct demo_recog_msg_t demo_recog_msg_t;
 
 /** Declaration of recognizer engine methods */
-static apt_bool_t demo_recog_engine_destroy(mrcp_resource_engine_t *engine);
-static apt_bool_t demo_recog_engine_open(mrcp_resource_engine_t *engine);
-static apt_bool_t demo_recog_engine_close(mrcp_resource_engine_t *engine);
-static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+static apt_bool_t demo_recog_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t demo_recog_engine_open(mrcp_engine_t *engine);
+static apt_bool_t demo_recog_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
 
 static const struct mrcp_engine_method_vtable_t engine_vtable = {
        demo_recog_engine_destroy,
@@ -68,7 +67,7 @@ static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
 
 /** Declaration of recognizer audio stream methods */
 static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t demo_recog_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
 
@@ -122,11 +121,14 @@ struct demo_recog_msg_t {
 static apt_bool_t demo_recog_msg_signal(demo_recog_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request);
 static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg);
 
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
+
 /** Declare this macro to use log routine of the server, plugin is loaded from */
 MRCP_PLUGIN_LOGGER_IMPLEMENT
 
 /** Create demo recognizer engine */
-MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
 {
        demo_recog_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_recog_engine_t));
        apt_task_t *task;
@@ -145,16 +147,16 @@ MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool
                vtable->process_msg = demo_recog_msg_process;
        }
 
-       /* create resource engine base */
-       return mrcp_resource_engine_create(
-                                       MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
-                                       demo_engine,               /* object to associate */
-                                       &engine_vtable,            /* virtual methods table of resource engine */
-                                       pool);                     /* pool to allocate memory from */
+       /* create engine base */
+       return mrcp_engine_create(
+                               MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
+                               demo_engine,               /* object to associate */
+                               &engine_vtable,            /* virtual methods table of engine */
+                               pool);                     /* pool to allocate memory from */
 }
 
 /** Destroy recognizer engine */
-static apt_bool_t demo_recog_engine_destroy(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_recog_engine_destroy(mrcp_engine_t *engine)
 {
        demo_recog_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -166,7 +168,7 @@ static apt_bool_t demo_recog_engine_destroy(mrcp_resource_engine_t *engine)
 }
 
 /** Open recognizer engine */
-static apt_bool_t demo_recog_engine_open(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_recog_engine_open(mrcp_engine_t *engine)
 {
        demo_recog_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -177,7 +179,7 @@ static apt_bool_t demo_recog_engine_open(mrcp_resource_engine_t *engine)
 }
 
 /** Close recognizer engine */
-static apt_bool_t demo_recog_engine_close(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_recog_engine_close(mrcp_engine_t *engine)
 {
        demo_recog_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -187,8 +189,11 @@ static apt_bool_t demo_recog_engine_close(mrcp_resource_engine_t *engine)
        return TRUE;
 }
 
-static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
 {
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
+
        /* create demo recog channel */
        demo_recog_channel_t *recog_channel = apr_palloc(pool,sizeof(demo_recog_channel_t));
        recog_channel->demo_engine = engine->obj;
@@ -196,26 +201,35 @@ static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_resource_eng
        recog_channel->stop_response = NULL;
        recog_channel->detector = mpf_activity_detector_create(pool);
        recog_channel->audio_out = NULL;
+
+       capabilities = mpf_sink_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
+                       recog_channel,        /* object to associate */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
        /* create engine channel base */
-       recog_channel->channel = mrcp_engine_sink_channel_create(
-                       engine,               /* resource engine */
+       recog_channel->channel = mrcp_engine_channel_create(
+                       engine,               /* engine */
                        &channel_vtable,      /* virtual methods table of engine channel */
-                       &audio_stream_vtable, /* virtual methods table of audio stream */
                        recog_channel,        /* object to associate */
-                       NULL,                 /* codec descriptor might be NULL by default */
+                       termination,          /* associated media termination */
                        pool);                /* pool to allocate memory from */
+
        return recog_channel->channel;
 }
 
 /** Destroy engine channel */
 static apt_bool_t demo_recog_channel_destroy(mrcp_engine_channel_t *channel)
 {
-       demo_recog_channel_t *recog_channel = channel->method_obj;
-       if(recog_channel->audio_out) {
-               fclose(recog_channel->audio_out);
-               recog_channel->audio_out = NULL;
-       }
-
+       /* nothing to destrtoy */
        return TRUE;
 }
 
@@ -255,13 +269,16 @@ static apt_bool_t demo_recog_channel_recognize(mrcp_engine_channel_t *channel, m
                        mpf_activity_detector_noinput_timeout_set(recog_channel->detector,recog_header->no_input_timeout);
                }
                if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT) == TRUE) {
-                       mpf_activity_detector_complete_timeout_set(recog_channel->detector,recog_header->speech_complete_timeout);
+                       mpf_activity_detector_silence_timeout_set(recog_channel->detector,recog_header->speech_complete_timeout);
                }
        }
 
        if(!recog_channel->audio_out) {
                const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
-               char *file_name = apr_pstrcat(channel->pool,"utter-",request->channel_id.session_id.buf,".pcm",NULL);
+               const mpf_codec_descriptor_t *descriptor = mrcp_engine_sink_stream_codec_get(channel);
+               char *file_name = apr_psprintf(channel->pool,"utter-%dkHz-%s.pcm",
+                       descriptor ? descriptor->sampling_rate/1000 : 8,
+                       request->channel_id.session_id.buf);
                char *file_path = apt_datadir_filepath_get(dir_layout,file_name,channel->pool);
                if(file_path) {
                        recog_channel->audio_out = fopen(file_path,"wb");
@@ -333,7 +350,7 @@ static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream)
 }
 
 /** Callback is called from MPF engine context to perform any action before open */
-static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
@@ -459,6 +476,18 @@ static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_
                                break;
                }
 
+               if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
+                       if(frame->marker == MPF_MARKER_START_OF_EVENT) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Start of Event: id [%d]",
+                                       frame->event_frame.event_id);
+                       }
+                       else if(frame->marker == MPF_MARKER_END_OF_EVENT) {
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected End of Event: id [%d] duration [%d ts]",
+                                       frame->event_frame.event_id,
+                                       frame->event_frame.duration);
+                       }
+               }
+
                if(recog_channel->audio_out) {
                        fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,recog_channel->audio_out);
                }
@@ -495,9 +524,17 @@ static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg)
                        mrcp_engine_channel_open_respond(demo_msg->channel,TRUE);
                        break;
                case DEMO_RECOG_MSG_CLOSE_CHANNEL:
+               {
                        /* close channel, make sure there is no activity and send asynch response */
+                       demo_recog_channel_t *recog_channel = demo_msg->channel->method_obj;
+                       if(recog_channel->audio_out) {
+                               fclose(recog_channel->audio_out);
+                               recog_channel->audio_out = NULL;
+                       }
+
                        mrcp_engine_channel_close_respond(demo_msg->channel);
                        break;
+               }
                case DEMO_RECOG_MSG_REQUEST_PROCESS:
                        demo_recog_channel_request_dispatch(demo_msg->channel,demo_msg->request);
                        break;
index c23129c390a37140e9793393aa21238ad8341100..fe41714fb71d5d22894207e3e4b68516785977fc 100644 (file)
  */
 
 /* 
- * Some mandatory rules for plugin implementation.
- * 1. Each plugin MUST contain the following function as an entry point of the plugin
- *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
- * 2. One and only one response MUST be sent back to the received request.
- * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
- *   (asynch response can be sent from the context of other thread)
- * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. Methods (callbacks) of the MPF engine stream MUST not block.
  */
 
-#include "mrcp_resource_engine.h"
-#include "mrcp_synth_resource.h"
-#include "mrcp_synth_header.h"
-#include "mrcp_generic_header.h"
-#include "mrcp_message.h"
+#include "mrcp_synth_engine.h"
 #include "apt_consumer_task.h"
 #include "apt_log.h"
 
@@ -39,10 +38,10 @@ typedef struct demo_synth_channel_t demo_synth_channel_t;
 typedef struct demo_synth_msg_t demo_synth_msg_t;
 
 /** Declaration of synthesizer engine methods */
-static apt_bool_t demo_synth_engine_destroy(mrcp_resource_engine_t *engine);
-static apt_bool_t demo_synth_engine_open(mrcp_resource_engine_t *engine);
-static apt_bool_t demo_synth_engine_close(mrcp_resource_engine_t *engine);
-static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+static apt_bool_t demo_synth_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t demo_synth_engine_open(mrcp_engine_t *engine);
+static apt_bool_t demo_synth_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
 
 static const struct mrcp_engine_method_vtable_t engine_vtable = {
        demo_synth_engine_destroy,
@@ -67,7 +66,7 @@ static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
 
 /** Declaration of synthesizer audio stream methods */
 static apt_bool_t demo_synth_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t demo_synth_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t demo_synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
@@ -119,15 +118,17 @@ struct demo_synth_msg_t {
 };
 
 
-#define DEMO_SPEECH_SOURCE_FILE "demo.pcm"
 static apt_bool_t demo_synth_msg_signal(demo_synth_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request);
 static apt_bool_t demo_synth_msg_process(apt_task_t *task, apt_task_msg_t *msg);
 
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
+
 /** Declare this macro to use log routine of the server, plugin is loaded from */
 MRCP_PLUGIN_LOGGER_IMPLEMENT
 
 /** Create demo synthesizer engine */
-MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
 {
        /* create demo engine */
        demo_synth_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_synth_engine_t));
@@ -148,16 +149,16 @@ MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool
                vtable->process_msg = demo_synth_msg_process;
        }
 
-       /* create resource engine base */
-       return mrcp_resource_engine_create(
-                                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
-                                       demo_engine,               /* object to associate */
-                                       &engine_vtable,            /* virtual methods table of resource engine */
-                                       pool);                     /* pool to allocate memory from */
+       /* create engine base */
+       return mrcp_engine_create(
+                               MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                               demo_engine,               /* object to associate */
+                               &engine_vtable,            /* virtual methods table of engine */
+                               pool);                     /* pool to allocate memory from */
 }
 
 /** Destroy synthesizer engine */
-static apt_bool_t demo_synth_engine_destroy(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_synth_engine_destroy(mrcp_engine_t *engine)
 {
        demo_synth_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -169,7 +170,7 @@ static apt_bool_t demo_synth_engine_destroy(mrcp_resource_engine_t *engine)
 }
 
 /** Open synthesizer engine */
-static apt_bool_t demo_synth_engine_open(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_synth_engine_open(mrcp_engine_t *engine)
 {
        demo_synth_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -180,7 +181,7 @@ static apt_bool_t demo_synth_engine_open(mrcp_resource_engine_t *engine)
 }
 
 /** Close synthesizer engine */
-static apt_bool_t demo_synth_engine_close(mrcp_resource_engine_t *engine)
+static apt_bool_t demo_synth_engine_close(mrcp_engine_t *engine)
 {
        demo_synth_engine_t *demo_engine = engine->obj;
        if(demo_engine->task) {
@@ -191,8 +192,11 @@ static apt_bool_t demo_synth_engine_close(mrcp_resource_engine_t *engine)
 }
 
 /** Create demo synthesizer channel derived from engine channel base */
-static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
 {
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
+
        /* create demo synth channel */
        demo_synth_channel_t *synth_channel = apr_palloc(pool,sizeof(demo_synth_channel_t));
        synth_channel->demo_engine = engine->obj;
@@ -201,14 +205,28 @@ static mrcp_engine_channel_t* demo_synth_engine_channel_create(mrcp_resource_eng
        synth_channel->time_to_complete = 0;
        synth_channel->paused = FALSE;
        synth_channel->audio_file = NULL;
+       
+       capabilities = mpf_source_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
+                       synth_channel,        /* object to associate */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
        /* create engine channel base */
-       synth_channel->channel = mrcp_engine_source_channel_create(
-                       engine,               /* resource engine */
+       synth_channel->channel = mrcp_engine_channel_create(
+                       engine,               /* engine */
                        &channel_vtable,      /* virtual methods table of engine channel */
-                       &audio_stream_vtable, /* virtual methods table of audio stream */
                        synth_channel,        /* object to associate */
-                       NULL,                 /* codec descriptor might be NULL by default */
+                       termination,          /* associated media termination */
                        pool);                /* pool to allocate memory from */
+
        return synth_channel->channel;
 }
 
@@ -244,7 +262,10 @@ static apt_bool_t demo_synth_channel_speak(mrcp_engine_channel_t *channel, mrcp_
        demo_synth_channel_t *synth_channel = channel->method_obj;
        synth_channel->time_to_complete = 0;
        if(channel->engine) {
-               file_path = apt_datadir_filepath_get(channel->engine->dir_layout,DEMO_SPEECH_SOURCE_FILE,channel->pool);
+               const mpf_codec_descriptor_t *descriptor = mrcp_engine_source_stream_codec_get(channel);
+               char *file_name = apr_psprintf(channel->pool,"demo-%dkHz.pcm",
+                       descriptor ? descriptor->sampling_rate/1000 : 8);
+               file_path = apt_datadir_filepath_get(channel->engine->dir_layout,file_name,channel->pool);
        }
        if(file_path) {
                synth_channel->audio_file = fopen(file_path,"rb");
@@ -394,7 +415,7 @@ static apt_bool_t demo_synth_stream_destroy(mpf_audio_stream_t *stream)
 }
 
 /** Callback is called from MPF engine context to perform any action before open */
-static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t demo_synth_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
index d057650369ad30f78234b4a4d0d8adc9389c6403..037939b8dd40549ec1f37fb60411061f24ae78ab 100644 (file)
  */
 
 /* 
- * Some mandatory rules concerning plugin implementation.
- * 1. Each plugin MUST contain the following function as an entry point of the plugin
- *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
- * 2. One and only one response MUST be sent back to the received request.
- * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
- *   (asynch response can be sent from the context of other thread)
- * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. Methods (callbacks) of the MPF engine stream MUST not block.
  */
 
+#include <stdlib.h>
 #include <swift.h>
-#include "mrcp_resource_engine.h"
-#include "mrcp_synth_resource.h"
-#include "mrcp_synth_header.h"
-#include "mrcp_generic_header.h"
-#include "mrcp_message.h"
+#include "mrcp_synth_engine.h"
 #include "mpf_buffer.h"
 #include "apt_log.h"
 
 /** Declaration of synthesizer engine methods */
-static apt_bool_t mrcp_swift_engine_destroy(mrcp_resource_engine_t *engine);
-static apt_bool_t mrcp_swift_engine_open(mrcp_resource_engine_t *engine);
-static apt_bool_t mrcp_swift_engine_close(mrcp_resource_engine_t *engine);
-static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+static apt_bool_t mrcp_swift_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t mrcp_swift_engine_open(mrcp_engine_t *engine);
+static apt_bool_t mrcp_swift_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
 
 static const struct mrcp_engine_method_vtable_t engine_vtable = {
        mrcp_swift_engine_destroy,
@@ -62,7 +62,7 @@ static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
 
 /** Declaration of synthesizer audio stream methods */
 static apt_bool_t synth_stream_destroy(mpf_audio_stream_t *stream);
-static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream);
+static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
 static apt_bool_t synth_stream_close(mpf_audio_stream_t *stream);
 static apt_bool_t synth_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *frame);
 
@@ -76,6 +76,18 @@ static const mpf_audio_stream_vtable_t audio_stream_vtable = {
        NULL
 };
 
+typedef struct mrcp_swift_engine_t mrcp_swift_engine_t;
+/** Declaration of Swift synthesizer engine */
+struct mrcp_swift_engine_t {
+       /** Swift synthesizer engine */
+       swift_engine *swift;
+       /** Speech language mapping */
+       apr_table_t  *language_table;
+       /** Sampling rates (bitmask of mpf_sample_rates_e)
+       installed voices support */
+       int           sample_rates;
+};
+
 typedef struct mrcp_swift_channel_t mrcp_swift_channel_t;
 /** Declaration of Swift synthesizer channel */
 struct mrcp_swift_channel_t {
@@ -118,123 +130,120 @@ static const int swift_prosody_rate_table[PROSODY_RATE_COUNT] = {
        170  /* PROSODY_RATE_DEFAULT */
 };
 
-static apr_table_t *swift_speech_language_table;
 
 static apr_table_t* mrcp_swift_language_table_create(apr_pool_t *pool);
-static void mrcp_swift_voices_show(swift_engine *engine);
+static apt_bool_t mrcp_swift_voices_scan(mrcp_swift_engine_t *engine);
 static swift_result_t mrcp_swift_write_audio(swift_event *event, swift_event_t type, void *udata);
 static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message);
 static apt_bool_t mrcp_swift_channel_params_set(mrcp_swift_channel_t *synth_channel, mrcp_message_t *message);
 
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
+
 /** Declare this macro to use log routine of the server, plugin is loaded from */
 MRCP_PLUGIN_LOGGER_IMPLEMENT
 
 /** Create Swift synthesizer engine */
-MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
 {
-       swift_engine *synth_engine;
-       mrcp_resource_engine_t *engine;
-       /* open swift engine */
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Engine [%s]",swift_version);
-       if((synth_engine = swift_engine_open(NULL)) ==  NULL) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Engine");
-               return NULL;
-       }
-       swift_speech_language_table = mrcp_swift_language_table_create(pool);
-       mrcp_swift_voices_show(synth_engine);
-
-       /* create resource engine base */
-       engine = mrcp_resource_engine_create(
-                                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
-                                       synth_engine,              /* object to associate */
-                                       &engine_vtable,            /* virtual methods table of resource engine */
-                                       pool);                     /* pool to allocate memory from */
-       if(!engine) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Engine");
-               swift_engine_close(synth_engine);
-       }
-       return engine;
+       mrcp_swift_engine_t *synth_engine = apr_palloc(pool,sizeof(mrcp_swift_engine_t));
+       synth_engine->swift = NULL;
+       synth_engine->language_table = mrcp_swift_language_table_create(pool);
+       synth_engine->sample_rates = MPF_SAMPLE_RATE_NONE;
+
+       /* create engine base */
+       return mrcp_engine_create(
+                               MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                               synth_engine,              /* object to associate */
+                               &engine_vtable,            /* virtual methods table of engine */
+                               pool);                     /* pool to allocate memory from */
 }
 
 /** Destroy synthesizer engine */
-static apt_bool_t mrcp_swift_engine_destroy(mrcp_resource_engine_t *engine)
+static apt_bool_t mrcp_swift_engine_destroy(mrcp_engine_t *engine)
 {
-       swift_engine *synth_engine = engine->obj;
-       /* close swift engine */
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Engine");
-       if(synth_engine) {
-               swift_engine_close(synth_engine);
-               engine->obj = NULL;
-       }
+       /* nothing to destroy */
        return TRUE;
 }
 
 /** Open synthesizer engine */
-static apt_bool_t mrcp_swift_engine_open(mrcp_resource_engine_t *engine)
+static apt_bool_t mrcp_swift_engine_open(mrcp_engine_t *engine)
 {
+       mrcp_swift_engine_t *synth_engine = engine->obj;
+       
+       /* open swift engine */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Engine [%s]",swift_version);
+       if((synth_engine->swift = swift_engine_open(NULL)) ==  NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Engine");
+               return FALSE;
+       }
+
+       if(mrcp_swift_voices_scan(synth_engine) == FALSE) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Scan Swift Voices");
+               swift_engine_close(synth_engine->swift);
+               synth_engine->swift = NULL;
+               return FALSE;
+       }
        return TRUE;
 }
 
 /** Close synthesizer engine */
-static apt_bool_t mrcp_swift_engine_close(mrcp_resource_engine_t *engine)
+static apt_bool_t mrcp_swift_engine_close(mrcp_engine_t *engine)
 {
+       mrcp_swift_engine_t *synth_engine = engine->obj;
+
+       /* close swift engine */
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Engine");
+       if(synth_engine->swift) {
+               swift_engine_close(synth_engine->swift);
+               synth_engine->swift = NULL;
+       }
        return TRUE;
 }
 
 /** Create demo synthesizer channel derived from engine channel base */
-static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool)
+static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
 {
-       swift_engine *synth_engine = engine->obj;
-       mrcp_swift_channel_t *synth_channel;
+       mrcp_swift_engine_t *synth_engine = engine->obj;
+
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
        mrcp_engine_channel_t *channel;
-       swift_params *params;
-       swift_port *port;
-       mpf_codec_descriptor_t *codec_descriptor;
-
-       codec_descriptor = 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;
-
-       params = swift_params_new(NULL);
-       swift_params_set_string(params, "audio/encoding", "pcm16");
-       swift_params_set_int(params, "audio/sampling-rate", codec_descriptor->sampling_rate);
-       /* open swift port */ 
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Port");
-       if((port = swift_port_open(synth_engine,params)) == NULL) {
-               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port");
-               return NULL;
-       }
 
        /* create swift synth channel */
-       synth_channel = apr_palloc(pool,sizeof(mrcp_swift_channel_t));
+       mrcp_swift_channel_t *synth_channel = apr_palloc(pool,sizeof(mrcp_swift_channel_t));
+       synth_channel->port = NULL;
+       synth_channel->tts_stream = 0;
+       synth_channel->channel = NULL;
+       synth_channel->audio_buffer = NULL;
        synth_channel->speak_request = NULL;
        synth_channel->stop_response = NULL;
        synth_channel->paused = FALSE;
-       synth_channel->channel = NULL;
-       synth_channel->port = port;
-       synth_channel->tts_stream = 0;
+
+       capabilities = mpf_source_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       synth_engine->sample_rates,
+                       "LPCM");
+
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
+                       synth_channel,        /* object to associate */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
        /* create engine channel base */
-       channel = mrcp_engine_source_channel_create(
-                       engine,               /* resource engine */
+       channel = mrcp_engine_channel_create(
+                       engine,               /* engine */
                        &channel_vtable,      /* virtual methods table of engine channel */
-                       &audio_stream_vtable, /* virtual methods table of audio stream */
                        synth_channel,        /* object to associate */
-                       codec_descriptor,     /* codec descriptor might be NULL by default */
+                       termination,          /* associated media termination */
                        pool);                /* pool to allocate memory from */
 
-       if(!channel) {
-               swift_port_close(port);
-               synth_channel->port = NULL;
-               return NULL;
+       if(channel) {
+               synth_channel->audio_buffer = mpf_buffer_create(pool);
        }
-
-       synth_channel->audio_buffer = mpf_buffer_create(pool);
-
-       /* set swift_write_audio as a callback, with the output file as its param */
-       swift_port_set_callback(port, &mrcp_swift_write_audio, SWIFT_EVENT_AUDIO | SWIFT_EVENT_END, synth_channel);
        synth_channel->channel = channel;
        return channel;
 }
@@ -242,13 +251,7 @@ static mrcp_engine_channel_t* mrcp_swift_engine_channel_create(mrcp_resource_eng
 /** Destroy engine channel */
 static apt_bool_t mrcp_swift_channel_destroy(mrcp_engine_channel_t *channel)
 {
-       mrcp_swift_channel_t *synth_channel = channel->method_obj;
-       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Port");
-       if(synth_channel->port) {
-               /* close swift port */ 
-               swift_port_close(synth_channel->port);
-               synth_channel->port = NULL;
-       }
+       /* nothing to destroy */
        return TRUE;
 }
 
@@ -256,13 +259,46 @@ static apt_bool_t mrcp_swift_channel_destroy(mrcp_engine_channel_t *channel)
 static apt_bool_t mrcp_swift_channel_open(mrcp_engine_channel_t *channel)
 {
        /* open channel and send asynch response */
-       return mrcp_engine_channel_open_respond(channel,TRUE);
+       apt_bool_t status = FALSE;
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       mrcp_swift_engine_t *synth_engine = channel->engine->obj;
+       const mpf_codec_descriptor_t *descriptor = mrcp_engine_source_stream_codec_get(synth_channel->channel);
+       if(descriptor) {
+               swift_params *params;
+               swift_port *port;
+
+               params = swift_params_new(NULL);
+               swift_params_set_string(params, "audio/encoding", "pcm16");
+               swift_params_set_int(params, "audio/sampling-rate", descriptor->sampling_rate);
+               /* open swift port */ 
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Swift Port");
+               port = swift_port_open(synth_engine->swift,params);
+               if(port) {
+                       /* set swift_write_audio as a callback, with the output file as its param */
+                       swift_port_set_callback(port, &mrcp_swift_write_audio, SWIFT_EVENT_AUDIO | SWIFT_EVENT_END, synth_channel);
+                       synth_channel->port = port;
+                       status = TRUE;
+               }
+               else {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port");
+               }
+       }
+
+       return mrcp_engine_channel_open_respond(channel,status);
 }
 
 /** Close engine channel (asynchronous response MUST be sent)*/
 static apt_bool_t mrcp_swift_channel_close(mrcp_engine_channel_t *channel)
 {
        /* close channel, make sure there is no activity and send asynch response */
+       mrcp_swift_channel_t *synth_channel = channel->method_obj;
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Close Swift Port");
+       if(synth_channel->port) {
+               /* close swift port */ 
+               swift_port_close(synth_channel->port);
+               synth_channel->port = NULL;
+       }
+
        return mrcp_engine_channel_close_respond(channel);
 }
 
@@ -379,7 +415,7 @@ static apt_bool_t synth_stream_destroy(mpf_audio_stream_t *stream)
 }
 
 /** Callback is called from MPF engine context to perform any action before open */
-static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream)
+static apt_bool_t synth_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
 {
        return TRUE;
 }
@@ -525,8 +561,10 @@ static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_chann
        }
        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);
+               mrcp_engine_t *engine = synth_channel->channel->engine;
+               mrcp_swift_engine_t *synth_engine = engine->obj;
+               if(synth_engine && synth_engine->language_table) {
+                       swift_lang_name = apr_table_get(synth_engine->language_table,synth_header->speech_language.buf);
                }
                if(!swift_lang_name) {
                        swift_lang_name = synth_header->speech_language.buf;
@@ -536,21 +574,29 @@ static apt_bool_t mrcp_swift_channel_voice_set(mrcp_swift_channel_t *synth_chann
        }
 
        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,"Find Swift Voice Matching the Criteria [%s]", search_criteria);
+               voice = swift_port_find_first_voice(synth_channel->port,search_criteria,NULL);
+               if(!voice) {
                        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"No Swift Voice Available Matching the Criteria [%s]",search_criteria);
+                       /* find the first available one */
                        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;
-               } 
+
+               if(voice) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Swift Voice [%s]",
+                               swift_voice_get_attribute(voice, "name"));
+                       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;
 }
 
-apt_bool_t swift_prosody_volume_get(const mrcp_prosody_volume_t *prosody_volume, int *volume)
+/** Get volume by prosody params */
+static apt_bool_t swift_prosody_volume_get(const mrcp_prosody_volume_t *prosody_volume, int *volume)
 {
        apt_bool_t res = FALSE;
        if(prosody_volume->type == PROSODY_VOLUME_TYPE_LABEL) {
@@ -571,7 +617,8 @@ apt_bool_t swift_prosody_volume_get(const mrcp_prosody_volume_t *prosody_volume,
        return res;
 }
 
-apt_bool_t swift_prosody_rate_get(const mrcp_prosody_rate_t *prosody_rate, int *rate)
+/** Get rate by prosody params */
+static apt_bool_t swift_prosody_rate_get(const mrcp_prosody_rate_t *prosody_rate, int *rate)
 {
        apt_bool_t res = FALSE;
        if(prosody_rate->type == PROSODY_RATE_TYPE_LABEL) {
@@ -643,24 +690,45 @@ static apt_bool_t mrcp_swift_channel_params_set(mrcp_swift_channel_t *synth_chan
        return TRUE;
 }
 
-/** Show Swift available voices */
-static void mrcp_swift_voices_show(swift_engine *engine) 
+static void mrcp_swift_sample_rates_set(mrcp_swift_engine_t *engine, const char *str)
+{
+       if(str) {
+               int value = atoi(str);
+               if(value == 8000) {
+                       engine->sample_rates |= MPF_SAMPLE_RATE_8000;
+               }
+               else if(value == 16000) {
+                       engine->sample_rates |= MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000;
+               }
+       }
+}
+
+/** Scan Swift available voices */
+static apt_bool_t mrcp_swift_voices_scan(mrcp_swift_engine_t *engine)
 {
        swift_port *port;
        swift_voice *voice;
        const char *license_status;
+       const char *sample_rate;
+
+       if(!engine->swift) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Swift Engine");
+               return FALSE;
+       }
 
        /* open swift port*/
-       if((port = swift_port_open(engine, NULL)) == NULL) {
+       if((port = swift_port_open(engine->swift, NULL)) == NULL) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Swift Port");
-               return;    
+               return FALSE;
        }
 
+       engine->sample_rates = MPF_SAMPLE_RATE_NONE;
+
        /* find the first voice on the system */
        if((voice = swift_port_find_first_voice(port, NULL, NULL)) == NULL) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Swift Voice Available");
                swift_port_close(port);
-               return;
+               return FALSE;
        }
        /* go through all of the voices on the system and print some info about each */
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Swift Available Voices:");
@@ -671,16 +739,21 @@ static void mrcp_swift_voices_show(swift_engine *engine)
                else {
                        license_status = "unlicensed";
                }
-               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"%s: %s, age %s, %s, %sHz, %s",
+               sample_rate = swift_voice_get_attribute(voice, "sample-rate");
+               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"%s: %s, age %s, %s, %sHz, %s, %s",
                        swift_voice_get_attribute(voice, "name"),
                        swift_voice_get_attribute(voice, "speaker/gender"),
                        swift_voice_get_attribute(voice, "speaker/age"),
                        swift_voice_get_attribute(voice, "language/name"),
-                       swift_voice_get_attribute(voice, "sample-rate"),
+                       sample_rate,
+                       swift_voice_get_attribute(voice, "version"),
                        license_status);
+
+               mrcp_swift_sample_rates_set(engine,sample_rate);
        }
 
        swift_port_close(port);
+       return TRUE;
 }
 
 /** Create speech language lookup table */
index ab896f10408515a288046124bab7681a832936ee..eb5a438368a02b5b2fdc7eed629469af4ed5bb9f 100644 (file)
 APT_BEGIN_EXTERN_C
 
 
+/** Opaque Flite voice declaration */
 typedef struct flite_voices_t flite_voices_t;
 
+/** Load Flite voices */
 flite_voices_t* flite_voices_load(apr_pool_t *pool);
+/** Unload Flite voices */
 void flite_voices_unload(flite_voices_t *voices);
 
+/** Get best matched voice */
 cst_voice* flite_voices_best_match_get(flite_voices_t *voices, mrcp_message_t *message);
 
 APT_END_EXTERN_C
index 4d9c4ad6ed7e7ca5b7471f66a303996caf56c185..3e70eddb2fb673ea5a6194d8e5318f974dca2324 100644 (file)
  */
 
 /* 
- * Some mandatory rules for plugin implementation.
- * 1. Each plugin MUST contain the following function as an entry point of the plugin
- *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
- * 2. One and only one response MUST be sent back to the received request.
- * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
- *   (asynch response can be sent from the context of other thread)
- * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. 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"
-#include "mrcp_generic_header.h"
-#include "mrcp_message.h"
+#include "mrcp_synth_engine.h"
 #include "mpf_buffer.h"
 #include "apr_time.h"
 #include "apt_consumer_task.h"
@@ -39,10 +38,10 @@ typedef struct flite_synth_engine_t flite_synth_engine_t;
 typedef struct flite_synth_channel_t flite_synth_channel_t;
 
 /** Declaration of synthesizer engine methods */
-static apt_bool_t flite_synth_engine_destroy(mrcp_resource_engine_t *engine);
-static apt_bool_t flite_synth_engine_open(mrcp_resource_engine_t *engine);
-static apt_bool_t flite_synth_engine_close(mrcp_resource_engine_t *engine);
-static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+static apt_bool_t flite_synth_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t flite_synth_engine_open(mrcp_engine_t *engine);
+static apt_bool_t flite_synth_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
 
 static const struct mrcp_engine_method_vtable_t engine_vtable = {
        flite_synth_engine_destroy,
@@ -119,36 +118,39 @@ 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 */
 static apt_bool_t flite_speak(apt_task_t *task, apt_task_msg_t *msg);
-static apt_bool_t flite_on_start(apt_task_t *task);
-static apt_bool_t flite_on_terminate(apt_task_t *task);
+static void flite_on_start(apt_task_t *task);
+static void flite_on_terminate(apt_task_t *task);
+
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
 
 /** Declare this macro to use log routine of the server where the plugin is loaded from */
 MRCP_PLUGIN_LOGGER_IMPLEMENT
 
 /** Create flite synthesizer engine */
-MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+MRCP_PLUGIN_DECLARE(mrcp_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 */
-       return mrcp_resource_engine_create(
-                                       MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
-                                       flite_engine,              /* object to associate */
-                                       &engine_vtable,            /* virtual methods table of resource engine */
-                                       pool);                     /* pool to allocate memory from */
+       /* create engine base */
+       return mrcp_engine_create(
+                               MRCP_SYNTHESIZER_RESOURCE, /* MRCP resource identifier */
+                               flite_engine,              /* object to associate */
+                               &engine_vtable,            /* virtual methods table of engine */
+                               pool);                     /* pool to allocate memory from */
 }
 
 /** Destroy synthesizer engine */
-static apt_bool_t flite_synth_engine_destroy(mrcp_resource_engine_t *engine)
+static apt_bool_t flite_synth_engine_destroy(mrcp_engine_t *engine)
 {
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_destroy");
        return TRUE;
 }
 
 /** Open synthesizer engine */
-static apt_bool_t flite_synth_engine_open(mrcp_resource_engine_t *engine)
+static apt_bool_t flite_synth_engine_open(mrcp_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_open");
@@ -162,7 +164,7 @@ static apt_bool_t flite_synth_engine_open(mrcp_resource_engine_t *engine)
 }
 
 /** Close synthesizer engine */
-static apt_bool_t flite_synth_engine_close(mrcp_resource_engine_t *engine)
+static apt_bool_t flite_synth_engine_close(mrcp_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");
@@ -200,10 +202,12 @@ static apt_bool_t flite_synth_task_create(flite_synth_channel_t *synth_channel)
 }
 
 /** 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)
+static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
 {
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
+
        /* create flite synth channel */
-       mpf_codec_descriptor_t *codec_descriptor = NULL;
        flite_synth_channel_t *synth_channel = (flite_synth_channel_t *) apr_palloc(pool,sizeof(flite_synth_channel_t));
 
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "flite_synth_engine_channel_create");
@@ -223,29 +227,32 @@ static mrcp_engine_channel_t* flite_synth_engine_channel_create(mrcp_resource_en
                return NULL;
        }
 
-#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
-
-       /* create engine channel base */
-       synth_channel->channel = mrcp_engine_source_channel_create(
-                       engine,               /* resource engine */
-                       &channel_vtable,      /* virtual methods table of engine channel */
-                       &audio_stream_vtable, /* virtual methods table of audio stream */
+       capabilities = mpf_source_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
                        synth_channel,        /* object to associate */
-                       codec_descriptor,     /* codec descriptor might be NULL by default */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
                        pool);                /* pool to allocate memory from */
-       
-       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;            
-       }
+
+       /* create engine channel base */
+       synth_channel->channel = mrcp_engine_channel_create(
+                       engine,               /* engine */
+                       &channel_vtable,      /* virtual methods table of engine channel */
+                       synth_channel,        /* object to associate */
+                       termination,          /* associated media termination */
+                       pool);                /* pool to allocate memory from */
+       
+       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;            
+       } 
 
        synth_channel->audio_buffer = mpf_buffer_create(pool);
        synth_channel->iId = ++synth_channel->flite_engine->iChannels;
@@ -423,8 +430,11 @@ static apt_bool_t flite_speak(apt_task_t *task, apt_task_msg_t *msg)
        apt_str_t *body;
        mrcp_message_t *response;
 
-       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 = 8000;
+       const mpf_codec_descriptor_t * descriptor = mrcp_engine_source_stream_codec_get(synth_channel->channel);
+       if(descriptor) {
+               rate = descriptor->sampling_rate;
+       }
        body = &synth_channel->speak_request->body;
 
        response = synth_channel->speak_response;
@@ -498,18 +508,18 @@ static APR_INLINE flite_synth_channel_t* flite_synth_channel_get(apt_task_t *tas
        return apt_consumer_task_object_get(consumer_task);
 }
 
-static apt_bool_t flite_on_start(apt_task_t *task)
+static void flite_on_start(apt_task_t *task)
 {
        flite_synth_channel_t *synth_channel = flite_synth_channel_get(task);
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task started - channel %d", synth_channel->iId);
-       return mrcp_engine_channel_open_respond(synth_channel->channel,TRUE);
+       mrcp_engine_channel_open_respond(synth_channel->channel,TRUE);
 }
 
-static apt_bool_t flite_on_terminate(apt_task_t *task)
+static void flite_on_terminate(apt_task_t *task)
 {
        flite_synth_channel_t *synth_channel = flite_synth_channel_get(task);
        apt_log(APT_LOG_MARK, APT_PRIO_DEBUG, "Speak task terminated - channel %d", synth_channel->iId);
-       return mrcp_engine_channel_close_respond(synth_channel->channel);
+       mrcp_engine_channel_close_respond(synth_channel->channel);
 }
 
 /** Process STOP request */
index a38f3a56b7e1ff419e4a9d42098e11c2726c6ad6..4cdfb7cf3c9b3886f7255e74c9457692e29a5fb2 100644 (file)
@@ -21,9 +21,16 @@ mrcppocketsphinx_la_LDFLAGS = -module $(PLUGIN_LT_VERSION)
 mrcppocketsphinx_la_LIBADD  = $(UNIMRCP_POCKETSPHINX_LIBS) $(UNIMRCP_SPHINXBASE_LIBS) -lm
 
 
+dictionary:
+       !(test -f $(UNIMRCP_POCKETSPHINX_MODELS)/lm/cmudict.0.6d) || \
+               $(INSTALL) -m 644 $(UNIMRCP_POCKETSPHINX_MODELS)/lm/cmudict.0.6d $(datadir)/default.dic
+
+model:
+       !(test -d $(UNIMRCP_POCKETSPHINX_MODELS)/hmm/wsj1/) || ($(mkinstalldirs) $(datadir)/wsj1; \
+               $(INSTALL) -m 644 $(UNIMRCP_POCKETSPHINX_MODELS)/hmm/wsj1/* $(datadir)/wsj1)
+
 install-data-local:
        test -d $(confdir) || $(mkinstalldirs) $(confdir)
        test -f $(confdir)/pocketsphinx.xml || $(INSTALL) -m 644 conf/pocketsphinx.xml $(confdir)
-       test -d $(datadir)/wsj1 || $(mkinstalldirs) $(datadir)/wsj1; \
-                       $(INSTALL) -m 644 $(UNIMRCP_POCKETSPHINX_MODELS)/hmm/wsj1/* $(datadir)/wsj1; \
-                       $(INSTALL) -m 644 $(UNIMRCP_POCKETSPHINX_MODELS)/lm/cmudict.0.6d $(datadir)/default.dic
+       test -f $(datadir)/default.dic || $(MAKE) dictionary
+       test -d $(datadir)/wsj1 || $(MAKE) model
index e37e55b94020cf64ff0e1702d18562dfdefe0b3f..a07c54c6e85071bce6d21a65c411b29cc48e60a8 100644 (file)
 
 APT_BEGIN_EXTERN_C
 
+/** Enumeration of PocketSphinx models */
 typedef enum {
-       POCKETSPHINX_MODEL_NARROWBAND,
-       POCKETSPHINX_MODEL_WIDEBAND
-
+       POCKETSPHINX_MODEL_NARROWBAND, /**< narrowband model */
+       POCKETSPHINX_MODEL_WIDEBAND    /**< wideband model */
 } pocketsphinx_model_e;
 
-/** Declaration of pocketsphinx properties */
+/** Declaration of PocketSphinx properties */
 typedef struct pocketsphinx_properties_t pocketsphinx_properties_t;
 
-/** Pocketsphinx properties */
+/** PocketSphinx properties */
 struct pocketsphinx_properties_t {
+       /** Data directory */
        const char          *data_dir;
+       /** Path to dictionary file */
        const char          *dictionary;
+       /** Path to narrowband model */
        const char          *model_8k;
+       /** Path to wideband model */
        const char          *model_16k;
+       /** Preferred (default) model */
        pocketsphinx_model_e preferred_model;
 
+       /** Sensitivity level */
        apr_size_t           sensitivity_level;
+       /** Sensitivity timeout */
        apr_size_t           sensitivity_timeout;
 
+       /** Noinput timeout */
        apr_size_t           no_input_timeout;
+       /** Recognition timeout */
        apr_size_t           recognition_timeout;
+       /** Partial result checking timeout */
        apr_size_t           partial_result_timeout;
 
+       /** Whether to save waveform or not */
        apt_bool_t           save_waveform;
+       /** Directory to save waveform in */
        const char          *save_waveform_dir;
 };
 
+/** Load PocketSphinx properties */
 apt_bool_t pocketsphinx_properties_load(pocketsphinx_properties_t *properties, 
                                                                                const char *file_path, 
                                                                                const apt_dir_layout_t *dir_layout,
index 14e241d5b5ab773a6aa8f24f77a14331ed22b49c..afe451cc88f65f0eac699ee6159cc3ae270d5f77 100644 (file)
  */
 
 /* 
- * Some mandatory rules for plugin implementation.
- * 1. Each plugin MUST contain the following function as an entry point of the plugin
- *        MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
- * 2. One and only one response MUST be sent back to the received request.
- * 3. Methods (callbacks) of the MRCP engine channel MUST not block.
- *   (asynch response can be sent from the context of other thread)
- * 4. Methods (callbacks) of the MPF engine stream MUST not block.
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. Methods (callbacks) of the MPF engine stream MUST not block.
  */
 
 #include <pocketsphinx.h>
 #include <apr_thread_proc.h>
 #include <apr_tables.h>
 #include <apr_file_io.h>
-#include "mrcp_resource_engine.h"
-#include "mrcp_recog_resource.h"
-#include "mrcp_recog_header.h"
-#include "mrcp_generic_header.h"
-#include "mrcp_message.h"
+#include "mrcp_recog_engine.h"
 #include "mpf_activity_detector.h"
 #include "pocketsphinx_properties.h"
 #include "apt_log.h"
@@ -46,10 +45,10 @@ typedef struct pocketsphinx_engine_t pocketsphinx_engine_t;
 typedef struct pocketsphinx_recognizer_t pocketsphinx_recognizer_t;
 
 /** Methods of recognition engine */
-static apt_bool_t pocketsphinx_engine_destroy(mrcp_resource_engine_t *engine);
-static apt_bool_t pocketsphinx_engine_open(mrcp_resource_engine_t *engine);
-static apt_bool_t pocketsphinx_engine_close(mrcp_resource_engine_t *engine);
-static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resource_engine_t *engine, apr_pool_t *pool);
+static apt_bool_t pocketsphinx_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t pocketsphinx_engine_open(mrcp_engine_t *engine);
+static apt_bool_t pocketsphinx_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_engine_t *engine, apr_pool_t *pool);
 
 static const struct mrcp_engine_method_vtable_t engine_vtable = {
        pocketsphinx_engine_destroy,
@@ -87,8 +86,8 @@ static const mpf_audio_stream_vtable_t audio_stream_vtable = {
 
 /** Pocketsphinx engine (engine is an aggregation of recognizers) */
 struct pocketsphinx_engine_t {
-       /* Resource engine base */
-       mrcp_resource_engine_t   *base;
+       /* Engine base */
+       mrcp_engine_t   *base;
        /** Properties loaded from config file */
        pocketsphinx_properties_t properties;
 };
@@ -102,7 +101,7 @@ struct pocketsphinx_recognizer_t {
        ps_decoder_t             *decoder;
        /** Configuration */
        cmd_ln_t                 *config;
-       /** Recognizer properties coppied from defualt engine properties */
+       /** Recognizer properties coppied from default engine properties */
        pocketsphinx_properties_t properties;
        /** Is input timer started */
        apt_bool_t                is_input_timer_on;
@@ -141,60 +140,68 @@ struct pocketsphinx_recognizer_t {
        mrcp_message_t           *stop_response;
        /** Is recognition channel being closed */
        apt_bool_t                close_requested;
+       /** Flag to prevent race condition when checking if a message is present */
+       apt_bool_t                message_waiting;
 };
 
+static void* APR_THREAD_FUNC pocketsphinx_recognizer_run(apr_thread_t *thread, void *data);
+
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
+
 /** Declare this macro to use log routine of the server, plugin is loaded from */
 MRCP_PLUGIN_LOGGER_IMPLEMENT
 
-static void* APR_THREAD_FUNC pocketsphinx_recognizer_run(apr_thread_t *thread, void *data);
-
 /** Create pocketsphinx engine (engine is an aggregation of recognizers) */
-MRCP_PLUGIN_DECLARE(mrcp_resource_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
 {
        pocketsphinx_engine_t *engine = apr_palloc(pool,sizeof(pocketsphinx_engine_t));
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create PocketSphinx Engine");
        
-       /* create resource engine base */
-       engine->base = mrcp_resource_engine_create(
+       /* create engine base */
+       engine->base = mrcp_engine_create(
                                        MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
                                        engine,                    /* object to associate */
-                                       &engine_vtable,            /* virtual methods table of resource engine */
+                                       &engine_vtable,            /* virtual methods table of engine */
                                        pool);                     /* pool to allocate memory from */
        return engine->base;
 }
 
 /** Destroy pocketsphinx engine */
-static apt_bool_t pocketsphinx_engine_destroy(mrcp_resource_engine_t *resource_engine)
+static apt_bool_t pocketsphinx_engine_destroy(mrcp_engine_t *engine_base)
 {
        return TRUE;
 }
 
 /** Open pocketsphinx engine */
-static apt_bool_t pocketsphinx_engine_open(mrcp_resource_engine_t *resource_engine)
+static apt_bool_t pocketsphinx_engine_open(mrcp_engine_t *engine_base)
 {
-       pocketsphinx_engine_t *engine = resource_engine->obj;
-       const apt_dir_layout_t *dir_layout = resource_engine->dir_layout;
+       pocketsphinx_engine_t *engine = engine_base->obj;
+       const apt_dir_layout_t *dir_layout = engine_base->dir_layout;
 
        char *file_path = NULL;
-       apr_filepath_merge(&file_path,dir_layout->conf_dir_path,POCKETSPHINX_CONFFILE_NAME,0,resource_engine->pool);
+       apr_filepath_merge(&file_path,dir_layout->conf_dir_path,POCKETSPHINX_CONFFILE_NAME,0,engine_base->pool);
 
        /* load properties */
-       pocketsphinx_properties_load(&engine->properties,file_path,dir_layout,resource_engine->pool);
+       pocketsphinx_properties_load(&engine->properties,file_path,dir_layout,engine_base->pool);
        return TRUE;
 }
 
 /** Close pocketsphinx engine */
-static apt_bool_t pocketsphinx_engine_close(mrcp_resource_engine_t *resource_engine)
+static apt_bool_t pocketsphinx_engine_close(mrcp_engine_t *engine_base)
 {
        return TRUE;
 }
 
 /** Create pocketsphinx recognizer */
-static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resource_engine_t *resource_engine, apr_pool_t *pool)
+static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_engine_t *engine_base, apr_pool_t *pool)
 {
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
        mrcp_engine_channel_t *channel;
-       mpf_codec_descriptor_t *codec_descriptor;
-       pocketsphinx_engine_t *engine = resource_engine->obj;
+       pocketsphinx_engine_t *engine = engine_base->obj;
+
+       /* create pocketsphinx recognizer */
        pocketsphinx_recognizer_t *recognizer = apr_palloc(pool,sizeof(pocketsphinx_recognizer_t));
        recognizer->decoder = NULL;
        recognizer->config = NULL;
@@ -215,27 +222,30 @@ static mrcp_engine_channel_t* pocketsphinx_engine_recognizer_create(mrcp_resourc
        recognizer->grammar_id = NULL;
        recognizer->grammar_table = apr_table_make(pool,1);
        recognizer->waveform = NULL;
+       recognizer->message_waiting = FALSE;
 
        /* 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;
-       }
+       capabilities = mpf_sink_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
+                       recognizer,           /* object to associate */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
 
        /* create engine channel base */
-       channel = mrcp_engine_sink_channel_create(
-                       resource_engine,      /* resource engine */
+       channel = mrcp_engine_channel_create(
+                       engine_base,          /* engine */
                        &channel_vtable,      /* virtual methods table of engine channel */
-                       &audio_stream_vtable, /* virtual methods table of audio stream */
                        recognizer,           /* object to associate */
-                       NULL,                 /* codec descriptor might be NULL by default */
+                       termination,          /* associated media termination */
                        pool);                /* pool to allocate memory from */
 
        apr_thread_mutex_create(&recognizer->mutex,APR_THREAD_MUTEX_DEFAULT,channel->pool);
@@ -290,6 +300,7 @@ static apt_bool_t pocketsphinx_recognizer_close(mrcp_engine_channel_t *channel)
        /* Signal recognition thread to terminate */
        apr_thread_mutex_lock(recognizer->mutex);
        recognizer->close_requested = TRUE;
+       recognizer->message_waiting = TRUE;
        apr_thread_cond_signal(recognizer->wait_object);
        apr_thread_mutex_unlock(recognizer->mutex);
        return TRUE;
@@ -303,6 +314,7 @@ static apt_bool_t pocketsphinx_recognizer_request_process(mrcp_engine_channel_t
        /* Store request and signal recognition thread to process the request */
        apr_thread_mutex_lock(recognizer->mutex);
        recognizer->request = request;
+       recognizer->message_waiting = TRUE;
        apr_thread_cond_signal(recognizer->wait_object);
        apr_thread_mutex_unlock(recognizer->mutex);
        return TRUE;
@@ -311,9 +323,10 @@ static apt_bool_t pocketsphinx_recognizer_request_process(mrcp_engine_channel_t
 /** Initialize pocketsphinx decoder [RECOG] */
 static apt_bool_t pocketsphinx_decoder_init(pocketsphinx_recognizer_t *recognizer, const char *grammar)
 {
+       const mpf_codec_descriptor_t *descriptor = mrcp_engine_sink_stream_codec_get(recognizer->channel);
        const char *model = recognizer->properties.model_8k;
        const char *rate = "8000";
-       if(recognizer->properties.preferred_model == POCKETSPHINX_MODEL_WIDEBAND) {
+       if(descriptor && descriptor->sampling_rate == 16000) {
                model = recognizer->properties.model_16k;
                rate = "16000";
        }
@@ -375,7 +388,6 @@ static apt_bool_t pocketsphinx_result_build(pocketsphinx_recognizer_t *recognize
                recognizer->grammar_id,
                recognizer->grammar_id,
                99,
-               recognizer->last_result,
                recognizer->last_result);
        if(body->buf) {
                mrcp_generic_header_t *generic_header;
@@ -409,16 +421,75 @@ static apt_bool_t pocketsphinx_grammars_clear(pocketsphinx_recognizer_t *recogni
        return TRUE;
 }
 
+/** Load pocketsphinx grammar [RECOG] */
+static mrcp_status_code_e pocketsphinx_grammar_load(pocketsphinx_recognizer_t *recognizer, const char *content_id, const char *content_type, const apt_str_t *content)
+{
+       /* load grammar */
+       mrcp_engine_channel_t *channel = recognizer->channel;
+       const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
+       const char *grammar_file_path = NULL;
+       const char *grammar_file_name = NULL;
+       apr_file_t *fd = NULL;
+       apr_status_t rv;
+       apr_size_t size;
+
+       /* only JSGF grammar is supported */
+       if(strstr(content_type,"jsgf") == NULL) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Supported Content-Type [%s] "APT_SIDRES_FMT,
+                       content_type,RECOGNIZER_SIDRES(recognizer));
+               return MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE;
+       }
+
+       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,
+               grammar_file_path,RECOGNIZER_SIDRES(recognizer));
+       rv = apr_file_open(&fd,grammar_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 Grammar File to Write [%s] "APT_SIDRES_FMT,
+                       grammar_file_path,RECOGNIZER_SIDRES(recognizer));
+               return MRCP_STATUS_CODE_METHOD_FAILED;
+       }
+
+       size = content->length;
+       apr_file_write(fd,content->buf,&size);
+       apr_file_close(fd);
+
+       /* init pocketsphinx decoder */
+       if(pocketsphinx_decoder_init(recognizer,grammar_file_path) != TRUE) {
+               apr_file_remove(grammar_file_path,channel->pool);
+               return MRCP_STATUS_CODE_METHOD_FAILED;
+       }
+       recognizer->grammar_id = content_id;
+       apr_table_setn(recognizer->grammar_table,content_id,grammar_file_path);
+       return MRCP_STATUS_CODE_SUCCESS;
+}
+
+/** Unload pocketsphinx grammar [RECOG] */
+static mrcp_status_code_e pocketsphinx_grammar_unload(pocketsphinx_recognizer_t *recognizer, const char *content_id)
+{
+       /* unload grammar */
+       const char *grammar_file_path = apr_table_get(recognizer->grammar_table,content_id);
+       if(!grammar_file_path) {
+               return MRCP_STATUS_CODE_ILLEGAL_PARAM_VALUE;
+       }
+
+       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Grammar File [%s] "APT_SIDRES_FMT,
+               grammar_file_path,RECOGNIZER_SIDRES(recognizer));
+       apr_file_remove(grammar_file_path,recognizer->channel->pool);
+       apr_table_unset(recognizer->grammar_table,content_id);
+       return MRCP_STATUS_CODE_SUCCESS;
+}
+
 /** Process DEFINE-GRAMMAR request [RECOG] */
 static apt_bool_t pocketsphinx_define_grammar(pocketsphinx_recognizer_t *recognizer, mrcp_message_t *request, mrcp_message_t *response)
 {
        const char *content_type = NULL;
        const char *content_id = NULL;
-       apt_str_t *grammar = NULL;
-
        mrcp_engine_channel_t *channel = recognizer->channel;
 
-       /* get recognizer header */
        mrcp_generic_header_t *generic_header = mrcp_generic_header_get(request);
        mrcp_recog_header_t *recog_header = mrcp_resource_header_prepare(response);
        if(!generic_header || !recog_header) {
@@ -427,7 +498,7 @@ static apt_bool_t pocketsphinx_define_grammar(pocketsphinx_recognizer_t *recogni
 
        recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_SUCCESS;
        mrcp_resource_header_property_add(response,RECOGNIZER_HEADER_COMPLETION_CAUSE);
-       
+
        /* content-id must be specified */
        if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_ID) == TRUE) {
                content_id = generic_header->content_id.buf;
@@ -439,78 +510,31 @@ static apt_bool_t pocketsphinx_define_grammar(pocketsphinx_recognizer_t *recogni
                return FALSE;
        }
 
-       if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
-               grammar = &request->body;
-       }
-
-       if(grammar) {
-               /* load grammar */
-               const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
-               const char *grammar_file_path = NULL;
-               const char *grammar_file_name = NULL;
-               apr_file_t *fd = NULL;
-               apr_status_t rv;
-               apr_size_t size;
-
+       if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_LENGTH) == TRUE &&
+               generic_header->content_length) {
                /* 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 "APT_SIDRES_FMT,RECOGNIZER_SIDRES(recognizer));
                        response->start_line.status_code = MRCP_STATUS_CODE_MISSING_PARAM;
                        recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
                        return FALSE;
                }
-       
-               /* only JSGF grammar is supported */
-               if(strstr(content_type,"jsgf") == NULL) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Not Supported Content-Type [%s] "APT_SIDRES_FMT,
-                               content_type,RECOGNIZER_SIDRES(recognizer));
-                       response->start_line.status_code = MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE;
-                       recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
-                       return FALSE;
-               }
-
-               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,
-                       grammar_file_path,RECOGNIZER_SIDRES(recognizer));
-               rv = apr_file_open(&fd,grammar_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 Grammar File to Write [%s] "APT_SIDRES_FMT,
-                               grammar_file_path,RECOGNIZER_SIDRES(recognizer));
-                       response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+               response->start_line.status_code = pocketsphinx_grammar_load(recognizer,content_id,content_type,&request->body);
+               if(response->start_line.status_code != MRCP_STATUS_CODE_SUCCESS) {
                        recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
                        return FALSE;
                }
-
-               size = grammar->length;
-               apr_file_write(fd,grammar->buf,&size);
-               apr_file_close(fd);
-
-               /* init pocketsphinx decoder */
-               if(pocketsphinx_decoder_init(recognizer,grammar_file_path) == TRUE) {
-                       recognizer->grammar_id = content_id;
-                       apr_table_setn(recognizer->grammar_table,content_id,grammar_file_path);
-               }
-               else {
-                       response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
-                       recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
-                       apr_file_remove(grammar_file_path,channel->pool);
-                       return FALSE;
-               }
        }
        else {
-               /* unload grammar */
-               const char *grammar_file_path = apr_table_get(recognizer->grammar_table,content_id);
-               if(grammar_file_path) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remove Grammar File [%s] "APT_SIDRES_FMT,
-                               grammar_file_path,RECOGNIZER_SIDRES(recognizer));
-                       apr_file_remove(grammar_file_path,channel->pool);
-                       apr_table_unset(recognizer->grammar_table,content_id);
+               response->start_line.status_code = pocketsphinx_grammar_unload(recognizer,content_id);
+               if(response->start_line.status_code != MRCP_STATUS_CODE_SUCCESS) {
+                       recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
+                       return FALSE;
                }
        }
 
@@ -522,13 +546,49 @@ 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)
 {
+       const char *content_type = NULL;
        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) {
+       mrcp_generic_header_t *generic_header = mrcp_generic_header_get(request);
+       if(!generic_header || !response_recog_header) {
                return FALSE;
        }
 
+       /* 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 "APT_SIDRES_FMT,RECOGNIZER_SIDRES(recognizer));
+               response->start_line.status_code = MRCP_STATUS_CODE_MISSING_PARAM;
+               response_recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
+               return FALSE;
+       }
+
+       if(strcmp(content_type,"text/uri-list") == 0) {
+               /* assume the uri-list contains last defined (active) grammar for now */
+       }
+       else {
+               const char *content_id = NULL;
+               /* content-id must be specified */
+               if(mrcp_generic_header_property_check(request,GENERIC_HEADER_CONTENT_ID) == TRUE) {
+                       content_id = generic_header->content_id.buf;
+               }
+               if(!content_id) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Content-Id "APT_SIDRES_FMT,RECOGNIZER_SIDRES(recognizer));
+                       response->start_line.status_code = MRCP_STATUS_CODE_MISSING_PARAM;
+                       response_recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
+                       return FALSE;
+               }
+
+               response->start_line.status_code = pocketsphinx_grammar_load(recognizer,content_id,content_type,&request->body);
+               if(response->start_line.status_code != MRCP_STATUS_CODE_SUCCESS) {
+                       response_recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_GRAM_LOAD_FAILURE;
+                       return FALSE;
+               }
+       }
+
        if(!recognizer->decoder || ps_start_utt(recognizer->decoder, NULL) < 0) {
                response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
                response_recog_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_ERROR;
@@ -557,8 +617,9 @@ static apt_bool_t pocketsphinx_recognize(pocketsphinx_recognizer_t *recognizer,
        /* 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);
+               const char *waveform_file_name = apr_psprintf(channel->pool,"utter-%s-%"MRCP_REQUEST_ID_FMT".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);
@@ -730,11 +791,13 @@ static void* APR_THREAD_FUNC pocketsphinx_recognizer_run(apr_thread_t *thread, v
        mrcp_engine_channel_open_respond(recognizer->channel,TRUE);
 
        do {
+               apr_thread_mutex_lock(recognizer->mutex);
                /** Wait for MRCP requests */
                apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Wait for incoming messages "APT_SIDRES_FMT, RECOGNIZER_SIDRES(recognizer));
-               apr_thread_mutex_lock(recognizer->mutex);
-               apr_thread_cond_wait(recognizer->wait_object,recognizer->mutex);
-               apr_thread_mutex_unlock(recognizer->mutex);
+               if (!recognizer->message_waiting) {
+                       apr_thread_cond_wait(recognizer->wait_object,recognizer->mutex);
+               }
+               recognizer->message_waiting = FALSE;
 
                if(recognizer->request) {
                        /* store request message and further dispatch it */
@@ -746,6 +809,7 @@ static void* APR_THREAD_FUNC pocketsphinx_recognizer_run(apr_thread_t *thread, v
                        /* end of input detected, get recognition result and raise recognition complete event */
                        pocketsphinx_recognition_complete(recognizer,recognizer->complete_event);
                }
+               apr_thread_mutex_unlock(recognizer->mutex);
        }
        while(recognizer->close_requested == FALSE);
 
@@ -814,6 +878,7 @@ static apt_bool_t pocketsphinx_end_of_input(pocketsphinx_recognizer_t *recognize
        /* signal recognition thread first */
        apr_thread_mutex_lock(recognizer->mutex);
        recognizer->complete_event = message;
+       recognizer->message_waiting = TRUE;
        apr_thread_cond_signal(recognizer->wait_object);
        apr_thread_mutex_unlock(recognizer->mutex);
        return TRUE;
index 2b8fe94e1cfca1d005ef33a54229629cb1e650a2..ecd50539950c800c67033ddb7de51f89228e9b9c 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <stdlib.h>
 #include <apr_xml.h>
 #include "pocketsphinx_properties.h"
 #include "apt_log.h"
diff --git a/libs/unimrcp/plugins/mrcp-recorder/Makefile.am b/libs/unimrcp/plugins/mrcp-recorder/Makefile.am
new file mode 100644 (file)
index 0000000..bdb2274
--- /dev/null
@@ -0,0 +1,16 @@
+MAINTAINERCLEANFILES      = Makefile.in
+
+INCLUDES                   = -Iinclude \
+                             -I$(top_srcdir)/libs/mrcp-engine/include \
+                             -I$(top_srcdir)/libs/mrcp/include \
+                             -I$(top_srcdir)/libs/mrcp/message/include \
+                             -I$(top_srcdir)/libs/mrcp/control/include \
+                             -I$(top_srcdir)/libs/mrcp/resources/include \
+                             -I$(top_srcdir)/libs/mpf/include \
+                             -I$(top_srcdir)/libs/apr-toolkit/include \
+                             $(UNIMRCP_APR_INCLUDES) $(UNIMRCP_APU_INCLUDES)
+
+plugin_LTLIBRARIES         = mrcprecorder.la
+
+mrcprecorder_la_SOURCES    = src/mrcp_recorder_engine.c
+mrcprecorder_la_LDFLAGS    = -module $(PLUGIN_LT_VERSION)
diff --git a/libs/unimrcp/plugins/mrcp-recorder/mrcprecorder.vcproj b/libs/unimrcp/plugins/mrcp-recorder/mrcprecorder.vcproj
new file mode 100644 (file)
index 0000000..da80adc
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="8.00"
+       Name="mrcprecorder"
+       ProjectGUID="{5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}"
+       RootNamespace="mrcprecorder"
+       Keyword="Win32Proj"
+       >
+       <Platforms>
+               <Platform
+                       Name="Win32"
+               />
+       </Platforms>
+       <ToolFiles>
+       </ToolFiles>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unidebug.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpplugin.vsprops"
+                       CharacterSet="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       ConfigurationType="2"
+                       InheritedPropertySheets="$(ProjectDir)..\..\build\vsprops\unirelease.vsprops;$(ProjectDir)..\..\build\vsprops\unimrcpplugin.vsprops"
+                       CharacterSet="1"
+                       WholeProgramOptimization="1"
+                       >
+                       <Tool
+                               Name="VCPreBuildEventTool"
+                       />
+                       <Tool
+                               Name="VCCustomBuildTool"
+                       />
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"
+                       />
+                       <Tool
+                               Name="VCMIDLTool"
+                       />
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalIncludeDirectories="include"
+                       />
+                       <Tool
+                               Name="VCManagedResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                       />
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                       />
+                       <Tool
+                               Name="VCLinkerTool"
+                       />
+                       <Tool
+                               Name="VCALinkTool"
+                       />
+                       <Tool
+                               Name="VCManifestTool"
+                       />
+                       <Tool
+                               Name="VCXDCMakeTool"
+                       />
+                       <Tool
+                               Name="VCBscMakeTool"
+                       />
+                       <Tool
+                               Name="VCFxCopTool"
+                       />
+                       <Tool
+                               Name="VCAppVerifierTool"
+                       />
+                       <Tool
+                               Name="VCWebDeploymentTool"
+                       />
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                       />
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="include"
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+                       >
+               </Filter>
+               <Filter
+                       Name="src"
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+                       >
+                       <File
+                               RelativePath=".\src\mrcp_recorder_engine.c"
+                               >
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/libs/unimrcp/plugins/mrcp-recorder/src/mrcp_recorder_engine.c b/libs/unimrcp/plugins/mrcp-recorder/src/mrcp_recorder_engine.c
new file mode 100644 (file)
index 0000000..7a928dc
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * 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.
+ */
+
+/* 
+ * Mandatory rules concerning plugin implementation.
+ * 1. Each plugin MUST implement a plugin/engine creator function
+ *    with the exact signature and name (the main entry point)
+ *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+ * 2. Each plugin MUST declare its version number
+ *        MRCP_PLUGIN_VERSION_DECLARE
+ * 3. One and only one response MUST be sent back to the received request.
+ * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
+ *   (asynchronous response can be sent from the context of other thread)
+ * 5. Methods (callbacks) of the MPF engine stream MUST not block.
+ */
+
+#include "mrcp_recorder_engine.h"
+#include "mpf_activity_detector.h"
+#include "apt_log.h"
+
+#define RECORDER_ENGINE_TASK_NAME "Recorder Engine"
+
+typedef struct recorder_channel_t recorder_channel_t;
+
+/** Declaration of recorder engine methods */
+static apt_bool_t recorder_engine_destroy(mrcp_engine_t *engine);
+static apt_bool_t recorder_engine_open(mrcp_engine_t *engine);
+static apt_bool_t recorder_engine_close(mrcp_engine_t *engine);
+static mrcp_engine_channel_t* recorder_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
+
+static const struct mrcp_engine_method_vtable_t engine_vtable = {
+       recorder_engine_destroy,
+       recorder_engine_open,
+       recorder_engine_close,
+       recorder_engine_channel_create
+};
+
+
+/** Declaration of recorder channel methods */
+static apt_bool_t recorder_channel_destroy(mrcp_engine_channel_t *channel);
+static apt_bool_t recorder_channel_open(mrcp_engine_channel_t *channel);
+static apt_bool_t recorder_channel_close(mrcp_engine_channel_t *channel);
+static apt_bool_t recorder_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
+
+static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
+       recorder_channel_destroy,
+       recorder_channel_open,
+       recorder_channel_close,
+       recorder_channel_request_process
+};
+
+/** Declaration of recorder audio stream methods */
+static apt_bool_t recorder_stream_destroy(mpf_audio_stream_t *stream);
+static apt_bool_t recorder_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
+static apt_bool_t recorder_stream_close(mpf_audio_stream_t *stream);
+static apt_bool_t recorder_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
+
+static const mpf_audio_stream_vtable_t audio_stream_vtable = {
+       recorder_stream_destroy,
+       NULL,
+       NULL,
+       NULL,
+       recorder_stream_open,
+       recorder_stream_close,
+       recorder_stream_write
+};
+
+/** Declaration of recorder channel */
+struct recorder_channel_t {
+       /** Engine channel base */
+       mrcp_engine_channel_t   *channel;
+
+       /** Active (in-progress) record request */
+       mrcp_message_t          *record_request;
+       /** Pending stop response */
+       mrcp_message_t          *stop_response;
+       /** Indicates whether input timers are started */
+       apt_bool_t               timers_started;
+       /** Voice activity detector */
+       mpf_activity_detector_t *detector;
+       /** Max length of the recording in msec */
+       apr_size_t               max_time;
+       /** Elapsed time of the recording in msec */
+       apr_size_t               cur_time;
+       /** Written size of the recording in bytes */
+       apr_size_t               cur_size;
+       /** File name of the recording */
+       const char              *file_name;
+       /** File to write to */
+       FILE                    *audio_out;
+};
+
+
+/** Declare this macro to set plugin version */
+MRCP_PLUGIN_VERSION_DECLARE
+
+/** Declare this macro to use log routine of the server, plugin is loaded from */
+MRCP_PLUGIN_LOGGER_IMPLEMENT
+
+/** Create recorder engine */
+MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
+{
+       /* create engine base */
+       return mrcp_engine_create(
+                               MRCP_RECORDER_RESOURCE,    /* MRCP resource identifier */
+                               NULL,                      /* object to associate */
+                               &engine_vtable,            /* virtual methods table of engine */
+                               pool);                     /* pool to allocate memory from */
+}
+
+/** Destroy recorder engine */
+static apt_bool_t recorder_engine_destroy(mrcp_engine_t *engine)
+{
+       return TRUE;
+}
+
+/** Open recorder engine */
+static apt_bool_t recorder_engine_open(mrcp_engine_t *engine)
+{
+       return TRUE;
+}
+
+/** Close recorder engine */
+static apt_bool_t recorder_engine_close(mrcp_engine_t *engine)
+{
+       return TRUE;
+}
+
+static mrcp_engine_channel_t* recorder_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
+{
+       mpf_stream_capabilities_t *capabilities;
+       mpf_termination_t *termination; 
+
+       /* create recorder channel */
+       recorder_channel_t *recorder_channel = apr_palloc(pool,sizeof(recorder_channel_t));
+       recorder_channel->record_request = NULL;
+       recorder_channel->stop_response = NULL;
+       recorder_channel->detector = mpf_activity_detector_create(pool);
+       recorder_channel->max_time = 0;
+       recorder_channel->cur_time = 0;
+       recorder_channel->cur_size = 0;
+       recorder_channel->file_name = NULL;
+       recorder_channel->audio_out = NULL;
+
+       capabilities = mpf_sink_stream_capabilities_create(pool);
+       mpf_codec_capabilities_add(
+                       &capabilities->codecs,
+                       MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
+                       "LPCM");
+
+       /* create media termination */
+       termination = mrcp_engine_audio_termination_create(
+                       recorder_channel,     /* object to associate */
+                       &audio_stream_vtable, /* virtual methods table of audio stream */
+                       capabilities,         /* stream capabilities */
+                       pool);                /* pool to allocate memory from */
+
+       /* create engine channel base */
+       recorder_channel->channel = mrcp_engine_channel_create(
+                       engine,               /* engine */
+                       &channel_vtable,      /* virtual methods table of engine channel */
+                       recorder_channel,     /* object to associate */
+                       termination,          /* associated media termination */
+                       pool);                /* pool to allocate memory from */
+
+       return recorder_channel->channel;
+}
+
+/** Destroy engine channel */
+static apt_bool_t recorder_channel_destroy(mrcp_engine_channel_t *channel)
+{
+       /* nothing to destrtoy */
+       return TRUE;
+}
+
+/** Open engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t recorder_channel_open(mrcp_engine_channel_t *channel)
+{
+       /* open channel and send asynch response */
+       return mrcp_engine_channel_open_respond(channel,TRUE);
+}
+
+/** Close engine channel (asynchronous response MUST be sent)*/
+static apt_bool_t recorder_channel_close(mrcp_engine_channel_t *channel)
+{
+       /* close channel, make sure there is no activity and send asynch response */
+       return mrcp_engine_channel_close_respond(channel);
+}
+
+/** Open file to record */
+static apt_bool_t recorder_file_open(recorder_channel_t *recorder_channel, mrcp_message_t *request)
+{
+       mrcp_engine_channel_t *channel = recorder_channel->channel;
+       const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
+       const mpf_codec_descriptor_t *descriptor = mrcp_engine_sink_stream_codec_get(channel);
+       char *file_name = apr_psprintf(channel->pool,"rec-%dkHz-%s-%"MRCP_REQUEST_ID_FMT".pcm",
+               descriptor ? descriptor->sampling_rate/1000 : 8,
+               request->channel_id.session_id.buf,
+               request->start_line.request_id);
+       char *file_path = apt_datadir_filepath_get(dir_layout,file_name,channel->pool);
+       if(!file_path) {
+               return FALSE;
+       }
+
+       if(recorder_channel->audio_out) {
+               fclose(recorder_channel->audio_out);
+               recorder_channel->audio_out = NULL;
+       }
+
+       recorder_channel->audio_out = fopen(file_path,"wb");
+       if(!recorder_channel->audio_out) {
+               return FALSE;
+       }
+
+       recorder_channel->file_name = file_name;
+       return TRUE;
+}
+
+/** Set Record-URI header field */
+static apt_bool_t recorder_channel_uri_set(recorder_channel_t *recorder_channel, mrcp_message_t *message)
+{
+       char *record_uri;
+       /* get/allocate recorder header */
+       mrcp_recorder_header_t *recorder_header = mrcp_resource_header_prepare(message);
+       if(!recorder_header) {
+               return FALSE;
+       }
+       
+       record_uri = apr_psprintf(message->pool,"<file://mediaserver/data/%s>;size=%d;duration=%d",
+                               recorder_channel->file_name,
+                               recorder_channel->cur_size,
+                               recorder_channel->cur_time);
+
+       apt_string_set(&recorder_header->record_uri,record_uri);
+       mrcp_resource_header_property_add(message,RECORDER_HEADER_RECORD_URI);
+       return TRUE;
+}
+
+/** Process RECORD request */
+static apt_bool_t recorder_channel_record(recorder_channel_t *recorder_channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       /* process RECORD request */
+       mrcp_recorder_header_t *recorder_header;
+       recorder_channel->timers_started = TRUE;
+
+       /* get recorder header */
+       recorder_header = mrcp_resource_header_get(request);
+       if(recorder_header) {
+               if(mrcp_resource_header_property_check(request,RECORDER_HEADER_START_INPUT_TIMERS) == TRUE) {
+                       recorder_channel->timers_started = recorder_header->start_input_timers;
+               }
+               if(mrcp_resource_header_property_check(request,RECORDER_HEADER_NO_INPUT_TIMEOUT) == TRUE) {
+                       mpf_activity_detector_noinput_timeout_set(recorder_channel->detector,recorder_header->no_input_timeout);
+               }
+               if(mrcp_resource_header_property_check(request,RECORDER_HEADER_FINAL_SILENCE) == TRUE) {
+                       mpf_activity_detector_silence_timeout_set(recorder_channel->detector,recorder_header->final_silence);
+               }
+               if(mrcp_resource_header_property_check(request,RECORDER_HEADER_MAX_TIME) == TRUE) {
+                       recorder_channel->max_time = recorder_header->max_time;
+               }
+       }
+
+       /* open file to record */
+       if(recorder_file_open(recorder_channel,request) == FALSE) {
+               response->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+               response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
+               /* send asynchronous response */
+               mrcp_engine_channel_message_send(recorder_channel->channel,response);
+               return TRUE;
+       }
+
+       recorder_channel->cur_time = 0;
+       recorder_channel->cur_size = 0;
+       response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* send asynchronous response */
+       mrcp_engine_channel_message_send(recorder_channel->channel,response);
+       recorder_channel->record_request = request;
+       return TRUE;
+}
+
+/** Process STOP request */
+static apt_bool_t recorder_channel_stop(recorder_channel_t *recorder_channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       /* store STOP request, make sure there is no more activity and only then send the response */
+       recorder_channel->stop_response = response;
+       return TRUE;
+}
+
+/** Process START-INPUT-TIMERS request */
+static apt_bool_t recorder_channel_timers_start(recorder_channel_t *recorder_channel, mrcp_message_t *request, mrcp_message_t *response)
+{
+       recorder_channel->timers_started = TRUE;
+       return mrcp_engine_channel_message_send(recorder_channel->channel,response);
+}
+
+/** Process MRCP channel request (asynchronous response MUST be sent)*/
+static apt_bool_t recorder_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request)
+{
+       apt_bool_t processed = FALSE;
+       recorder_channel_t *recorder_channel = channel->method_obj;
+       mrcp_message_t *response = mrcp_response_create(request,request->pool);
+       switch(request->start_line.method_id) {
+               case RECORDER_SET_PARAMS:
+                       break;
+               case RECORDER_GET_PARAMS:
+                       break;
+               case RECORDER_RECORD:
+                       processed = recorder_channel_record(recorder_channel,request,response);
+                       break;
+               case RECORDER_STOP:
+                       processed = recorder_channel_stop(recorder_channel,request,response);
+                       break;
+               case RECORDER_START_INPUT_TIMERS:
+                       processed = recorder_channel_timers_start(recorder_channel,request,response);
+                       break;
+               default:
+                       break;
+       }
+       if(processed == FALSE) {
+               /* send asynchronous response for not handled request */
+               mrcp_engine_channel_message_send(channel,response);
+       }
+       return TRUE;
+}
+
+/* Raise START-OF-INPUT event */
+static apt_bool_t recorder_start_of_input(recorder_channel_t *recorder_channel)
+{
+       /* create START-OF-INPUT event */
+       mrcp_message_t *message = mrcp_event_create(
+                                               recorder_channel->record_request,
+                                               RECORDER_START_OF_INPUT,
+                                               recorder_channel->record_request->pool);
+       if(!message) {
+               return FALSE;
+       }
+
+       /* set request state */
+       message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
+       /* send asynch event */
+       return mrcp_engine_channel_message_send(recorder_channel->channel,message);
+}
+
+/* Raise RECORD-COMPLETE event */
+static apt_bool_t recorder_record_complete(recorder_channel_t *recorder_channel, mrcp_recorder_completion_cause_e cause)
+{
+       mrcp_recorder_header_t *recorder_header;
+       /* create RECORD-COMPLETE event */
+       mrcp_message_t *message = mrcp_event_create(
+                                               recorder_channel->record_request,
+                                               RECORDER_RECORD_COMPLETE,
+                                               recorder_channel->record_request->pool);
+       if(!message) {
+               return FALSE;
+       }
+
+       if(recorder_channel->audio_out) {
+               fclose(recorder_channel->audio_out);
+               recorder_channel->audio_out = NULL;
+       }
+
+       /* get/allocate recorder header */
+       recorder_header = mrcp_resource_header_prepare(message);
+       if(recorder_header) {
+               /* set completion cause */
+               recorder_header->completion_cause = cause;
+               mrcp_resource_header_property_add(message,RECORDER_HEADER_COMPLETION_CAUSE);
+       }
+       /* set record-uri */
+       recorder_channel_uri_set(recorder_channel,message);
+       /* set request state */
+       message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
+
+       recorder_channel->record_request = NULL;
+       /* send asynch event */
+       return mrcp_engine_channel_message_send(recorder_channel->channel,message);
+}
+
+/** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
+static apt_bool_t recorder_stream_destroy(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action before open */
+static apt_bool_t recorder_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to perform any action after close */
+static apt_bool_t recorder_stream_close(mpf_audio_stream_t *stream)
+{
+       return TRUE;
+}
+
+/** Callback is called from MPF engine context to write/send new frame */
+static apt_bool_t recorder_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
+{
+       recorder_channel_t *recorder_channel = stream->obj;
+       if(recorder_channel->stop_response) {
+               if(recorder_channel->audio_out) {
+                       fclose(recorder_channel->audio_out);
+                       recorder_channel->audio_out = NULL;
+               }
+               
+               if(recorder_channel->record_request){
+                       /* set record-uri */
+                       recorder_channel_uri_set(recorder_channel,recorder_channel->stop_response);
+               }
+               /* send asynchronous response to STOP request */
+               mrcp_engine_channel_message_send(recorder_channel->channel,recorder_channel->stop_response);
+               recorder_channel->stop_response = NULL;
+               recorder_channel->record_request = NULL;
+               return TRUE;
+       }
+
+       if(recorder_channel->record_request) {
+               mpf_detector_event_e det_event = mpf_activity_detector_process(recorder_channel->detector,frame);
+               switch(det_event) {
+                       case MPF_DETECTOR_EVENT_ACTIVITY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Activity");
+                               recorder_start_of_input(recorder_channel);
+                               break;
+                       case MPF_DETECTOR_EVENT_INACTIVITY:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity");
+                               recorder_record_complete(recorder_channel,RECORDER_COMPLETION_CAUSE_SUCCESS_SILENCE);
+                               break;
+                       case MPF_DETECTOR_EVENT_NOINPUT:
+                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Noinput");
+                               if(recorder_channel->timers_started == TRUE) {
+                                       recorder_record_complete(recorder_channel,RECORDER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT);
+                               }
+                               break;
+                       default:
+                               break;
+               }
+
+               if(recorder_channel->audio_out) {
+                       fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,recorder_channel->audio_out);
+                       
+                       recorder_channel->cur_size += frame->codec_frame.size;
+                       recorder_channel->cur_time += CODEC_FRAME_TIME_BASE;
+                       if(recorder_channel->max_time && recorder_channel->cur_time >= recorder_channel->max_time) {
+                               recorder_record_complete(recorder_channel,RECORDER_COMPLETION_CAUSE_SUCCESS_MAXTIME);
+                       }
+               }
+       }
+       return TRUE;
+}
index 4075ebb546dde9fa102a8bda3bc0ca75de12bf5e..446c1ab5773c481ae59d897e297f88067a5abb23 100644 (file)
@@ -17,8 +17,6 @@
 #include <apr_thread_cond.h>
 #include "apt_test_suite.h"
 #include "mpf_engine.h"
-#include "mpf_user.h"
-#include "mpf_termination.h"
 #include "mpf_rtp_termination_factory.h"
 #include "mpf_file_termination_factory.h"
 #include "mpf_audio_file_descriptor.h"
@@ -51,8 +49,8 @@ struct mpf_suite_engine_t {
        /** The main task of the test engine, which sends messages to MPF engine and 
         * processes responses and events sent back from MPF engine */
        apt_consumer_task_t       *consumer_task;
-       /** MPF engine task */
-       apt_task_t                *engine_task;
+       /** MPF engine */
+       mpf_engine_t              *engine;
        /** RTP termination factory */
        mpf_termination_factory_t *rtp_termination_factory;
        /** File termination factory */
@@ -68,7 +66,7 @@ static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * c
 
 static void mpf_suite_on_start_complete(apt_task_t *task);
 static void mpf_suite_on_terminate_complete(apt_task_t *task);
-static apt_bool_t mpf_suite_msg_process(apt_task_t *task, apt_task_msg_t *msg);
+static apt_bool_t mpf_suite_task_msg_process(apt_task_t *task, apt_task_msg_t *msg);
 
 static mpf_audio_file_descriptor_t* mpf_file_reader_descriptor_create(mpf_suite_session_t *session);
 static mpf_audio_file_descriptor_t* mpf_file_writer_descriptor_create(mpf_suite_session_t *session);
@@ -97,7 +95,7 @@ static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * c
 
        suite_engine = apr_palloc(suite->pool,sizeof(mpf_suite_engine_t));
 
-       engine = mpf_engine_create(suite->pool);
+       engine = mpf_engine_create(1,suite->pool);
        if(!engine) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create MPF Engine");
                return FALSE;
@@ -106,7 +104,7 @@ static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * c
        if(codec_manager) {
                mpf_engine_codec_manager_register(engine,codec_manager);
        }
-       suite_engine->engine_task = mpf_task_get(engine);
+       suite_engine->engine = engine;
 
        config = mpf_rtp_config_create(suite->pool);
        apt_string_set(&config->ip,"127.0.0.1");
@@ -126,12 +124,12 @@ static apt_bool_t mpf_test_run(apt_test_suite_t *suite, int argc, const char * c
        task = apt_consumer_task_base_get(suite_engine->consumer_task);
        vtable = apt_task_vtable_get(task);
        if(vtable) {
-               vtable->process_msg = mpf_suite_msg_process;
+               vtable->process_msg = mpf_suite_task_msg_process;
                vtable->on_start_complete = mpf_suite_on_start_complete;
                vtable->on_terminate_complete = mpf_suite_on_terminate_complete;
        }
 
-       apt_task_add(task,suite_engine->engine_task);
+       apt_task_add(task,mpf_task_get(engine));
 
        apr_thread_mutex_create(&suite_engine->wait_object_mutex,APR_THREAD_MUTEX_UNNESTED,suite->pool);
        apr_thread_cond_create(&suite_engine->wait_object,suite->pool);
@@ -163,8 +161,8 @@ static void mpf_suite_on_start_complete(apt_task_t *task)
        mpf_suite_session_t *session;
        apt_task_t *consumer_task;
        mpf_suite_engine_t *suite_engine;
-       apt_task_msg_t *msg;
-       mpf_message_t *mpf_message;
+       mpf_task_msg_t *task_msg = NULL;
+       void *descriptor;
        apr_pool_t *pool = NULL;
 
        consumer_task = apt_task_object_get(task);
@@ -180,22 +178,17 @@ static void mpf_suite_on_start_complete(apt_task_t *task)
        session->rtp_mode = TRUE;
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create MPF Context");
-       session->context = mpf_context_create(session,2,pool);
+       session->context = mpf_engine_context_create(suite_engine->engine,session,2,pool);
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Termination [1]");
        session->termination1 = mpf_termination_create(suite_engine->file_termination_factory,session,session->pool);
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Termination [1]");
-       msg = apt_task_msg_get(task);
-       msg->type = TASK_MSG_USER;
-       mpf_message = (mpf_message_t*) msg->data;
-
-       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
-       mpf_message->command_id = MPF_COMMAND_ADD;
-       mpf_message->context = session->context;
-       mpf_message->termination = session->termination1;
-       mpf_message->descriptor = mpf_file_reader_descriptor_create(session);
-       apt_task_msg_signal(suite_engine->engine_task,msg);
+       descriptor = mpf_file_reader_descriptor_create(session);
+       mpf_engine_termination_message_add(
+                       suite_engine->engine,
+                       MPF_ADD_TERMINATION,session->context,session->termination1,descriptor,
+                       &task_msg);
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Create Termination [2]");
        if(session->rtp_mode == TRUE) {
@@ -206,21 +199,20 @@ static void mpf_suite_on_start_complete(apt_task_t *task)
        }
 
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Add Termination [2]");
-       msg = apt_task_msg_get(task);
-       msg->type = TASK_MSG_USER;
-       mpf_message = (mpf_message_t*) msg->data;
-
-       mpf_message->message_type = MPF_MESSAGE_TYPE_REQUEST;
-       mpf_message->command_id = MPF_COMMAND_ADD;
-       mpf_message->context = session->context;
-       mpf_message->termination = session->termination2;
+       descriptor = NULL;
        if(session->rtp_mode == TRUE) {
-               mpf_message->descriptor = mpf_rtp_local_descriptor_create(session);
+               descriptor = mpf_rtp_local_descriptor_create(session);
        }
        else {
-               mpf_message->descriptor = mpf_file_writer_descriptor_create(session);
+               descriptor = mpf_file_writer_descriptor_create(session);
        }
-       apt_task_msg_signal(suite_engine->engine_task,msg);
+
+       mpf_engine_termination_message_add(
+                       suite_engine->engine,
+                       MPF_ADD_TERMINATION,session->context,session->termination2,descriptor,
+                       &task_msg);
+
+       mpf_engine_message_send(suite_engine->engine,&task_msg);
 }
 
 /** Execution of MPF test suite scenario is terminated  */
@@ -229,147 +221,118 @@ static void mpf_suite_on_terminate_complete(apt_task_t *task)
        apt_log(APT_LOG_MARK,APT_PRIO_INFO,"On MPF Suite Terminate");
 }
 
-/** Process task messages  */
-static apt_bool_t mpf_suite_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+/** Process MPF response  */
+static apt_bool_t mpf_suite_response_process(mpf_suite_engine_t *suite_engine, const mpf_message_t *mpf_message)
 {
-       const mpf_message_t *mpf_message = (const mpf_message_t*) msg->data;
-       if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Response");
-               if(mpf_message->command_id == MPF_COMMAND_ADD) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Add Termination");
-                       if(mpf_message->termination) {
-                               mpf_suite_session_t *session;
-                               session = mpf_termination_object_get(mpf_message->termination);
-                               if(session->termination2 == mpf_message->termination && session->rtp_mode == TRUE) {
-                                       apt_task_msg_t *msg;
-                                       mpf_message_t *request;
-                                       apt_task_t *consumer_task;
-                                       mpf_suite_engine_t *suite_engine;
-
-                                       consumer_task = apt_task_object_get(task);
-                                       suite_engine = apt_task_object_get(consumer_task);
-
-                                       msg = apt_task_msg_get(task);
-                                       msg->type = TASK_MSG_USER;
-                                       request = (mpf_message_t*) msg->data;
-
-                                       request->message_type = MPF_MESSAGE_TYPE_REQUEST;
-                                       request->command_id = MPF_COMMAND_MODIFY;
-                                       request->context = session->context;
-                                       request->termination = session->termination2;
-                                       request->descriptor = mpf_rtp_remote_descriptor_create(session);
-                                       apt_task_msg_signal(suite_engine->engine_task,msg);
-                               }
-                       }
-               }
-               else if(mpf_message->command_id == MPF_COMMAND_SUBTRACT) {
-                       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Subtract Termination");
-                       if(mpf_message->termination) {
-                               mpf_suite_session_t *session;
-                               session = mpf_termination_object_get(mpf_message->termination);
-                               if(session->termination1 == mpf_message->termination) {
-                                       session->termination1 = NULL;
-                               }
-                               if(session->termination2 == mpf_message->termination) {
-                                       session->termination2 = NULL;
-                               }
-                               mpf_termination_destroy(mpf_message->termination);
-
-                               if(!session->termination1 && !session->termination2) {
-                                       apt_task_t *consumer_task;
-                                       mpf_suite_engine_t *suite_engine;
-
-                                       mpf_context_destroy(session->context);
-                                       session->context = NULL;
-                                       apr_pool_destroy(session->pool);
-
-                                       consumer_task = apt_task_object_get(task);
-                                       suite_engine = apt_task_object_get(consumer_task);
-
-                                       apr_thread_mutex_lock(suite_engine->wait_object_mutex);
-                                       apr_thread_cond_signal(suite_engine->wait_object);
-                                       apr_thread_mutex_unlock(suite_engine->wait_object_mutex);
-                               }
+       mpf_task_msg_t *task_msg = NULL;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Response");
+       if(mpf_message->command_id == MPF_ADD_TERMINATION) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Add Termination");
+               if(mpf_message->termination) {
+                       mpf_suite_session_t *session;
+                       session = mpf_termination_object_get(mpf_message->termination);
+                       if(session->termination2 == mpf_message->termination && session->rtp_mode == TRUE) {
+                               void *descriptor = mpf_rtp_remote_descriptor_create(session);
+                               mpf_engine_termination_message_add(
+                                       suite_engine->engine,
+                                       MPF_MODIFY_TERMINATION,session->context,session->termination2,descriptor,
+                                       &task_msg);
                        }
                }
        }
-       else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
-               apt_task_t *consumer_task;
-               mpf_suite_engine_t *suite_engine;
-               apt_task_msg_t *msg;
-               mpf_message_t *request;
-               mpf_suite_session_t *session;
-               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
+       else if(mpf_message->command_id == MPF_SUBTRACT_TERMINATION) {
+               apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"On Subtract Termination");
                if(mpf_message->termination) {
+                       mpf_suite_session_t *session;
                        session = mpf_termination_object_get(mpf_message->termination);
-                       if(session->termination1) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [1]");
-                               msg = apt_task_msg_get(task);
-                               msg->type = TASK_MSG_USER;
-                               request = (mpf_message_t*) msg->data;
-
-                               request->message_type = MPF_MESSAGE_TYPE_REQUEST;
-                               request->command_id = MPF_COMMAND_SUBTRACT;
-                               request->context = session->context;
-                               request->termination = session->termination1;
-
-                               consumer_task = apt_task_object_get(task);
-                               suite_engine = apt_task_object_get(consumer_task);
-                               apt_task_msg_signal(suite_engine->engine_task,msg);
+                       if(session->termination1 == mpf_message->termination) {
+                               session->termination1 = NULL;
                        }
-                       if(session->termination2) {
-                               apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [2]");
-                               msg = apt_task_msg_get(task);
-                               msg->type = TASK_MSG_USER;
-                               request = (mpf_message_t*) msg->data;
-
-                               request->message_type = MPF_MESSAGE_TYPE_REQUEST;
-                               request->command_id = MPF_COMMAND_SUBTRACT;
-                               request->context = session->context;
-                               request->termination = session->termination2;
-
-                               consumer_task = apt_task_object_get(task);
-                               suite_engine = apt_task_object_get(consumer_task);
-                               apt_task_msg_signal(suite_engine->engine_task,msg);
+                       if(session->termination2 == mpf_message->termination) {
+                               session->termination2 = NULL;
                        }
+                       mpf_termination_destroy(mpf_message->termination);
+
+                       if(!session->termination1 && !session->termination2) {
+                               mpf_engine_context_destroy(session->context);
+                               session->context = NULL;
+                               apr_pool_destroy(session->pool);
+
+                               apr_thread_mutex_lock(suite_engine->wait_object_mutex);
+                               apr_thread_cond_signal(suite_engine->wait_object);
+                               apr_thread_mutex_unlock(suite_engine->wait_object_mutex);
+                       }
+               }
+       }
+       return mpf_engine_message_send(suite_engine->engine,&task_msg);
+}
+
+/** Process MPF event  */
+static apt_bool_t mpf_suite_event_process(mpf_suite_engine_t *suite_engine, const mpf_message_t *mpf_message)
+{
+       mpf_task_msg_t *task_msg = NULL;
+       mpf_suite_session_t *session;
+       apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
+       if(mpf_message->termination) {
+               session = mpf_termination_object_get(mpf_message->termination);
+               if(session->termination1) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [1]");
+                       mpf_engine_termination_message_add(
+                               suite_engine->engine,
+                               MPF_SUBTRACT_TERMINATION,session->context,session->termination1,NULL,
+                               &task_msg);
+               }
+               if(session->termination2) {
+                       apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Subtract Termination [2]");
+                       mpf_engine_termination_message_add(
+                               suite_engine->engine,
+                               MPF_SUBTRACT_TERMINATION,session->context,session->termination2,NULL,
+                               &task_msg);
                }
        }
+       return mpf_engine_message_send(suite_engine->engine,&task_msg);
+}
 
+/** Process task messages */
+static apt_bool_t mpf_suite_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
+{
+       apr_size_t i;
+       const mpf_message_t *mpf_message;
+       apt_task_t *consumer_task = apt_task_object_get(task);
+       mpf_suite_engine_t *suite_engine = apt_task_object_get(consumer_task);
+       const mpf_message_container_t *container = (const mpf_message_container_t*) msg->data;
+       for(i=0; i<container->count; i++) {
+               mpf_message = &container->messages[i];
+               if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
+                       mpf_suite_response_process(suite_engine,mpf_message);
+               }
+               else {
+                       mpf_suite_event_process(suite_engine,mpf_message);
+               }
+       }
        return TRUE;
 }
 
 /** Create sample file reader descriptor */
 static mpf_audio_file_descriptor_t* mpf_file_reader_descriptor_create(mpf_suite_session_t *session)
 {
-       mpf_codec_descriptor_t *codec_descriptor;
        mpf_audio_file_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_audio_file_descriptor_t));
        descriptor->mask = FILE_READER;
        descriptor->read_handle = fopen("demo.pcm","rb");
        descriptor->write_handle = NULL;
-
-       codec_descriptor = &descriptor->codec_descriptor;
-       codec_descriptor->payload_type = 96;
-       apt_string_set(&codec_descriptor->name,"LPCM");
-       codec_descriptor->sampling_rate = 8000;
-       codec_descriptor->channel_count = 1;
+       descriptor->codec_descriptor = mpf_codec_lpcm_descriptor_create(8000,1,session->pool);
        return descriptor;
 }
 
 /** Create sample file writer descriptor */
 static mpf_audio_file_descriptor_t* mpf_file_writer_descriptor_create(mpf_suite_session_t *session)
 {
-       mpf_codec_descriptor_t *codec_descriptor;
        mpf_audio_file_descriptor_t *descriptor = apr_palloc(session->pool,sizeof(mpf_audio_file_descriptor_t));
        descriptor->mask = FILE_WRITER;
        descriptor->max_write_size = 500000; /* 500Kb */
        descriptor->write_handle = fopen("demo_out.pcm","wb");
        descriptor->read_handle = NULL;
-
-       codec_descriptor = &descriptor->codec_descriptor;
-       codec_descriptor->payload_type = 96;
-       apt_string_set(&codec_descriptor->name,"LPCM");
-       codec_descriptor->sampling_rate = 8000;
-       codec_descriptor->channel_count = 1;
+       descriptor->codec_descriptor = mpf_codec_lpcm_descriptor_create(8000,1,session->pool);
        return descriptor;
 }
 
@@ -380,9 +343,9 @@ static mpf_rtp_stream_descriptor_t* mpf_rtp_local_descriptor_create(mpf_suite_se
        mpf_rtp_stream_descriptor_init(descriptor);
        descriptor->local = apr_palloc(session->pool,sizeof(mpf_rtp_media_descriptor_t));
        mpf_rtp_media_descriptor_init(descriptor->local);
-       descriptor->local->mode = STREAM_MODE_NONE;
-       apt_string_set(&descriptor->local->base.ip,"127.0.0.1");
-       descriptor->local->base.port = 5000;
+       descriptor->local->direction = STREAM_DIRECTION_NONE;
+       apt_string_set(&descriptor->local->ip,"127.0.0.1");
+       descriptor->local->port = 5000;
        return descriptor;
 }
 
@@ -395,9 +358,9 @@ static mpf_rtp_stream_descriptor_t* mpf_rtp_remote_descriptor_create(mpf_suite_s
        mpf_rtp_stream_descriptor_init(descriptor);
        descriptor->remote = apr_palloc(session->pool,sizeof(mpf_rtp_media_descriptor_t));
        mpf_rtp_media_descriptor_init(descriptor->remote);
-       descriptor->remote->mode = STREAM_MODE_SEND_RECEIVE;
-       apt_string_set(&descriptor->remote->base.ip,"127.0.0.1");
-       descriptor->remote->base.port = 5002;
+       descriptor->remote->direction = STREAM_DIRECTION_DUPLEX;
+       apt_string_set(&descriptor->remote->ip,"127.0.0.1");
+       descriptor->remote->port = 5002;
        codec_list = &descriptor->remote->codec_list;
        mpf_codec_list_init(codec_list,2,session->pool);
        codec_descriptor = mpf_codec_list_add(codec_list);
index 69168a11b9dc35d77198ec781b6bdc59edbc3214..1af3fc579d110235aa0ed18ac6c19e5bb56b788c 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="windows-1251"?>
 <VisualStudioProject
        ProjectType="Visual C++"
-       Version="8,00"
+       Version="8.00"
        Name="mrcptest"
        ProjectGUID="{3CA97077-6210-4362-998A-D15A35EEAA08}"
        RootNamespace="mrcptest"
index 11aeb9769529a7b8e0849f07b762c06ed0292254..2c94303e27db08bf2fa7f63fd98f9783caacf113 100644 (file)
@@ -18,7 +18,8 @@
 #include <apr_file_io.h>
 #include "apt_test_suite.h"
 #include "apt_log.h"
-#include "mrcp_default_factory.h"
+#include "mrcp_resource_loader.h"
+#include "mrcp_resource_factory.h"
 #include "mrcp_message.h"
 #include "mrcp_stream.h"
 
@@ -173,7 +174,15 @@ static apt_bool_t test_dir_process(apt_test_suite_t *suite, mrcp_resource_factor
 
 static apt_bool_t parse_gen_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
 {
-       mrcp_resource_factory_t *factory = mrcp_default_factory_create(suite->pool);
+       mrcp_resource_factory_t *factory;
+       mrcp_resource_loader_t *resource_loader;
+       resource_loader = mrcp_resource_loader_create(TRUE,suite->pool);
+       if(!resource_loader) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Loader");
+               return FALSE;
+       }
+       
+       factory = mrcp_resource_factory_get(resource_loader);
        if(!factory) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Factory");
                return FALSE;
index 830cba3fde529bcf8bb64bf7b82fa59f89be4606..19a72f42c5ae97d9714a31f4f4b6b88612c36c07 100644 (file)
@@ -17,7 +17,8 @@
 #include "apt_test_suite.h"
 #include "apt_log.h"
 /* common includes */
-#include "mrcp_default_factory.h"
+#include "mrcp_resource_loader.h"
+#include "mrcp_resource_factory.h"
 #include "mrcp_message.h"
 #include "mrcp_generic_header.h"
 /* synthesizer includes */
 static mrcp_message_t* speak_request_create(mrcp_resource_factory_t *factory, apr_pool_t *pool)
 {
        mrcp_message_t *message;
+       mrcp_resource_t *resource = mrcp_resource_get(factory,MRCP_SYNTHESIZER_RESOURCE);
+       if(!resource) {
+               return NULL;
+       }
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create SPEAK Request");
-       message = mrcp_request_create(MRCP_SYNTHESIZER_RESOURCE,SYNTHESIZER_SPEAK,pool);
-       mrcp_message_resourcify_by_id(factory,message);
+       message = mrcp_request_create(resource,MRCP_VERSION_2,SYNTHESIZER_SPEAK,pool);
        if(message) {
                mrcp_generic_header_t *generic_header;
                mrcp_synth_header_t *synth_header;
@@ -156,9 +160,12 @@ static mrcp_message_t* speak_event_create(mrcp_resource_factory_t *factory, cons
 static mrcp_message_t* get_params_request_create(mrcp_resource_factory_t *factory, apr_pool_t *pool)
 {
        mrcp_message_t *message;
+       mrcp_resource_t *resource = mrcp_resource_get(factory,MRCP_SYNTHESIZER_RESOURCE);
+       if(!resource) {
+               return NULL;
+       }
        apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create GET-PARAMS Request");
-       message = mrcp_request_create(MRCP_SYNTHESIZER_RESOURCE,SYNTHESIZER_GET_PARAMS,pool);
-       mrcp_message_resourcify_by_id(factory,message);
+       message = mrcp_request_create(resource,MRCP_VERSION_2,SYNTHESIZER_GET_PARAMS,pool);
        if(message) {
                apt_str_t param_name;
                apt_str_t param_value;
@@ -289,7 +296,15 @@ static apt_bool_t get_params_test_run(apt_test_suite_t *suite, mrcp_resource_fac
 
 static apt_bool_t set_get_test_run(apt_test_suite_t *suite, int argc, const char * const *argv)
 {
-       mrcp_resource_factory_t *factory = mrcp_default_factory_create(suite->pool);
+       mrcp_resource_factory_t *factory;
+       mrcp_resource_loader_t *resource_loader;
+       resource_loader = mrcp_resource_loader_create(TRUE,suite->pool);
+       if(!resource_loader) {
+               apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Loader");
+               return FALSE;
+       }
+       
+       factory = mrcp_resource_factory_get(resource_loader);
        if(!factory) {
                apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Resource Factory");
                return FALSE;
index e547b9b1f1d998c512d4b8344f06d36430a1dd3f..971243ade24815f25968c1ed022c146fb6fb935d 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <stdio.h>
+#include <ctype.h>
 #include "apt_pool.h"
 #include "apt_string_table.h"
 #include "apt_text_stream.h"
index 421ed1692977db8cae2c1f8c7d02f424a1db508b..84eb159db6b591fec964403946df285295bf8dde 100644 (file)
@@ -27,27 +27,27 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcp", "libs\mrcp\mrcp.vcpr
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsignaling", "libs\mrcp-signaling\mrcpsignaling.vcproj", "{12A49562-BAB9-43A3-A21D-15B60BBB4C31}"
        ProjectSection(ProjectDependencies) = postProject
-               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
                {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpserver", "libs\mrcp-server\mrcpserver.vcproj", "{18B1F35A-10F8-4287-9B37-2D10501B0B38}"
        ProjectSection(ProjectDependencies) = postProject
-               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
                {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libunimrcpserver", "platforms\libunimrcp-server\libunimrcpserver.vcproj", "{C98AF157-352E-4737-BD30-A24E2647F5AE}"
        ProjectSection(ProjectDependencies) = postProject
-               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
-               {18B1F35A-10F8-4287-9B37-2D10501B0B38} = {18B1F35A-10F8-4287-9B37-2D10501B0B38}
                {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
+               {18B1F35A-10F8-4287-9B37-2D10501B0B38} = {18B1F35A-10F8-4287-9B37-2D10501B0B38}
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpsofiasip", "modules\mrcp-sofiasip\mrcpsofiasip.vcproj", "{746F3632-5BB2-4570-9453-31D6D58A7D8E}"
        ProjectSection(ProjectDependencies) = postProject
-               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
                {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA} = {A9EDAC04-6A5F-4BA7-BC0D-CCE7B255B6EA}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\mrcp-client\mrcpclient.vcproj", "{72782932-37CC-46AE-8C7F-9A7B1A6EE108}"
@@ -57,9 +57,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpclient", "libs\mrcp-cli
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libunimrcpclient", "platforms\libunimrcp-client\libunimrcpclient.vcproj", "{EE157390-1E85-416C-946E-620E32C9AD33}"
        ProjectSection(ProjectDependencies) = postProject
-               {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {72782932-37CC-46AE-8C7F-9A7B1A6EE108}
-               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
                {DEB01ACB-D65F-4A62-AED9-58C1054499E9} = {DEB01ACB-D65F-4A62-AED9-58C1054499E9}
+               {746F3632-5BB2-4570-9453-31D6D58A7D8E} = {746F3632-5BB2-4570-9453-31D6D58A7D8E}
+               {72782932-37CC-46AE-8C7F-9A7B1A6EE108} = {72782932-37CC-46AE-8C7F-9A7B1A6EE108}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unimrcpclient", "platforms\unimrcp-client\unimrcpclient.vcproj", "{57FAF32E-49FD-491F-895D-132D0D5EFE0A}"
@@ -74,8 +74,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpv2transport", "libs\mrc
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpengine", "libs\mrcp-engine\mrcpengine.vcproj", "{843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}"
        ProjectSection(ProjectDependencies) = postProject
-               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
                {B5A00BFA-6083-4FAE-A097-71642D6473B5} = {B5A00BFA-6083-4FAE-A097-71642D6473B5}
+               {1C320193-46A6-4B34-9C56-8AB584FC1B56} = {1C320193-46A6-4B34-9C56-8AB584FC1B56}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demosynth", "plugins\demo-synth\demosynth.vcproj", "{92BFA534-C419-4EB2-AAA3-510653F38F08}"
@@ -127,8 +127,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtsptest", "tests\rtsptest\
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpunirtsp", "modules\mrcp-unirtsp\mrcpunirtsp.vcproj", "{DEB01ACB-D65F-4A62-AED9-58C1054499E9}"
        ProjectSection(ProjectDependencies) = postProject
-               {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
                {12A49562-BAB9-43A3-A21D-15B60BBB4C31} = {12A49562-BAB9-43A3-A21D-15B60BBB4C31}
+               {504B3154-7A4F-459D-9877-B951021C3F1F} = {504B3154-7A4F-459D-9877-B951021C3F1F}
        EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prepare", "build\tools\prepare.vcproj", "{01D63BF5-7798-4746-852A-4B45229BB735}"
@@ -150,6 +150,26 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcpflite", "plugins\mrcp-f
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "preparesphinx", "build\tools\preparesphinx.vcproj", "{71D62A04-8EF6-4C6B-AC12-0C15A875E53A}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asrclient", "platforms\asr-client\asrclient.vcproj", "{6B83AC6D-01CE-4E1C-81CE-02AD8116C684}"
+       ProjectSection(ProjectDependencies) = postProject
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3} = {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libasrclient", "platforms\libasr-client\libasrclient.vcproj", "{272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}"
+       ProjectSection(ProjectDependencies) = postProject
+               {EE157390-1E85-416C-946E-620E32C9AD33} = {EE157390-1E85-416C-946E-620E32C9AD33}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "umc", "platforms\umc\umc.vcproj", "{CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}"
+       ProjectSection(ProjectDependencies) = postProject
+               {EE157390-1E85-416C-946E-620E32C9AD33} = {EE157390-1E85-416C-946E-620E32C9AD33}
+       EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mrcprecorder", "plugins\mrcp-recorder\mrcprecorder.vcproj", "{5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}"
+       ProjectSection(ProjectDependencies) = postProject
+               {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C} = {843425BE-9A9A-44F4-A4E3-4B57D6ABD53C}
+       EndProjectSection
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Win32 = Debug|Win32
@@ -256,6 +276,22 @@ Global
                {56F6FB96-2BC7-4CAE-A8BF-6A0FAEC90556}.Release|Win32.ActiveCfg = Release|Win32
                {71D62A04-8EF6-4C6B-AC12-0C15A875E53A}.Debug|Win32.ActiveCfg = Debug|Win32
                {71D62A04-8EF6-4C6B-AC12-0C15A875E53A}.Release|Win32.ActiveCfg = Release|Win32
+               {6B83AC6D-01CE-4E1C-81CE-02AD8116C684}.Debug|Win32.ActiveCfg = Debug|Win32
+               {6B83AC6D-01CE-4E1C-81CE-02AD8116C684}.Debug|Win32.Build.0 = Debug|Win32
+               {6B83AC6D-01CE-4E1C-81CE-02AD8116C684}.Release|Win32.ActiveCfg = Release|Win32
+               {6B83AC6D-01CE-4E1C-81CE-02AD8116C684}.Release|Win32.Build.0 = Release|Win32
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}.Debug|Win32.ActiveCfg = Debug|Win32
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}.Debug|Win32.Build.0 = Debug|Win32
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}.Release|Win32.ActiveCfg = Release|Win32
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3}.Release|Win32.Build.0 = Release|Win32
+               {CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}.Debug|Win32.ActiveCfg = Debug|Win32
+               {CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}.Debug|Win32.Build.0 = Debug|Win32
+               {CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}.Release|Win32.ActiveCfg = Release|Win32
+               {CD1C52C1-D8E1-4654-AE65-6CCAB38DE894}.Release|Win32.Build.0 = Release|Win32
+               {5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}.Debug|Win32.ActiveCfg = Debug|Win32
+               {5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}.Debug|Win32.Build.0 = Debug|Win32
+               {5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}.Release|Win32.ActiveCfg = Release|Win32
+               {5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2}.Release|Win32.Build.0 = Release|Win32
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -276,11 +312,15 @@ Global
                {C98AF157-352E-4737-BD30-A24E2647F5AE} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
                {EE157390-1E85-416C-946E-620E32C9AD33} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
                {57FAF32E-49FD-491F-895D-132D0D5EFE0A} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {6B83AC6D-01CE-4E1C-81CE-02AD8116C684} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {272FAFA8-2B2F-4716-B95F-3B37CF2E0CB3} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
+               {CD1C52C1-D8E1-4654-AE65-6CCAB38DE894} = {8E282AE2-038C-49FE-AC67-BC9615AFD800}
                {92BFA534-C419-4EB2-AAA3-510653F38F08} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
                {B495B6D9-AF84-479D-B30A-313C16EF8BFD} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
                {729EF28E-38C9-40DE-A138-87785F021411} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
                {3C614AE8-B611-4D43-A9AF-1CAA440A9F69} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
                {56F6FB96-2BC7-4CAE-A8BF-6A0FAEC90556} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
+               {5AFB8B04-AEB9-408C-B53E-AFBC44B5F3F2} = {09BABD45-8F30-4F99-B8B8-8DD78F6804DB}
                {79EF9F1D-E211-4ED1-91D2-FC935AB3A872} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
                {429C907B-97D1-4B2D-9B0E-A14A5BFDAD15} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}
                {DCF01B1C-5268-44F3-9130-D647FABFB663} = {AC4356E8-48A1-4D2D-AFB1-11CF30B974CD}