merge upstream changes to svn r2096

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
This commit is contained in:
Michael Jerris 2009-11-20 22:00:51 +00:00
parent 6bd0cb0b1d
commit 89ca44ed3e
245 changed files with 18406 additions and 4543 deletions

View 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>
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>

View 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
data - data files
log - log files
plugin - run-time loadable modules

View 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

View 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"

View 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.

View 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>

View File

@ -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>

View 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 -->
@ -50,7 +57,21 @@
<!-- <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>

View 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 -->
@ -46,8 +53,22 @@
<!-- <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>

View 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

Binary file not shown.

View File

@ -0,0 +1,3 @@
#JSGF V1.0;
grammar digits;
public <numbers> = (one | two | three);

Binary file not shown.

View File

@ -0,0 +1 @@
Hello World.

View 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 */

View 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.

View 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__*/

View 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);

View 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

View 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

View 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.

View 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) {

View 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) {

View 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);
}

View 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) {

View 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) {

View 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;
}

View 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

View 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) {

View 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

View 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);

View File

@ -23,31 +23,30 @@
*/
#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

View 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

View 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;
}

View 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 list declaration */
typedef struct mpf_codec_list_t mpf_codec_list_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 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 descriptor */
@ -65,17 +70,37 @@ 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;
/** 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 */
struct mpf_codec_attribs_t {
/** Codec name */
apt_str_t name;
/** Bits per sample */
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 */
@ -86,16 +111,6 @@ struct mpf_codec_frame_t {
apr_size_t size;
};
/** Codec attributes */
struct mpf_codec_attribs_t {
/** Codec name */
apt_str_t name;
/** Bits per sample */
apr_byte_t bits_per_samples;
/** Supported sampling rates (mpf_sample_rates_e) */
int sample_rates;
};
/** 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_t* descriptor = (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

View 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);

View File

@ -22,31 +22,52 @@
* @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);
/** 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;
/**
* Destroy factory of media contexts.
*/
MPF_DECLARE(void) mpf_context_factory_destroy(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;
};
/**
* Process factory of media contexts.
*/
MPF_DECLARE(apt_bool_t) mpf_context_factory_process(mpf_context_factory_t *factory);
/**
* 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.
@ -63,22 +84,42 @@ 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);
/**
* Apply topology.
* @param context the context which holds the termination
* @param termination the termination to apply toplogy for
* 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_topology_apply(mpf_context_t *context, mpf_termination_t *termination);
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 to apply topology for
*/
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);

View 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

View File

@ -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__*/

View File

@ -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__*/

View 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

View File

@ -27,11 +27,15 @@
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

View File

@ -22,7 +22,7 @@
* @brief MPF File Termination Factory
*/
#include "mpf_types.h"
#include "mpf_termination_factory.h"
APT_BEGIN_EXTERN_C

View 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 */

View 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);

View File

@ -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__*/

View 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__*/

View File

@ -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__*/

View File

@ -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__*/

View File

@ -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__*/

View File

@ -23,29 +23,51 @@
*/
#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

View File

@ -14,31 +14,27 @@
* 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__*/

View File

@ -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__*/

View 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

View 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

View 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;
}

View 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 */

View File

@ -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__*/

View File

@ -19,60 +19,90 @@
/**
* @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(tx_stat,0,sizeof(rtp_tx_stat_t));
memset(sr_stat,0,sizeof(rtcp_sr_stat_t));
}
/** Reset RTP receive statistics */
/** Reset RTCP RR statistics */
static APR_INLINE void mpf_rtcp_rr_stat_reset(rtcp_rr_stat_t *rr_stat)
{
memset(rr_stat,0,sizeof(rtcp_rr_stat_t));
}
/** 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));

View 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

View 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

View File

@ -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__*/

View File

@ -23,13 +23,14 @@
*/
#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__*/

View File

@ -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__*/

View File

@ -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__*/

View 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
@ -80,6 +90,13 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
mpf_video_stream_t *video_stream,
apr_pool_t *pool);
/**
* Add MPF termination.
* @param termination the termination to add
* @param descriptor the termination specific descriptor
*/
MPF_DECLARE(apt_bool_t) mpf_termination_add(mpf_termination_t *termination, void *descriptor);
/**
* Modify MPF termination.
* @param termination the termination to modify
@ -88,47 +105,11 @@ MPF_DECLARE(mpf_termination_t*) mpf_termination_base_create(
MPF_DECLARE(apt_bool_t) mpf_termination_modify(mpf_termination_t *termination, void *descriptor);
/**
* Validate MPF termination.
* @param termination the termination to validate
* Subtract MPF termination.
* @param termination the termination to subtract
*/
MPF_DECLARE(apt_bool_t) mpf_termination_validate(mpf_termination_t *termination);
MPF_DECLARE(apt_bool_t) mpf_termination_subtract(mpf_termination_t *termination);
/**
* 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);
/**
* 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
*/
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);
APT_END_EXTERN_C

View File

@ -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__*/

View File

@ -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__*/

View 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

View File

@ -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__*/

View File

@ -191,6 +191,14 @@
RelativePath=".\include\mpf_decoder.h"
>
</File>
<File
RelativePath=".\include\mpf_dtmf_detector.h"
>
</File>
<File
RelativePath=".\include\mpf_dtmf_generator.h"
>
</File>
<File
RelativePath=".\include\mpf_encoder.h"
>
@ -215,18 +223,34 @@
RelativePath=".\include\mpf_jitter_buffer.h"
>
</File>
<File
RelativePath=".\include\mpf_media_descriptor.h"
>
</File>
<File
RelativePath=".\include\mpf_message.h"
>
</File>
<File
RelativePath=".\include\mpf_mixer.h"
>
</File>
<File
RelativePath=".\include\mpf_multiplier.h"
>
</File>
<File
RelativePath=".\include\mpf_named_event.h"
>
</File>
<File
RelativePath=".\include\mpf_object.h"
>
</File>
<File
RelativePath=".\include\mpf_resampler.h"
>
</File>
<File
RelativePath=".\include\mpf_rtcp_packet.h"
>
</File>
<File
RelativePath=".\include\mpf_rtp_attribs.h"
>
@ -243,6 +267,10 @@
RelativePath=".\include\mpf_rtp_header.h"
>
</File>
<File
RelativePath=".\include\mpf_rtp_pt.h"
>
</File>
<File
RelativePath=".\include\mpf_rtp_stat.h"
>
@ -255,12 +283,16 @@
RelativePath=".\include\mpf_rtp_termination_factory.h"
>
</File>
<File
RelativePath=".\include\mpf_scheduler.h"
>
</File>
<File
RelativePath=".\include\mpf_stream.h"
>
</File>
<File
RelativePath=".\include\mpf_stream_mode.h"
RelativePath=".\include\mpf_stream_descriptor.h"
>
</File>
<File
@ -268,17 +300,17 @@
>
</File>
<File
RelativePath=".\include\mpf_timer.h"
RelativePath=".\include\mpf_termination_factory.h"
>
</File>
<File
RelativePath=".\include\mpf_timer_manager.h"
>
</File>
<File
RelativePath=".\include\mpf_types.h"
>
</File>
<File
RelativePath=".\include\mpf_user.h"
>
</File>
</Filter>
<Filter
Name="src"
@ -324,6 +356,14 @@
RelativePath=".\src\mpf_decoder.c"
>
</File>
<File
RelativePath=".\src\mpf_dtmf_detector.c"
>
</File>
<File
RelativePath=".\src\mpf_dtmf_generator.c"
>
</File>
<File
RelativePath=".\src\mpf_encoder.c"
>
@ -344,6 +384,22 @@
RelativePath=".\src\mpf_jitter_buffer.c"
>
</File>
<File
RelativePath=".\src\mpf_mixer.c"
>
</File>
<File
RelativePath=".\src\mpf_multiplier.c"
>
</File>
<File
RelativePath=".\src\mpf_named_event.c"
>
</File>
<File
RelativePath=".\src\mpf_resampler.c"
>
</File>
<File
RelativePath=".\src\mpf_rtp_attribs.c"
>
@ -356,12 +412,24 @@
RelativePath=".\src\mpf_rtp_termination_factory.c"
>
</File>
<File
RelativePath=".\src\mpf_scheduler.c"
>
</File>
<File
RelativePath=".\src\mpf_stream.c"
>
</File>
<File
RelativePath=".\src\mpf_termination.c"
>
</File>
<File
RelativePath=".\src\mpf_timer.c"
RelativePath=".\src\mpf_termination_factory.c"
>
</File>
<File
RelativePath=".\src\mpf_timer_manager.c"
>
</File>
</Filter>

View 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);

View 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;
}

View File

@ -15,98 +15,199 @@
*/
#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 = source->rx_codec;
frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
codec = mpf_codec_manager_codec_get(codec_manager,source->rx_descriptor,pool);
if(!codec) {
return NULL;
}
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);
}

View File

@ -15,12 +15,84 @@
*/
#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;
}
/** 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)
/** 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)
{
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 */
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;
continue;
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;
}
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;
}
else {
if(apt_string_compare(&attribs->name,&descriptor->name) == TRUE) {
if(mpf_sampling_rate_check(descriptor->sampling_rate,attribs->sample_rates) == TRUE) {
match = TRUE;
}
}
}
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;
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_lists_intersect(mpf_codec_list_t *codec_list1, mpf_codec_list_t *codec_list2)
{
int i;
mpf_codec_descriptor_t *descriptor1;
mpf_codec_descriptor_t *descriptor2;
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 = &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;
}
/* 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(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;

View 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
};

View File

@ -17,10 +17,7 @@
#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);

View File

@ -16,25 +16,28 @@
#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;
}
if(codec) {
descriptor = mpf_codec_list_add(codec_list);
descriptor->name = name;
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;
}

View File

@ -14,30 +14,126 @@
* 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_association_add(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2)
{
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;
}
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_association_remove(mpf_context_t *context, mpf_termination_t *termination1, mpf_termination_t *termination2)
{
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;
}
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 == 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_associations_reset(mpf_context_t *context)
{
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);
/* 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--;
}
item = &context->matrix[j][i];
if(item->on) {
item->on = 0;
header_item2->tx_count--;
header_item1->rx_count--;
}
}
}
return TRUE;
}
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);
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);
}
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;
}
MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context)
{
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);
}
return TRUE;
}
MPF_DECLARE(apt_bool_t) mpf_context_process(mpf_context_t *context)
{
int i;
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;
object = context->table[i][j];
if(object && object->process) {
object->process(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 TRUE;
}
MPF_DECLARE(apt_bool_t) mpf_context_topology_apply(mpf_context_t *context, mpf_termination_t *termination)
static mpf_object_t* mpf_context_bridge_create(mpf_context_t *context, apr_size_t i)
{
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 */
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;
}
i = termination->slot;
for(j=0; j<context->max_termination_count; j++) {
if(i == j) continue;
sink_termination = context->table[j][j];
object = mpf_context_connection_create(context,termination,sink_termination);
if(object) {
context->table[i][j] = object;
}
}
j = termination->slot;
for(i=0; i<context->max_termination_count; i++) {
if(i == j) continue;
source_termination = context->table[i][i];
object = mpf_context_connection_create(context,source_termination,termination);
if(object) {
context->table[i][j] = object;
}
}
return TRUE;
}
MPF_DECLARE(apt_bool_t) mpf_context_topology_destroy(mpf_context_t *context, mpf_termination_t *termination)
{
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;
}
i = termination->slot;
for(j=0; j<context->max_termination_count; j++) {
if(i == j) continue;
object = context->table[i][j];
if(object) {
if(object->destroy) {
object->destroy(object);
}
context->table[i][j] = NULL;
}
}
j = termination->slot;
for(i=0; i<context->max_termination_count; i++) {
if(i == j) continue;
object = context->table[i][j];
if(object) {
if(object->destroy) {
object->destroy(object);
}
context->table[i][j] = NULL;
}
}
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_object_t *object = NULL;
mpf_audio_stream_t *source;
mpf_audio_stream_t *sink;
if(!src_termination || !sink_termination) {
return NULL;
}
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 object;
return FALSE;
}

View 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);
decoder->source = source;
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;
codec = source->rx_codec;
frame_size = mpf_codec_frame_size_calculate(codec->descriptor,codec->attribs);
decoder->base->rx_codec = codec;
decoder->source = source;
decoder->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;

View File

@ -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;
}

View File

@ -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;
}

View 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;

View File

@ -15,13 +15,13 @@
*/
#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);
}
mpf_termination_validate(termination);
if(mpf_context_termination_add(context,termination) == FALSE) {
response->status_code = MPF_STATUS_CODE_FAILURE;
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_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);
}
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_MODIFY_TERMINATION:
{
mpf_termination_modify(termination,mpf_request->descriptor);
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_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_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_ADD_ASSOCIATION:
{
mpf_context_association_add(context,termination,mpf_request->assoc_termination);
break;
}
case MPF_REMOVE_ASSOCIATION:
{
mpf_context_association_remove(context,termination,mpf_request->assoc_termination);
break;
}
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);

View 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(

View 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;

View File

@ -16,30 +16,56 @@
#include "mpf_jitter_buffer.h"
struct mpf_jitter_buffer_t {
mpf_jb_config_t *config;
#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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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;
}

View 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:

File diff suppressed because it is too large Load Diff

View 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)

View File

@ -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

View File

@ -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);
}
}
}

View 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);
}

View File

@ -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;
}

Some files were not shown because too many files have changed in this diff Show More