mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-07-15 19:40:06 +00:00
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:
parent
6bd0cb0b1d
commit
89ca44ed3e
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -25,7 +25,7 @@
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="xcopy "$(AprDir)\$(ConfigurationName)\libapr-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\pthread\pthreadVC2.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if not exist "$(SolutionDir)$(ConfigurationName)\conf" xcopy "$(SolutionDir)conf\*.xml" "$(SolutionDir)$(ConfigurationName)\conf\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\data" xcopy "$(SolutionDir)data\*" "$(SolutionDir)$(ConfigurationName)\data\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\log" mkdir "$(SolutionDir)$(ConfigurationName)\log\"
"
|
||||
CommandLine="xcopy "$(AprDir)\$(ConfigurationName)\libapr-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if exist "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" (
 xcopy "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
 if exist "$(AprIconvDir)\$(ConfigurationName)\iconv" (
 if not exist "$(SolutionDir)$(ConfigurationName)\bin\iconv" mkdir "$(SolutionDir)$(ConfigurationName)\bin\iconv"
 xcopy "$(AprIconvDir)\$(ConfigurationName)\iconv\*.so" "$(SolutionDir)$(ConfigurationName)\bin\iconv\" /Y
 )
)

xcopy "$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\pthread\pthreadVC2.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if not exist "$(SolutionDir)$(ConfigurationName)\conf" xcopy "$(SolutionDir)conf\*.xml" "$(SolutionDir)$(ConfigurationName)\conf\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\data" xcopy "$(SolutionDir)data\*" "$(SolutionDir)$(ConfigurationName)\data\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\log" mkdir "$(SolutionDir)$(ConfigurationName)\log\"
"
|
||||
ExcludedFromBuild="false"
|
||||
/>
|
||||
<Tool
|
||||
@ -47,7 +47,7 @@
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="xcopy "$(AprDir)\$(ConfigurationName)\libapr-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\pthread\pthreadVC2.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if not exist "$(SolutionDir)$(ConfigurationName)\conf" xcopy "$(SolutionDir)conf\*.xml" "$(SolutionDir)$(ConfigurationName)\conf\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\data" xcopy "$(SolutionDir)data\*" "$(SolutionDir)$(ConfigurationName)\data\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\log" mkdir "$(SolutionDir)$(ConfigurationName)\log\"
"
|
||||
CommandLine="xcopy "$(AprDir)\$(ConfigurationName)\libapr-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(AprUtilDir)\$(ConfigurationName)\libaprutil-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if exist "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" (
 xcopy "$(AprIconvDir)\$(ConfigurationName)\libapriconv-1.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
 if exist "$(AprIconvDir)\$(ConfigurationName)\iconv" (
 if not exist "$(SolutionDir)$(ConfigurationName)\bin\iconv" mkdir "$(SolutionDir)$(ConfigurationName)\bin\iconv"
 xcopy "$(AprIconvDir)\$(ConfigurationName)\iconv\*.so" "$(SolutionDir)$(ConfigurationName)\bin\iconv\" /Y
 )
)

xcopy "$(SofiaDir)\win32\libsofia-sip-ua\$(ConfigurationName)\libsofia_sip_ua.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y
xcopy "$(SofiaDir)\win32\pthread\pthreadVC2.dll" "$(SolutionDir)$(ConfigurationName)\bin\" /Y

if not exist "$(SolutionDir)$(ConfigurationName)\conf" xcopy "$(SolutionDir)conf\*.xml" "$(SolutionDir)$(ConfigurationName)\conf\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\data" xcopy "$(SolutionDir)data\*" "$(SolutionDir)$(ConfigurationName)\data\" /Y
if not exist "$(SolutionDir)$(ConfigurationName)\log" mkdir "$(SolutionDir)$(ConfigurationName)\log\"
"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
96
libs/unimrcp/conf/umcscenarios.xml
Normal file
96
libs/unimrcp/conf/umcscenarios.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
BIN
libs/unimrcp/data/demo-16kHz.pcm
Normal file
BIN
libs/unimrcp/data/demo-16kHz.pcm
Normal file
Binary file not shown.
3
libs/unimrcp/data/grammar.jsgf
Normal file
3
libs/unimrcp/data/grammar.jsgf
Normal file
@ -0,0 +1,3 @@
|
||||
#JSGF V1.0;
|
||||
grammar digits;
|
||||
public <numbers> = (one | two | three);
|
BIN
libs/unimrcp/data/one-16kHz.pcm
Normal file
BIN
libs/unimrcp/data/one-16kHz.pcm
Normal file
Binary file not shown.
1
libs/unimrcp/data/speak.txt
Normal file
1
libs/unimrcp/data/speak.txt
Normal file
@ -0,0 +1 @@
|
||||
Hello World.
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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__*/
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
121
libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h
Normal file
121
libs/unimrcp/libs/mpf/include/mpf_dtmf_detector.h
Normal 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__*/
|
131
libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h
Normal file
131
libs/unimrcp/libs/mpf/include/mpf_dtmf_generator.h
Normal 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__*/
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
* @brief MPF File Termination Factory
|
||||
*/
|
||||
|
||||
#include "mpf_types.h"
|
||||
#include "mpf_termination_factory.h"
|
||||
|
||||
APT_BEGIN_EXTERN_C
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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__*/
|
@ -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__*/
|
||||
|
47
libs/unimrcp/libs/mpf/include/mpf_mixer.h
Normal file
47
libs/unimrcp/libs/mpf/include/mpf_mixer.h
Normal 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__*/
|
47
libs/unimrcp/libs/mpf/include/mpf_multiplier.h
Normal file
47
libs/unimrcp/libs/mpf/include/mpf_multiplier.h
Normal 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__*/
|
71
libs/unimrcp/libs/mpf/include/mpf_named_event.h
Normal file
71
libs/unimrcp/libs/mpf/include/mpf_named_event.h
Normal 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__*/
|
@ -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
|
||||
|
||||
|
@ -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__*/
|
200
libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h
Normal file
200
libs/unimrcp/libs/mpf/include/mpf_rtcp_packet.h
Normal 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__*/
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
44
libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h
Normal file
44
libs/unimrcp/libs/mpf/include/mpf_rtp_pt.h
Normal 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__*/
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
61
libs/unimrcp/libs/mpf/include/mpf_scheduler.h
Normal file
61
libs/unimrcp/libs/mpf/include/mpf_scheduler.h
Normal 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__*/
|
@ -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__*/
|
||||
|
88
libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h
Normal file
88
libs/unimrcp/libs/mpf/include/mpf_stream_descriptor.h
Normal 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__*/
|
@ -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__*/
|
@ -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
|
||||
|
||||
|
88
libs/unimrcp/libs/mpf/include/mpf_termination_factory.h
Normal file
88
libs/unimrcp/libs/mpf/include/mpf_termination_factory.h
Normal 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__*/
|
53
libs/unimrcp/libs/mpf/include/mpf_timer_manager.h
Normal file
53
libs/unimrcp/libs/mpf/include/mpf_timer_manager.h
Normal 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__*/
|
@ -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
|
||||
|
||||
|
@ -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__*/
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
299
libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c
Normal file
299
libs/unimrcp/libs/mpf/src/mpf_dtmf_detector.c
Normal 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;
|
||||
}
|
347
libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c
Normal file
347
libs/unimrcp/libs/mpf/src/mpf_dtmf_generator.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
205
libs/unimrcp/libs/mpf/src/mpf_mixer.c
Normal file
205
libs/unimrcp/libs/mpf/src/mpf_mixer.c
Normal 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;
|
||||
}
|
182
libs/unimrcp/libs/mpf/src/mpf_multiplier.c
Normal file
182
libs/unimrcp/libs/mpf/src/mpf_multiplier.c
Normal 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;
|
||||
}
|
74
libs/unimrcp/libs/mpf/src/mpf_named_event.c
Normal file
74
libs/unimrcp/libs/mpf/src/mpf_named_event.c
Normal 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 */
|
||||
}
|
26
libs/unimrcp/libs/mpf/src/mpf_resampler.c
Normal file
26
libs/unimrcp/libs/mpf/src/mpf_resampler.c
Normal 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;
|
||||
}
|
@ -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
@ -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)
|
||||
|
250
libs/unimrcp/libs/mpf/src/mpf_scheduler.c
Normal file
250
libs/unimrcp/libs/mpf/src/mpf_scheduler.c
Normal 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
|
158
libs/unimrcp/libs/mpf/src/mpf_stream.c
Normal file
158
libs/unimrcp/libs/mpf/src/mpf_stream.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
66
libs/unimrcp/libs/mpf/src/mpf_termination_factory.c
Normal file
66
libs/unimrcp/libs/mpf/src/mpf_termination_factory.c
Normal 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
Loading…
x
Reference in New Issue
Block a user