2002-05-13 22:29:39 +00:00
|
|
|
/*
|
2005-09-14 20:46:50 +00:00
|
|
|
* Asterisk -- An open source telephony toolkit.
|
2002-05-13 22:29:39 +00:00
|
|
|
*
|
2007-02-22 23:12:26 +00:00
|
|
|
* Copyright (C) 1999 - 2007, Digium, Inc.
|
2002-05-13 22:29:39 +00:00
|
|
|
*
|
2004-09-07 01:22:57 +00:00
|
|
|
* Mark Spencer <markster@digium.com>
|
2002-05-13 22:29:39 +00:00
|
|
|
*
|
2007-02-22 23:12:26 +00:00
|
|
|
* SLA Implementation by:
|
|
|
|
* Russell Bryant <russell@digium.com>
|
|
|
|
*
|
2005-09-14 20:46:50 +00:00
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
2002-05-13 22:29:39 +00:00
|
|
|
* This program is free software, distributed under the terms of
|
2005-09-14 20:46:50 +00:00
|
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
|
|
* at the top of the source tree.
|
|
|
|
*/
|
|
|
|
|
2005-10-24 20:12:06 +00:00
|
|
|
/*! \file
|
2005-09-14 20:46:50 +00:00
|
|
|
*
|
2007-02-22 23:12:26 +00:00
|
|
|
* \brief Meet me conference bridge and Shared Line Appearances
|
2005-12-30 21:18:06 +00:00
|
|
|
*
|
|
|
|
* \author Mark Spencer <markster@digium.com>
|
2007-02-22 23:12:26 +00:00
|
|
|
* \author (SLA) Russell Bryant <russell@digium.com>
|
2017-12-22 14:23:22 +00:00
|
|
|
*
|
2005-11-06 15:09:47 +00:00
|
|
|
* \ingroup applications
|
2002-05-13 22:29:39 +00:00
|
|
|
*/
|
|
|
|
|
2012-10-14 21:45:16 +00:00
|
|
|
/*! \li \ref app_meetme.c uses configuration file \ref meetme.conf
|
2012-10-01 23:22:50 +00:00
|
|
|
* \addtogroup configuration_file Configuration Files
|
|
|
|
*/
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/*!
|
2012-10-01 23:22:50 +00:00
|
|
|
* \page meetme.conf meetme.conf
|
|
|
|
* \verbinclude meetme.conf.sample
|
|
|
|
*/
|
|
|
|
|
2006-04-24 17:11:45 +00:00
|
|
|
/*** MODULEINFO
|
2008-06-12 17:27:55 +00:00
|
|
|
<depend>dahdi</depend>
|
2011-07-14 20:28:54 +00:00
|
|
|
<defaultenabled>no</defaultenabled>
|
2021-08-11 11:15:16 +00:00
|
|
|
<support_level>deprecated</support_level>
|
2011-07-14 20:28:54 +00:00
|
|
|
<replacement>app_confbridge</replacement>
|
2021-08-11 11:15:16 +00:00
|
|
|
<deprecated_in>19</deprecated_in>
|
|
|
|
<removed_in>21</removed_in>
|
2006-04-24 17:11:45 +00:00
|
|
|
***/
|
|
|
|
|
2006-06-07 18:54:56 +00:00
|
|
|
#include "asterisk.h"
|
|
|
|
|
2008-06-25 23:05:28 +00:00
|
|
|
#include <dahdi/user.h>
|
2005-06-06 22:39:32 +00:00
|
|
|
|
2005-04-21 06:02:45 +00:00
|
|
|
#include "asterisk/lock.h"
|
|
|
|
#include "asterisk/file.h"
|
|
|
|
#include "asterisk/channel.h"
|
|
|
|
#include "asterisk/pbx.h"
|
|
|
|
#include "asterisk/module.h"
|
|
|
|
#include "asterisk/config.h"
|
|
|
|
#include "asterisk/app.h"
|
|
|
|
#include "asterisk/dsp.h"
|
|
|
|
#include "asterisk/musiconhold.h"
|
|
|
|
#include "asterisk/manager.h"
|
|
|
|
#include "asterisk/cli.h"
|
|
|
|
#include "asterisk/say.h"
|
|
|
|
#include "asterisk/utils.h"
|
2005-12-20 13:07:02 +00:00
|
|
|
#include "asterisk/translate.h"
|
|
|
|
#include "asterisk/ulaw.h"
|
2008-11-12 18:32:46 +00:00
|
|
|
#include "asterisk/astobj2.h"
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
#include "asterisk/devicestate.h"
|
2007-02-10 00:40:57 +00:00
|
|
|
#include "asterisk/dial.h"
|
2007-03-08 20:56:57 +00:00
|
|
|
#include "asterisk/causes.h"
|
2007-11-20 23:29:33 +00:00
|
|
|
#include "asterisk/paths.h"
|
2010-07-08 14:48:42 +00:00
|
|
|
#include "asterisk/test.h"
|
2013-06-07 15:54:26 +00:00
|
|
|
#include "asterisk/stasis.h"
|
|
|
|
#include "asterisk/stasis_channels.h"
|
|
|
|
#include "asterisk/stasis_message_router.h"
|
|
|
|
#include "asterisk/json.h"
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
#include "asterisk/format_compatibility.h"
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2006-05-21 15:13:19 +00:00
|
|
|
#include "enter.h"
|
|
|
|
#include "leave.h"
|
|
|
|
|
2008-11-13 15:46:06 +00:00
|
|
|
/*** DOCUMENTATION
|
|
|
|
<application name="MeetMe" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
MeetMe conference bridge.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="confno">
|
|
|
|
<para>The conference number</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="options">
|
|
|
|
<optionlist>
|
|
|
|
<option name="a">
|
|
|
|
<para>Set admin mode.</para>
|
|
|
|
</option>
|
|
|
|
<option name="A">
|
|
|
|
<para>Set marked mode.</para>
|
|
|
|
</option>
|
|
|
|
<option name="b">
|
|
|
|
<para>Run AGI script specified in <variable>MEETME_AGI_BACKGROUND</variable>
|
|
|
|
Default: <literal>conf-background.agi</literal>.</para>
|
|
|
|
<note><para>This does not work with non-DAHDI channels in the same
|
|
|
|
conference).</para></note>
|
|
|
|
</option>
|
|
|
|
<option name="c">
|
|
|
|
<para>Announce user(s) count on joining a conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="C">
|
|
|
|
<para>Continue in dialplan when kicked out of conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="d">
|
|
|
|
<para>Dynamically add conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="D">
|
|
|
|
<para>Dynamically add conference, prompting for a PIN.</para>
|
|
|
|
</option>
|
|
|
|
<option name="e">
|
|
|
|
<para>Select an empty conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="E">
|
|
|
|
<para>Select an empty pinless conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="F">
|
|
|
|
<para>Pass DTMF through the conference.</para>
|
|
|
|
</option>
|
2009-12-10 17:31:23 +00:00
|
|
|
<option name="G">
|
|
|
|
<argument name="x" required="true">
|
|
|
|
<para>The file to playback</para>
|
|
|
|
</argument>
|
|
|
|
<para>Play an intro announcement in conference.</para>
|
|
|
|
</option>
|
2008-11-13 15:46:06 +00:00
|
|
|
<option name="i">
|
|
|
|
<para>Announce user join/leave with review.</para>
|
|
|
|
</option>
|
|
|
|
<option name="I">
|
|
|
|
<para>Announce user join/leave without review.</para>
|
|
|
|
</option>
|
2011-09-15 12:50:40 +00:00
|
|
|
<option name="k">
|
|
|
|
<para>Close the conference if there's only one active participant left at exit.</para>
|
|
|
|
</option>
|
2008-11-13 15:46:06 +00:00
|
|
|
<option name="l">
|
|
|
|
<para>Set listen only mode (Listen only, no talking).</para>
|
|
|
|
</option>
|
|
|
|
<option name="m">
|
|
|
|
<para>Set initially muted.</para>
|
|
|
|
</option>
|
|
|
|
<option name="M" hasparams="optional">
|
|
|
|
<para>Enable music on hold when the conference has a single caller. Optionally,
|
|
|
|
specify a musiconhold class to use. If one is not provided, it will use the
|
|
|
|
channel's currently set music class, or <literal>default</literal>.</para>
|
|
|
|
<argument name="class" required="true" />
|
|
|
|
</option>
|
2013-02-28 16:56:20 +00:00
|
|
|
<option name="n">
|
|
|
|
<para>Disable the denoiser. By default, if <literal>func_speex</literal> is loaded, Asterisk
|
|
|
|
will apply a denoiser to channels in the MeetMe conference. However, channel
|
|
|
|
drivers that present audio with a varying rate will experience degraded
|
|
|
|
performance with a denoiser attached. This parameter allows a channel joining
|
|
|
|
the conference to choose not to have a denoiser attached without having to
|
|
|
|
unload <literal>func_speex</literal>.</para>
|
|
|
|
</option>
|
2008-11-13 15:46:06 +00:00
|
|
|
<option name="o">
|
|
|
|
<para>Set talker optimization - treats talkers who aren't speaking as
|
|
|
|
being muted, meaning (a) No encode is done on transmission and (b)
|
|
|
|
Received audio that is not registered as talking is omitted causing no
|
|
|
|
buildup in background noise.</para>
|
|
|
|
</option>
|
|
|
|
<option name="p" hasparams="optional">
|
|
|
|
<para>Allow user to exit the conference by pressing <literal>#</literal> (default)
|
2012-09-10 18:58:12 +00:00
|
|
|
or any of the defined keys. Dial plan execution will continue at the next
|
|
|
|
priority following MeetMe. The key used is set to channel variable
|
2008-11-13 15:46:06 +00:00
|
|
|
<variable>MEETME_EXIT_KEY</variable>.</para>
|
|
|
|
<argument name="keys" required="true" />
|
2011-10-12 17:52:55 +00:00
|
|
|
<note>
|
|
|
|
<para>Option <literal>s</literal> has priority for <literal>*</literal>
|
|
|
|
since it cannot change its activation code.</para>
|
|
|
|
</note>
|
2008-11-13 15:46:06 +00:00
|
|
|
</option>
|
|
|
|
<option name="P">
|
|
|
|
<para>Always prompt for the pin even if it is specified.</para>
|
|
|
|
</option>
|
|
|
|
<option name="q">
|
|
|
|
<para>Quiet mode (don't play enter/leave sounds).</para>
|
|
|
|
</option>
|
|
|
|
<option name="r">
|
|
|
|
<para>Record conference (records as <variable>MEETME_RECORDINGFILE</variable>
|
|
|
|
using format <variable>MEETME_RECORDINGFORMAT</variable>. Default filename is
|
|
|
|
<literal>meetme-conf-rec-${CONFNO}-${UNIQUEID}</literal> and the default format is
|
|
|
|
wav.</para>
|
|
|
|
</option>
|
|
|
|
<option name="s">
|
|
|
|
<para>Present menu (user or admin) when <literal>*</literal> is received
|
|
|
|
(send to menu).</para>
|
|
|
|
</option>
|
|
|
|
<option name="t">
|
|
|
|
<para>Set talk only mode. (Talk only, no listening).</para>
|
|
|
|
</option>
|
|
|
|
<option name="T">
|
|
|
|
<para>Set talker detection (sent to manager interface and meetme list).</para>
|
|
|
|
</option>
|
2010-11-24 23:46:14 +00:00
|
|
|
<option name="v" hasparams="optional">
|
|
|
|
<para>Announce when a user is joining or leaving the conference. Use the voicemail greeting as the announcement.
|
|
|
|
If the i or I options are set, the application will fall back to them if no voicemail greeting can be found.</para>
|
|
|
|
<argument name="mailbox@[context]" required="true">
|
|
|
|
<para>The mailbox and voicemail context to play from. If no context provided, assumed context is default.</para>
|
|
|
|
</argument>
|
|
|
|
</option>
|
2010-06-17 00:30:51 +00:00
|
|
|
<option name="w" hasparams="optional">
|
2008-11-13 15:46:06 +00:00
|
|
|
<para>Wait until the marked user enters the conference.</para>
|
|
|
|
<argument name="secs" required="true" />
|
|
|
|
</option>
|
|
|
|
<option name="x">
|
2012-08-09 17:40:45 +00:00
|
|
|
<para>Leave the conference when the last marked user leaves.</para>
|
2008-11-13 15:46:06 +00:00
|
|
|
</option>
|
|
|
|
<option name="X">
|
|
|
|
<para>Allow user to exit the conference by entering a valid single digit
|
|
|
|
extension <variable>MEETME_EXIT_CONTEXT</variable> or the current context
|
|
|
|
if that variable is not defined.</para>
|
2011-10-12 17:52:55 +00:00
|
|
|
<note>
|
|
|
|
<para>Option <literal>s</literal> has priority for <literal>*</literal>
|
|
|
|
since it cannot change its activation code.</para>
|
|
|
|
</note>
|
2008-11-13 15:46:06 +00:00
|
|
|
</option>
|
|
|
|
<option name="1">
|
|
|
|
<para>Do not play message when first person enters</para>
|
|
|
|
</option>
|
|
|
|
<option name="S">
|
|
|
|
<para>Kick the user <replaceable>x</replaceable> seconds <emphasis>after</emphasis> he entered into
|
|
|
|
the conference.</para>
|
|
|
|
<argument name="x" required="true" />
|
|
|
|
</option>
|
|
|
|
<option name="L" argsep=":">
|
|
|
|
<para>Limit the conference to <replaceable>x</replaceable> ms. Play a warning when
|
|
|
|
<replaceable>y</replaceable> ms are left. Repeat the warning every <replaceable>z</replaceable> ms.
|
|
|
|
The following special variables can be used with this option:</para>
|
|
|
|
<variablelist>
|
|
|
|
<variable name="CONF_LIMIT_TIMEOUT_FILE">
|
|
|
|
<para>File to play when time is up.</para>
|
|
|
|
</variable>
|
|
|
|
<variable name="CONF_LIMIT_WARNING_FILE">
|
|
|
|
<para>File to play as warning if <replaceable>y</replaceable> is defined. The
|
|
|
|
default is to say the time remaining.</para>
|
|
|
|
</variable>
|
|
|
|
</variablelist>
|
|
|
|
<argument name="x" />
|
|
|
|
<argument name="y" />
|
|
|
|
<argument name="z" />
|
|
|
|
</option>
|
|
|
|
</optionlist>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="pin" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Enters the user into a specified MeetMe conference. If the <replaceable>confno</replaceable>
|
|
|
|
is omitted, the user will be prompted to enter one. User can exit the conference by hangup, or
|
|
|
|
if the <literal>p</literal> option is specified, by pressing <literal>#</literal>.</para>
|
2011-11-02 13:46:15 +00:00
|
|
|
<note><para>The DAHDI kernel modules and a functional DAHDI timing source (see dahdi_test)
|
2008-11-13 15:46:06 +00:00
|
|
|
must be present for conferencing to operate properly. In addition, the chan_dahdi channel driver
|
|
|
|
must be loaded for the <literal>i</literal> and <literal>r</literal> options to operate at
|
|
|
|
all.</para></note>
|
|
|
|
</description>
|
|
|
|
<see-also>
|
|
|
|
<ref type="application">MeetMeCount</ref>
|
|
|
|
<ref type="application">MeetMeAdmin</ref>
|
|
|
|
<ref type="application">MeetMeChannelAdmin</ref>
|
|
|
|
</see-also>
|
|
|
|
</application>
|
|
|
|
<application name="MeetMeCount" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
MeetMe participant count.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="confno" required="true">
|
|
|
|
<para>Conference number.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="var" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Plays back the number of users in the specified MeetMe conference.
|
|
|
|
If <replaceable>var</replaceable> is specified, playback will be skipped and the value
|
|
|
|
will be returned in the variable. Upon application completion, MeetMeCount will hangup
|
|
|
|
the channel, unless priority <literal>n+1</literal> exists, in which case priority progress will
|
|
|
|
continue.</para>
|
|
|
|
</description>
|
|
|
|
<see-also>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
</see-also>
|
|
|
|
</application>
|
|
|
|
<application name="MeetMeAdmin" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
MeetMe conference administration.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="confno" required="true" />
|
|
|
|
<parameter name="command" required="true">
|
|
|
|
<optionlist>
|
|
|
|
<option name="e">
|
|
|
|
<para>Eject last user that joined.</para>
|
|
|
|
</option>
|
|
|
|
<option name="E">
|
|
|
|
<para>Extend conference end time, if scheduled.</para>
|
|
|
|
</option>
|
|
|
|
<option name="k">
|
|
|
|
<para>Kick one user out of conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="K">
|
|
|
|
<para>Kick all users out of conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="l">
|
|
|
|
<para>Unlock conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="L">
|
|
|
|
<para>Lock conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="m">
|
|
|
|
<para>Unmute one user.</para>
|
|
|
|
</option>
|
|
|
|
<option name="M">
|
|
|
|
<para>Mute one user.</para>
|
|
|
|
</option>
|
|
|
|
<option name="n">
|
|
|
|
<para>Unmute all users in the conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="N">
|
|
|
|
<para>Mute all non-admin users in the conference.</para>
|
|
|
|
</option>
|
|
|
|
<option name="r">
|
|
|
|
<para>Reset one user's volume settings.</para>
|
|
|
|
</option>
|
|
|
|
<option name="R">
|
|
|
|
<para>Reset all users volume settings.</para>
|
|
|
|
</option>
|
|
|
|
<option name="s">
|
|
|
|
<para>Lower entire conference speaking volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="S">
|
|
|
|
<para>Raise entire conference speaking volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="t">
|
|
|
|
<para>Lower one user's talk volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="T">
|
|
|
|
<para>Raise one user's talk volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="u">
|
|
|
|
<para>Lower one user's listen volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="U">
|
|
|
|
<para>Raise one user's listen volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="v">
|
|
|
|
<para>Lower entire conference listening volume.</para>
|
|
|
|
</option>
|
|
|
|
<option name="V">
|
|
|
|
<para>Raise entire conference listening volume.</para>
|
|
|
|
</option>
|
|
|
|
</optionlist>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="user" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Run admin <replaceable>command</replaceable> for conference <replaceable>confno</replaceable>.</para>
|
|
|
|
<para>Will additionally set the variable <variable>MEETMEADMINSTATUS</variable> with one of
|
|
|
|
the following values:</para>
|
|
|
|
<variablelist>
|
|
|
|
<variable name="MEETMEADMINSTATUS">
|
|
|
|
<value name="NOPARSE">
|
|
|
|
Invalid arguments.
|
|
|
|
</value>
|
|
|
|
<value name="NOTFOUND">
|
|
|
|
User specified was not found.
|
|
|
|
</value>
|
|
|
|
<value name="FAILED">
|
|
|
|
Another failure occurred.
|
|
|
|
</value>
|
|
|
|
<value name="OK">
|
|
|
|
The operation was completed successfully.
|
|
|
|
</value>
|
|
|
|
</variable>
|
|
|
|
</variablelist>
|
|
|
|
</description>
|
|
|
|
<see-also>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
</see-also>
|
|
|
|
</application>
|
|
|
|
<application name="MeetMeChannelAdmin" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
MeetMe conference Administration (channel specific).
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="channel" required="true" />
|
|
|
|
<parameter name="command" required="true">
|
|
|
|
<optionlist>
|
|
|
|
<option name="k">
|
|
|
|
<para>Kick the specified user out of the conference he is in.</para>
|
|
|
|
</option>
|
|
|
|
<option name="m">
|
|
|
|
<para>Unmute the specified user.</para>
|
|
|
|
</option>
|
|
|
|
<option name="M">
|
|
|
|
<para>Mute the specified user.</para>
|
|
|
|
</option>
|
|
|
|
</optionlist>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Run admin <replaceable>command</replaceable> for a specific
|
2011-06-17 18:39:26 +00:00
|
|
|
<replaceable>channel</replaceable> in any conference.</para>
|
2008-11-13 15:46:06 +00:00
|
|
|
</description>
|
|
|
|
</application>
|
|
|
|
<application name="SLAStation" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
Shared Line Appearance Station.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="station" required="true">
|
|
|
|
<para>Station name</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>This application should be executed by an SLA station. The argument depends
|
|
|
|
on how the call was initiated. If the phone was just taken off hook, then the argument
|
|
|
|
<replaceable>station</replaceable> should be just the station name. If the call was
|
|
|
|
initiated by pressing a line key, then the station name should be preceded by an underscore
|
|
|
|
and the trunk name associated with that line button.</para>
|
|
|
|
<para>For example: <literal>station1_line1</literal></para>
|
|
|
|
<para>On exit, this application will set the variable <variable>SLASTATION_STATUS</variable> to
|
|
|
|
one of the following values:</para>
|
|
|
|
<variablelist>
|
|
|
|
<variable name="SLASTATION_STATUS">
|
|
|
|
<value name="FAILURE" />
|
|
|
|
<value name="CONGESTION" />
|
|
|
|
<value name="SUCCESS" />
|
|
|
|
</variable>
|
|
|
|
</variablelist>
|
|
|
|
</description>
|
|
|
|
</application>
|
|
|
|
<application name="SLATrunk" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
Shared Line Appearance Trunk.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="trunk" required="true">
|
|
|
|
<para>Trunk name</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="options">
|
|
|
|
<optionlist>
|
|
|
|
<option name="M" hasparams="optional">
|
|
|
|
<para>Play back the specified MOH <replaceable>class</replaceable>
|
|
|
|
instead of ringing</para>
|
|
|
|
<argument name="class" required="true" />
|
|
|
|
</option>
|
|
|
|
</optionlist>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>This application should be executed by an SLA trunk on an inbound call. The channel calling
|
|
|
|
this application should correspond to the SLA trunk with the name <replaceable>trunk</replaceable>
|
|
|
|
that is being passed as an argument.</para>
|
|
|
|
<para>On exit, this application will set the variable <variable>SLATRUNK_STATUS</variable> to
|
|
|
|
one of the following values:</para>
|
|
|
|
<variablelist>
|
|
|
|
<variable name="SLATRUNK_STATUS">
|
|
|
|
<value name="FAILURE" />
|
|
|
|
<value name="SUCCESS" />
|
|
|
|
<value name="UNANSWERED" />
|
|
|
|
<value name="RINGTIMEOUT" />
|
|
|
|
</variable>
|
|
|
|
</variablelist>
|
|
|
|
</description>
|
|
|
|
</application>
|
2009-06-06 22:27:48 +00:00
|
|
|
<function name="MEETME_INFO" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
Query a given conference of various properties.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="keyword" required="true">
|
|
|
|
<para>Options:</para>
|
|
|
|
<enumlist>
|
|
|
|
<enum name="lock">
|
|
|
|
<para>Boolean of whether the corresponding conference is locked.</para>
|
|
|
|
</enum>
|
|
|
|
<enum name="parties">
|
|
|
|
<para>Number of parties in a given conference</para>
|
|
|
|
</enum>
|
|
|
|
<enum name="activity">
|
|
|
|
<para>Duration of conference in seconds.</para>
|
|
|
|
</enum>
|
|
|
|
<enum name="dynamic">
|
|
|
|
<para>Boolean of whether the corresponding conference is dynamic.</para>
|
|
|
|
</enum>
|
|
|
|
</enumlist>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="confno" required="true">
|
|
|
|
<para>Conference number to retrieve information from.</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<description />
|
|
|
|
<see-also>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
<ref type="application">MeetMeCount</ref>
|
|
|
|
<ref type="application">MeetMeAdmin</ref>
|
|
|
|
<ref type="application">MeetMeChannelAdmin</ref>
|
|
|
|
</see-also>
|
|
|
|
</function>
|
2009-05-22 17:52:35 +00:00
|
|
|
<manager name="MeetmeMute" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
Mute a Meetme user.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
|
|
|
<parameter name="Meetme" required="true" />
|
|
|
|
<parameter name="Usernum" required="true" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
</description>
|
|
|
|
</manager>
|
|
|
|
<manager name="MeetmeUnmute" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
Unmute a Meetme user.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
|
|
|
<parameter name="Meetme" required="true" />
|
|
|
|
<parameter name="Usernum" required="true" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
</description>
|
|
|
|
</manager>
|
|
|
|
<manager name="MeetmeList" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
List participants in a conference.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
2010-11-30 19:13:54 +00:00
|
|
|
<parameter name="Conference" required="false">
|
2009-05-22 17:52:35 +00:00
|
|
|
<para>Conference number.</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Lists all users in a particular MeetMe conference.
|
|
|
|
MeetmeList will follow as separate events, followed by a final event called
|
|
|
|
MeetmeListComplete.</para>
|
|
|
|
</description>
|
|
|
|
</manager>
|
2011-02-09 22:48:02 +00:00
|
|
|
<manager name="MeetmeListRooms" language="en_US">
|
|
|
|
<synopsis>
|
|
|
|
List active conferences.
|
|
|
|
</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
|
|
|
</syntax>
|
|
|
|
<description>
|
|
|
|
<para>Lists data about all active conferences.
|
|
|
|
MeetmeListRooms will follow as separate events, followed by a final event called
|
|
|
|
MeetmeListRoomsComplete.</para>
|
|
|
|
</description>
|
|
|
|
</manager>
|
2013-06-07 15:54:26 +00:00
|
|
|
<managerEvent language="en_US" name="MeetmeJoin">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a user joins a MeetMe conference.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="Meetme">
|
|
|
|
<para>The identifier for the MeetMe conference.</para>
|
|
|
|
</parameter>
|
2018-05-29 17:28:48 +00:00
|
|
|
<parameter name="User">
|
2013-06-07 15:54:26 +00:00
|
|
|
<para>The identifier of the MeetMe user who joined.</para>
|
|
|
|
</parameter>
|
2013-08-01 17:07:52 +00:00
|
|
|
<channel_snapshot/>
|
2013-06-07 15:54:26 +00:00
|
|
|
</syntax>
|
|
|
|
<see-also>
|
|
|
|
<ref type="managerEvent">MeetmeLeave</ref>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
</see-also>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeLeave">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
|
2013-08-01 17:07:52 +00:00
|
|
|
<channel_snapshot/>
|
2013-06-07 15:54:26 +00:00
|
|
|
<parameter name="Duration">
|
|
|
|
<para>The length of time in seconds that the Meetme user was in the conference.</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<see-also>
|
|
|
|
<ref type="managerEvent">MeetmeJoin</ref>
|
|
|
|
</see-also>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeEnd">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a MeetMe conference ends.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
|
|
|
|
</syntax>
|
|
|
|
<see-also>
|
|
|
|
<ref type="managerEvent">MeetmeJoin</ref>
|
|
|
|
</see-also>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeTalkRequest">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a MeetMe user has started talking.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
|
2013-08-01 17:07:52 +00:00
|
|
|
<channel_snapshot/>
|
2013-06-07 15:54:26 +00:00
|
|
|
<parameter name="Duration">
|
|
|
|
<para>The length of time in seconds that the Meetme user has been in the conference at the time of this event.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Status">
|
|
|
|
<enumlist>
|
|
|
|
<enum name="on"/>
|
|
|
|
<enum name="off"/>
|
|
|
|
</enumlist>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeTalking">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
|
2013-08-01 17:07:52 +00:00
|
|
|
<channel_snapshot/>
|
2013-06-07 15:54:26 +00:00
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
|
|
|
|
</syntax>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeMute">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised when a MeetMe user is muted or unmuted.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
|
2013-08-01 17:07:52 +00:00
|
|
|
<channel_snapshot/>
|
2013-06-07 15:54:26 +00:00
|
|
|
<xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
|
|
|
|
</syntax>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
2022-07-23 23:07:18 +00:00
|
|
|
<managerEvent language="en_US" name="MeetmeList">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised in response to a MeetmeList command.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="Conference">
|
|
|
|
<para>Conference ID.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="UserNumber">
|
|
|
|
<para>User ID.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="CallerIDNum">
|
|
|
|
<para>Caller ID number.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="CallerIDName">
|
|
|
|
<para>Caller ID name.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="ConnectedLineNum">
|
|
|
|
<para>Connected Line number.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="ConnectedLineName">
|
|
|
|
<para>Connected Line name.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Channel">
|
|
|
|
<para>Channel name</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Admin">
|
|
|
|
<para>Whether or not the user is an admin.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Role">
|
|
|
|
<para>User role. Can be "Listen only", "Talk only", or "Talk and listen".</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="MarkedUser">
|
|
|
|
<para>Whether or not the user is a marked user.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Muted">
|
|
|
|
<para>Whether or not the user is currently muted.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Talking">
|
|
|
|
<para>Whether or not the user is currently talking.</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<see-also>
|
|
|
|
<ref type="manager">MeetmeList</ref>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
</see-also>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
|
|
|
<managerEvent language="en_US" name="MeetmeListRooms">
|
|
|
|
<managerEventInstance class="EVENT_FLAG_CALL">
|
|
|
|
<synopsis>Raised in response to a MeetmeListRooms command.</synopsis>
|
|
|
|
<syntax>
|
|
|
|
<parameter name="Conference">
|
|
|
|
<para>Conference ID.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Parties">
|
|
|
|
<para>Number of parties in the conference.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Marked">
|
|
|
|
<para>Number of marked users in the conference.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Activity">
|
|
|
|
<para>Total duration of conference in HH:MM:SS format.</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Creation">
|
|
|
|
<para>How the conference was created: "Dyanmic" or "Static".</para>
|
|
|
|
</parameter>
|
|
|
|
<parameter name="Locked">
|
|
|
|
<para>Whether or not the conference is locked.</para>
|
|
|
|
</parameter>
|
|
|
|
</syntax>
|
|
|
|
<see-also>
|
|
|
|
<ref type="manager">MeetmeListRooms</ref>
|
|
|
|
<ref type="application">MeetMe</ref>
|
|
|
|
</see-also>
|
|
|
|
</managerEventInstance>
|
|
|
|
</managerEvent>
|
2008-11-13 15:46:06 +00:00
|
|
|
***/
|
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
#define CONFIG_FILE_NAME "meetme.conf"
|
|
|
|
#define SLA_CONFIG_FILE "sla.conf"
|
|
|
|
#define STR_CONCISE "concise"
|
2006-05-21 15:13:19 +00:00
|
|
|
|
|
|
|
/*! each buffer is 20ms, so this is 640ms total */
|
|
|
|
#define DEFAULT_AUDIO_BUFFERS 32
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
/*! String format for scheduled conferences */
|
|
|
|
#define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
|
|
|
|
|
2006-05-21 15:13:19 +00:00
|
|
|
enum {
|
2006-05-23 16:35:46 +00:00
|
|
|
ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
|
|
|
|
ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
|
2007-10-25 18:59:22 +00:00
|
|
|
ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
|
|
|
|
/*! User has requested to speak */
|
|
|
|
ADMINFLAG_T_REQUEST = (1 << 4),
|
2011-09-15 12:50:40 +00:00
|
|
|
ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
|
2006-05-21 15:13:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define MEETME_DELAYDETECTTALK 300
|
|
|
|
#define MEETME_DELAYDETECTENDTALK 1000
|
|
|
|
|
|
|
|
#define AST_FRAME_BITS 32
|
|
|
|
|
|
|
|
enum volume_action {
|
|
|
|
VOL_UP,
|
|
|
|
VOL_DOWN
|
|
|
|
};
|
|
|
|
|
|
|
|
enum entrance_sound {
|
|
|
|
ENTER,
|
|
|
|
LEAVE
|
|
|
|
};
|
|
|
|
|
|
|
|
enum recording_state {
|
|
|
|
MEETME_RECORD_OFF,
|
|
|
|
MEETME_RECORD_STARTED,
|
|
|
|
MEETME_RECORD_ACTIVE,
|
|
|
|
MEETME_RECORD_TERMINATE
|
|
|
|
};
|
|
|
|
|
|
|
|
#define CONF_SIZE 320
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/*! user has admin access on the conference */
|
|
|
|
CONFFLAG_ADMIN = (1 << 0),
|
|
|
|
/*! If set the user can only receive audio from the conference */
|
|
|
|
CONFFLAG_MONITOR = (1 << 1),
|
2007-07-03 20:34:27 +00:00
|
|
|
/*! If set asterisk will exit conference when key defined in p() option is pressed */
|
|
|
|
CONFFLAG_KEYEXIT = (1 << 2),
|
2006-05-21 15:13:19 +00:00
|
|
|
/*! If set asterisk will provide a menu to the user when '*' is pressed */
|
|
|
|
CONFFLAG_STARMENU = (1 << 3),
|
|
|
|
/*! If set the use can only send audio to the conference */
|
|
|
|
CONFFLAG_TALKER = (1 << 4),
|
|
|
|
/*! If set there will be no enter or leave sounds */
|
|
|
|
CONFFLAG_QUIET = (1 << 5),
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! If set, when user joins the conference, they will be told the number
|
2006-05-21 15:13:19 +00:00
|
|
|
* of users that are already in */
|
|
|
|
CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
|
|
|
|
/*! Set to run AGI Script in Background */
|
|
|
|
CONFFLAG_AGI = (1 << 7),
|
|
|
|
/*! Set to have music on hold when user is alone in conference */
|
|
|
|
CONFFLAG_MOH = (1 << 8),
|
2012-08-09 17:40:45 +00:00
|
|
|
/*! If set, the channel will leave the conference if all marked users leave */
|
2006-05-21 15:13:19 +00:00
|
|
|
CONFFLAG_MARKEDEXIT = (1 << 9),
|
|
|
|
/*! If set, the MeetMe will wait until a marked user enters */
|
|
|
|
CONFFLAG_WAITMARKED = (1 << 10),
|
|
|
|
/*! If set, the MeetMe will exit to the specified context */
|
|
|
|
CONFFLAG_EXIT_CONTEXT = (1 << 11),
|
|
|
|
/*! If set, the user will be marked */
|
|
|
|
CONFFLAG_MARKEDUSER = (1 << 12),
|
|
|
|
/*! If set, user will be ask record name on entry of conference */
|
|
|
|
CONFFLAG_INTROUSER = (1 << 13),
|
|
|
|
/*! If set, the MeetMe will be recorded */
|
|
|
|
CONFFLAG_RECORDCONF = (1<< 14),
|
|
|
|
/*! If set, the user will be monitored if the user is talking or not */
|
|
|
|
CONFFLAG_MONITORTALKER = (1 << 15),
|
|
|
|
CONFFLAG_DYNAMIC = (1 << 16),
|
|
|
|
CONFFLAG_DYNAMICPIN = (1 << 17),
|
|
|
|
CONFFLAG_EMPTY = (1 << 18),
|
|
|
|
CONFFLAG_EMPTYNOPIN = (1 << 19),
|
|
|
|
CONFFLAG_ALWAYSPROMPT = (1 << 20),
|
2009-02-18 19:12:49 +00:00
|
|
|
/*! If set, treat talking users as muted users */
|
|
|
|
CONFFLAG_OPTIMIZETALKER = (1 << 21),
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! If set, won't speak the extra prompt when the first person
|
2006-05-21 15:13:19 +00:00
|
|
|
* enters the conference */
|
|
|
|
CONFFLAG_NOONLYPERSON = (1 << 22),
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! If set, user will be asked to record name on entry of conference
|
2006-05-21 15:13:19 +00:00
|
|
|
* without review */
|
2006-07-08 02:24:07 +00:00
|
|
|
CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
|
2006-05-31 22:54:58 +00:00
|
|
|
/*! If set, the user will be initially self-muted */
|
2006-07-08 02:24:07 +00:00
|
|
|
CONFFLAG_STARTMUTED = (1 << 24),
|
2007-02-10 00:40:57 +00:00
|
|
|
/*! Pass DTMF through the conference */
|
|
|
|
CONFFLAG_PASS_DTMF = (1 << 25),
|
|
|
|
CONFFLAG_SLA_STATION = (1 << 26),
|
|
|
|
CONFFLAG_SLA_TRUNK = (1 << 27),
|
2006-10-18 22:19:57 +00:00
|
|
|
/*! If set, the user should continue in the dialplan if kicked out */
|
2007-11-06 22:15:32 +00:00
|
|
|
CONFFLAG_KICK_CONTINUE = (1 << 28),
|
|
|
|
CONFFLAG_DURATION_STOP = (1 << 29),
|
|
|
|
CONFFLAG_DURATION_LIMIT = (1 << 30),
|
2006-05-21 15:13:19 +00:00
|
|
|
};
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/* These flags are defined separately because we ran out of bits that an enum can be used to represent.
|
2011-08-11 21:55:48 +00:00
|
|
|
If you add new flags, be sure to do it in the same way that these are. */
|
|
|
|
/*! Do not write any audio to this channel until the state is up. */
|
2011-08-12 18:03:29 +00:00
|
|
|
#define CONFFLAG_NO_AUDIO_UNTIL_UP (1ULL << 31)
|
|
|
|
#define CONFFLAG_INTROMSG (1ULL << 32) /*!< If set play an intro announcement at start of conference */
|
|
|
|
#define CONFFLAG_INTROUSER_VMREC (1ULL << 33)
|
2011-09-15 12:50:40 +00:00
|
|
|
/*! If there's only one person left in a conference when someone leaves, kill the conference */
|
2013-08-19 23:58:47 +00:00
|
|
|
#define CONFFLAG_KILL_LAST_MAN_STANDING (1ULL << 34)
|
2013-02-28 16:56:20 +00:00
|
|
|
/*! If set, don't enable a denoiser for the channel */
|
2013-08-19 23:58:47 +00:00
|
|
|
#define CONFFLAG_DONT_DENOISE (1ULL << 35)
|
2009-12-10 17:31:23 +00:00
|
|
|
|
2006-09-11 22:17:46 +00:00
|
|
|
enum {
|
|
|
|
OPT_ARG_WAITMARKED = 0,
|
2007-07-03 20:34:27 +00:00
|
|
|
OPT_ARG_EXITKEYS = 1,
|
2007-11-06 22:15:32 +00:00
|
|
|
OPT_ARG_DURATION_STOP = 2,
|
|
|
|
OPT_ARG_DURATION_LIMIT = 3,
|
2007-11-21 00:21:38 +00:00
|
|
|
OPT_ARG_MOH_CLASS = 4,
|
2009-12-10 17:31:23 +00:00
|
|
|
OPT_ARG_INTROMSG = 5,
|
2010-11-24 23:46:14 +00:00
|
|
|
OPT_ARG_INTROUSER_VMREC = 6,
|
|
|
|
OPT_ARG_ARRAY_SIZE = 7,
|
2007-01-20 00:13:52 +00:00
|
|
|
};
|
2006-09-11 22:17:46 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
|
|
|
|
AST_APP_OPTION('a', CONFFLAG_ADMIN ),
|
|
|
|
AST_APP_OPTION('b', CONFFLAG_AGI ),
|
|
|
|
AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
|
2006-10-18 22:19:57 +00:00
|
|
|
AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
|
|
|
|
AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
|
|
|
|
AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
|
|
|
|
AST_APP_OPTION('e', CONFFLAG_EMPTY ),
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
|
2009-12-10 17:31:23 +00:00
|
|
|
AST_APP_OPTION_ARG('G', CONFFLAG_INTROMSG, OPT_ARG_INTROMSG ),
|
2010-11-24 23:46:14 +00:00
|
|
|
AST_APP_OPTION_ARG('v', CONFFLAG_INTROUSER_VMREC , OPT_ARG_INTROUSER_VMREC),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
|
|
|
|
AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
|
2011-09-15 12:50:40 +00:00
|
|
|
AST_APP_OPTION('k', CONFFLAG_KILL_LAST_MAN_STANDING ),
|
2007-11-21 00:21:38 +00:00
|
|
|
AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ),
|
2006-05-23 16:35:46 +00:00
|
|
|
AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
|
2013-02-28 16:56:20 +00:00
|
|
|
AST_APP_OPTION('n', CONFFLAG_DONT_DENOISE ),
|
2009-02-18 19:12:49 +00:00
|
|
|
AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
|
2007-07-03 20:34:27 +00:00
|
|
|
AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('q', CONFFLAG_QUIET ),
|
|
|
|
AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
|
|
|
|
AST_APP_OPTION('s', CONFFLAG_STARMENU ),
|
|
|
|
AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
|
2006-05-23 16:35:46 +00:00
|
|
|
AST_APP_OPTION('l', CONFFLAG_MONITOR ),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('t', CONFFLAG_TALKER ),
|
2006-09-11 22:17:46 +00:00
|
|
|
AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
|
2006-05-21 15:13:19 +00:00
|
|
|
AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
|
|
|
|
AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
|
|
|
|
AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
|
2007-11-06 22:15:32 +00:00
|
|
|
AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP),
|
|
|
|
AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
|
2007-02-10 00:40:57 +00:00
|
|
|
END_OPTIONS );
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2009-05-12 13:59:35 +00:00
|
|
|
static const char * const app = "MeetMe";
|
|
|
|
static const char * const app2 = "MeetMeCount";
|
|
|
|
static const char * const app3 = "MeetMeAdmin";
|
|
|
|
static const char * const app4 = "MeetMeChannelAdmin";
|
|
|
|
static const char * const slastation_app = "SLAStation";
|
|
|
|
static const char * const slatrunk_app = "SLATrunk";
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
/* Lookup RealTime conferences based on confno and current time */
|
|
|
|
static int rt_schedule;
|
|
|
|
static int fuzzystart;
|
|
|
|
static int earlyalert;
|
|
|
|
static int endalert;
|
2008-10-01 23:02:25 +00:00
|
|
|
static int extendby;
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2009-08-18 18:57:28 +00:00
|
|
|
/*! Log participant count to the RealTime backend */
|
2007-10-17 15:13:51 +00:00
|
|
|
static int rt_log_members;
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
#define MAX_CONFNUM 80
|
|
|
|
#define MAX_PIN 80
|
2009-07-14 20:14:45 +00:00
|
|
|
#define OPTIONS_LEN 100
|
2006-07-01 23:54:43 +00:00
|
|
|
|
2009-12-28 12:44:58 +00:00
|
|
|
/* Enough space for "<conference #>,<pin>,<admin pin>" followed by a 0 byte. */
|
|
|
|
#define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
|
|
|
|
|
2008-11-12 18:32:46 +00:00
|
|
|
enum announcetypes {
|
|
|
|
CONF_HASJOIN,
|
|
|
|
CONF_HASLEFT
|
|
|
|
};
|
|
|
|
|
|
|
|
struct announce_listitem {
|
|
|
|
AST_LIST_ENTRY(announce_listitem) entry;
|
|
|
|
char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
|
|
|
|
char language[MAX_LANGUAGE];
|
|
|
|
struct ast_channel *confchan;
|
|
|
|
int confusers;
|
2010-11-24 23:46:14 +00:00
|
|
|
int vmrec;
|
2008-11-12 18:32:46 +00:00
|
|
|
enum announcetypes announcetype;
|
|
|
|
};
|
|
|
|
|
2006-07-03 07:40:08 +00:00
|
|
|
/*! \brief The MeetMe Conference object */
|
2006-01-26 19:33:27 +00:00
|
|
|
struct ast_conference {
|
2006-05-21 15:13:19 +00:00
|
|
|
ast_mutex_t playlock; /*!< Conference specific lock (players) */
|
|
|
|
ast_mutex_t listenlock; /*!< Conference specific lock (listeners) */
|
2007-02-10 00:40:57 +00:00
|
|
|
char confno[MAX_CONFNUM]; /*!< Conference */
|
2006-05-21 15:13:19 +00:00
|
|
|
struct ast_channel *chan; /*!< Announcements channel */
|
|
|
|
struct ast_channel *lchan; /*!< Listen/Record channel */
|
|
|
|
int fd; /*!< Announcements fd */
|
2008-06-12 17:27:55 +00:00
|
|
|
int dahdiconf; /*!< DAHDI Conf # */
|
2006-05-21 15:13:19 +00:00
|
|
|
int users; /*!< Number of active users */
|
|
|
|
int markedusers; /*!< Number of marked users */
|
2007-12-13 23:10:42 +00:00
|
|
|
int maxusers; /*!< Participant limit if scheduled */
|
|
|
|
int endalert; /*!< When to play conf ending message */
|
2006-05-21 15:13:19 +00:00
|
|
|
time_t start; /*!< Start time (s) */
|
|
|
|
int refcount; /*!< reference count of usage */
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
enum recording_state recording:2; /*!< recording status */
|
2006-05-21 15:13:19 +00:00
|
|
|
unsigned int isdynamic:1; /*!< Created on the fly? */
|
|
|
|
unsigned int locked:1; /*!< Is the conference locked? */
|
2010-05-03 22:13:24 +00:00
|
|
|
unsigned int gmuted:1; /*!< Is the conference globally muted? (all non-admins) */
|
2006-05-21 15:13:19 +00:00
|
|
|
pthread_t recordthread; /*!< thread for recording */
|
2007-12-13 23:10:42 +00:00
|
|
|
ast_mutex_t recordthreadlock; /*!< control threads trying to start recordthread */
|
2007-09-12 20:47:32 +00:00
|
|
|
pthread_attr_t attr; /*!< thread attribute */
|
2008-04-30 19:21:04 +00:00
|
|
|
char *recordingfilename; /*!< Filename to record the Conference into */
|
|
|
|
char *recordingformat; /*!< Format to record the Conference in */
|
2007-02-10 00:40:57 +00:00
|
|
|
char pin[MAX_PIN]; /*!< If protected by a PIN */
|
|
|
|
char pinadmin[MAX_PIN]; /*!< If protected by a admin PIN */
|
2007-05-02 23:50:07 +00:00
|
|
|
char uniqueid[32];
|
2007-12-13 23:10:42 +00:00
|
|
|
long endtime; /*!< When to end the conf if scheduled */
|
2008-10-17 04:28:13 +00:00
|
|
|
const char *useropts; /*!< RealTime user flags */
|
|
|
|
const char *adminopts; /*!< RealTime moderator flags */
|
|
|
|
const char *bookid; /*!< RealTime conference id */
|
2005-12-20 13:07:02 +00:00
|
|
|
struct ast_frame *transframe[32];
|
|
|
|
struct ast_frame *origframe;
|
|
|
|
struct ast_trans_pvt *transpath[32];
|
2010-07-13 17:37:40 +00:00
|
|
|
struct ao2_container *usercontainer;
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_ENTRY(ast_conference) list;
|
2008-11-12 18:32:46 +00:00
|
|
|
/* announce_thread related data */
|
|
|
|
pthread_t announcethread;
|
|
|
|
ast_mutex_t announcethreadlock;
|
|
|
|
unsigned int announcethread_stop:1;
|
|
|
|
ast_cond_t announcelist_addition;
|
|
|
|
AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist;
|
|
|
|
ast_mutex_t announcelistlock;
|
2006-01-26 19:33:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static AST_LIST_HEAD_STATIC(confs, ast_conference);
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2007-03-29 17:42:48 +00:00
|
|
|
static unsigned int conf_map[1024] = {0, };
|
|
|
|
|
2005-09-07 02:27:58 +00:00
|
|
|
struct volume {
|
2006-05-21 15:13:19 +00:00
|
|
|
int desired; /*!< Desired volume adjustment */
|
|
|
|
int actual; /*!< Actual volume adjustment (for channels that can't adjust) */
|
2005-09-07 02:27:58 +00:00
|
|
|
};
|
|
|
|
|
2007-02-24 20:29:41 +00:00
|
|
|
/*! \brief The MeetMe User object */
|
2004-05-22 04:11:22 +00:00
|
|
|
struct ast_conf_user {
|
2006-05-21 15:13:19 +00:00
|
|
|
int user_no; /*!< User Number */
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 userflags; /*!< Flags as set in the conference */
|
2006-05-21 15:13:19 +00:00
|
|
|
int adminflags; /*!< Flags set by the Admin */
|
|
|
|
struct ast_channel *chan; /*!< Connected channel */
|
|
|
|
int talking; /*!< Is user talking */
|
2009-08-18 18:57:28 +00:00
|
|
|
int dahdichannel; /*!< Is a DAHDI channel */
|
2006-05-21 15:13:19 +00:00
|
|
|
char usrvalue[50]; /*!< Custom User Value */
|
2009-08-18 18:57:28 +00:00
|
|
|
char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
|
2006-05-21 15:13:19 +00:00
|
|
|
time_t jointime; /*!< Time the user joined the conference */
|
2011-05-02 15:58:27 +00:00
|
|
|
time_t kicktime; /*!< Time the user will be kicked from the conference */
|
|
|
|
struct timeval start_time; /*!< Time the user entered into the conference */
|
|
|
|
long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
|
|
|
|
long play_warning; /*!< Play a warning when 'y' ms are left */
|
|
|
|
long warning_freq; /*!< Repeat the warning every 'z' ms */
|
|
|
|
const char *warning_sound; /*!< File to play as warning if 'y' is defined */
|
|
|
|
const char *end_sound; /*!< File to play when time is up. */
|
2005-09-07 02:27:58 +00:00
|
|
|
struct volume talk;
|
|
|
|
struct volume listen;
|
2006-05-13 11:06:34 +00:00
|
|
|
AST_LIST_ENTRY(ast_conf_user) list;
|
2004-05-22 04:11:22 +00:00
|
|
|
};
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
enum sla_which_trunk_refs {
|
|
|
|
ALL_TRUNK_REFS,
|
|
|
|
INACTIVE_TRUNK_REFS,
|
|
|
|
};
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
enum sla_trunk_state {
|
|
|
|
SLA_TRUNK_STATE_IDLE,
|
|
|
|
SLA_TRUNK_STATE_RINGING,
|
|
|
|
SLA_TRUNK_STATE_UP,
|
|
|
|
SLA_TRUNK_STATE_ONHOLD,
|
2007-03-08 20:56:57 +00:00
|
|
|
SLA_TRUNK_STATE_ONHOLD_BYME,
|
2006-07-01 23:54:43 +00:00
|
|
|
};
|
|
|
|
|
2007-02-28 22:09:33 +00:00
|
|
|
enum sla_hold_access {
|
|
|
|
/*! This means that any station can put it on hold, and any station
|
|
|
|
* can retrieve the call from hold. */
|
|
|
|
SLA_HOLD_OPEN,
|
|
|
|
/*! This means that only the station that put the call on hold may
|
|
|
|
* retrieve it from hold. */
|
|
|
|
SLA_HOLD_PRIVATE,
|
|
|
|
};
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref;
|
|
|
|
|
|
|
|
struct sla_station {
|
|
|
|
AST_RWLIST_ENTRY(sla_station) entry;
|
|
|
|
AST_DECLARE_STRING_FIELDS(
|
2017-12-22 14:23:22 +00:00
|
|
|
AST_STRING_FIELD(name);
|
|
|
|
AST_STRING_FIELD(device);
|
|
|
|
AST_STRING_FIELD(autocontext);
|
2007-02-10 00:40:57 +00:00
|
|
|
);
|
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
|
|
|
|
struct ast_dial *dial;
|
2007-02-22 23:12:26 +00:00
|
|
|
/*! Ring timeout for this station, for any trunk. If a ring timeout
|
|
|
|
* is set for a specific trunk on this station, that will take
|
|
|
|
* priority over this value. */
|
|
|
|
unsigned int ring_timeout;
|
2007-02-28 18:21:47 +00:00
|
|
|
/*! Ring delay for this station, for any trunk. If a ring delay
|
|
|
|
* is set for a specific trunk on this station, that will take
|
|
|
|
* priority over this value. */
|
|
|
|
unsigned int ring_delay;
|
2007-02-28 22:09:33 +00:00
|
|
|
/*! This option uses the values in the sla_hold_access enum and sets the
|
|
|
|
* access control type for hold on this station. */
|
|
|
|
unsigned int hold_access:1;
|
2013-07-10 01:56:15 +00:00
|
|
|
/*! Mark used during reload processing */
|
|
|
|
unsigned int mark:1;
|
2007-02-10 00:40:57 +00:00
|
|
|
};
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \brief A reference to a station
|
|
|
|
*
|
|
|
|
* This struct looks near useless at first glance. However, its existence
|
|
|
|
* in the list of stations in sla_trunk means that this station references
|
|
|
|
* that trunk. We use the mark to keep track of whether it needs to be
|
|
|
|
* removed from the sla_trunk's list of stations during a reload.
|
|
|
|
*/
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station_ref {
|
|
|
|
AST_LIST_ENTRY(sla_station_ref) entry;
|
|
|
|
struct sla_station *station;
|
2013-07-10 01:56:15 +00:00
|
|
|
/*! Mark used during reload processing */
|
|
|
|
unsigned int mark:1;
|
2007-02-10 00:40:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sla_trunk {
|
|
|
|
AST_DECLARE_STRING_FIELDS(
|
|
|
|
AST_STRING_FIELD(name);
|
|
|
|
AST_STRING_FIELD(device);
|
2017-12-22 14:23:22 +00:00
|
|
|
AST_STRING_FIELD(autocontext);
|
2007-02-10 00:40:57 +00:00
|
|
|
);
|
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
|
|
|
|
/*! Number of stations that use this trunk */
|
|
|
|
unsigned int num_stations;
|
|
|
|
/*! Number of stations currently on a call with this trunk */
|
|
|
|
unsigned int active_stations;
|
|
|
|
/*! Number of stations that have this trunk on hold. */
|
|
|
|
unsigned int hold_stations;
|
|
|
|
struct ast_channel *chan;
|
2007-02-22 23:12:26 +00:00
|
|
|
unsigned int ring_timeout;
|
2007-02-28 19:57:41 +00:00
|
|
|
/*! If set to 1, no station will be able to join an active call with
|
|
|
|
* this trunk. */
|
|
|
|
unsigned int barge_disabled:1;
|
2007-02-28 22:09:33 +00:00
|
|
|
/*! This option uses the values in the sla_hold_access enum and sets the
|
|
|
|
* access control type for hold on this trunk. */
|
|
|
|
unsigned int hold_access:1;
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
/*! Whether this trunk is currently on hold, meaning that once a station
|
|
|
|
* connects to it, the trunk channel needs to have UNHOLD indicated to it. */
|
|
|
|
unsigned int on_hold:1;
|
2013-07-10 01:56:15 +00:00
|
|
|
/*! Mark used during reload processing */
|
|
|
|
unsigned int mark:1;
|
2007-02-10 00:40:57 +00:00
|
|
|
};
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \brief A station's reference to a trunk
|
|
|
|
*
|
|
|
|
* An sla_station keeps a list of trunk_refs. This holds metadata about the
|
|
|
|
* stations usage of the trunk.
|
|
|
|
*/
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref {
|
|
|
|
AST_LIST_ENTRY(sla_trunk_ref) entry;
|
|
|
|
struct sla_trunk *trunk;
|
|
|
|
enum sla_trunk_state state;
|
|
|
|
struct ast_channel *chan;
|
2007-02-26 01:05:15 +00:00
|
|
|
/*! Ring timeout to use when this trunk is ringing on this specific
|
|
|
|
* station. This takes higher priority than a ring timeout set at
|
|
|
|
* the station level. */
|
2007-02-22 23:12:26 +00:00
|
|
|
unsigned int ring_timeout;
|
2007-02-28 18:21:47 +00:00
|
|
|
/*! Ring delay to use when this trunk is ringing on this specific
|
|
|
|
* station. This takes higher priority than a ring delay set at
|
|
|
|
* the station level. */
|
|
|
|
unsigned int ring_delay;
|
2013-07-10 01:56:15 +00:00
|
|
|
/*! Mark used during reload processing */
|
|
|
|
unsigned int mark:1;
|
2007-02-10 00:40:57 +00:00
|
|
|
};
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static struct ao2_container *sla_stations;
|
|
|
|
static struct ao2_container *sla_trunks;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
static const char sla_registrar[] = "SLA";
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/*! \brief Event types that can be queued up for the SLA thread */
|
2007-02-10 00:40:57 +00:00
|
|
|
enum sla_event_type {
|
2007-02-22 23:12:26 +00:00
|
|
|
/*! A station has put the call on hold */
|
2007-02-10 00:40:57 +00:00
|
|
|
SLA_EVENT_HOLD,
|
2007-02-22 23:12:26 +00:00
|
|
|
/*! The state of a dial has changed */
|
|
|
|
SLA_EVENT_DIAL_STATE,
|
|
|
|
/*! The state of a ringing trunk has changed */
|
|
|
|
SLA_EVENT_RINGING_TRUNK,
|
2006-07-01 23:54:43 +00:00
|
|
|
};
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_event {
|
|
|
|
enum sla_event_type type;
|
|
|
|
struct sla_station *station;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
AST_LIST_ENTRY(sla_event) entry;
|
2006-07-01 23:54:43 +00:00
|
|
|
};
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! \brief A station that failed to be dialed
|
2007-02-22 23:12:26 +00:00
|
|
|
* \note Only used by the SLA thread. */
|
|
|
|
struct sla_failed_station {
|
|
|
|
struct sla_station *station;
|
|
|
|
struct timeval last_try;
|
|
|
|
AST_LIST_ENTRY(sla_failed_station) entry;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! \brief A trunk that is ringing */
|
|
|
|
struct sla_ringing_trunk {
|
|
|
|
struct sla_trunk *trunk;
|
|
|
|
/*! The time that this trunk started ringing */
|
|
|
|
struct timeval ring_begin;
|
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
|
|
|
|
AST_LIST_ENTRY(sla_ringing_trunk) entry;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum sla_station_hangup {
|
|
|
|
SLA_STATION_HANGUP_NORMAL,
|
|
|
|
SLA_STATION_HANGUP_TIMEOUT,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! \brief A station that is ringing */
|
|
|
|
struct sla_ringing_station {
|
|
|
|
struct sla_station *station;
|
|
|
|
/*! The time that this station started ringing */
|
|
|
|
struct timeval ring_begin;
|
|
|
|
AST_LIST_ENTRY(sla_ringing_station) entry;
|
|
|
|
};
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
/*!
|
|
|
|
* \brief A structure for data used by the sla thread
|
|
|
|
*/
|
2007-03-14 16:34:03 +00:00
|
|
|
static struct {
|
2007-02-10 00:40:57 +00:00
|
|
|
/*! The SLA thread ID */
|
|
|
|
pthread_t thread;
|
|
|
|
ast_cond_t cond;
|
|
|
|
ast_mutex_t lock;
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
|
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
|
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
|
|
|
|
unsigned int stop:1;
|
2007-03-14 16:34:03 +00:00
|
|
|
/*! Attempt to handle CallerID, even though it is known not to work
|
|
|
|
* properly in some situations. */
|
|
|
|
unsigned int attempt_callerid:1;
|
2007-02-10 00:40:57 +00:00
|
|
|
} sla = {
|
|
|
|
.thread = AST_PTHREADT_NULL,
|
|
|
|
};
|
2006-07-01 23:54:43 +00:00
|
|
|
|
2009-08-18 18:57:28 +00:00
|
|
|
/*! \brief The number of audio buffers to be allocated on pseudo channels
|
2006-05-21 15:13:19 +00:00
|
|
|
* when in a conference */
|
|
|
|
static int audio_buffers;
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! \brief Map 'volume' levels from -5 through +5 into decibel (dB)
|
2010-06-08 14:38:18 +00:00
|
|
|
* settings for channel drivers.
|
|
|
|
*
|
2009-08-18 18:57:28 +00:00
|
|
|
* \note these are not a straight linear-to-dB
|
2006-05-21 15:13:19 +00:00
|
|
|
* conversion... the numbers have been modified
|
2010-06-08 14:38:18 +00:00
|
|
|
* to give the user a better level of adjustability.
|
2006-05-21 15:13:19 +00:00
|
|
|
*/
|
2009-05-21 21:13:09 +00:00
|
|
|
static const char gain_map[] = {
|
2006-05-21 15:13:19 +00:00
|
|
|
-15,
|
|
|
|
-13,
|
|
|
|
-10,
|
|
|
|
-6,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
6,
|
|
|
|
10,
|
|
|
|
13,
|
|
|
|
15,
|
2005-09-07 01:30:01 +00:00
|
|
|
};
|
|
|
|
|
2013-06-07 15:54:26 +00:00
|
|
|
/* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
|
|
|
|
static struct stasis_message_router *meetme_event_message_router;
|
|
|
|
|
2013-07-01 13:16:09 +00:00
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
|
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
|
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
|
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
|
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
|
|
|
|
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
|
2013-06-07 15:54:26 +00:00
|
|
|
|
|
|
|
static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
|
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
|
|
|
struct stasis_message *message);
|
2013-06-07 15:54:26 +00:00
|
|
|
|
|
|
|
static void meetme_stasis_cleanup(void)
|
|
|
|
{
|
|
|
|
if (meetme_event_message_router) {
|
|
|
|
stasis_message_router_unsubscribe(meetme_event_message_router);
|
|
|
|
meetme_event_message_router = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
|
|
|
|
STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int meetme_stasis_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
|
|
|
|
STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
|
|
|
|
|
|
|
|
meetme_event_message_router = stasis_message_router_create(
|
2019-10-29 13:23:54 +00:00
|
|
|
ast_channel_topic_all());
|
2013-06-07 15:54:26 +00:00
|
|
|
|
|
|
|
if (!meetme_event_message_router) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_join_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_leave_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_end_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_mute_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_talking_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stasis_message_router_add(meetme_event_message_router,
|
|
|
|
meetme_talk_request_type(),
|
|
|
|
meetme_stasis_cb,
|
|
|
|
NULL)) {
|
|
|
|
meetme_stasis_cleanup();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
|
Multiple revisions 399887,400138,400178,400180-400181
........
r399887 | dlee | 2013-09-26 10:41:47 -0500 (Thu, 26 Sep 2013) | 1 line
Minor performance bump by not allocate manager variable struct if we don't need it
........
r400138 | dlee | 2013-09-30 10:24:00 -0500 (Mon, 30 Sep 2013) | 23 lines
Stasis performance improvements
This patch addresses several performance problems that were found in
the initial performance testing of Asterisk 12.
The Stasis dispatch object was allocated as an AO2 object, even though
it has a very confined lifecycle. This was replaced with a straight
ast_malloc().
The Stasis message router was spending an inordinate amount of time
searching hash tables. In this case, most of our routers had 6 or
fewer routes in them to begin with. This was replaced with an array
that's searched linearly for the route.
We more heavily rely on AO2 objects in Asterisk 12, and the memset()
in ao2_ref() actually became noticeable on the profile. This was
#ifdef'ed to only run when AO2_DEBUG was enabled.
After being misled by an erroneous comment in taskprocessor.c during
profiling, the wrong comment was removed.
Review: https://reviewboard.asterisk.org/r/2873/
........
r400178 | dlee | 2013-09-30 13:26:27 -0500 (Mon, 30 Sep 2013) | 24 lines
Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.
The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.
The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.
For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).
The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.
Review: https://reviewboard.asterisk.org/r/2881/
........
r400180 | dlee | 2013-09-30 13:39:34 -0500 (Mon, 30 Sep 2013) | 28 lines
Optimize how Stasis forwards are dispatched
This patch optimizes how forwards are dispatched in Stasis.
Originally, forwards were dispatched as subscriptions that are invoked
on the publishing thread. This did not account for the vast number of
forwards we would end up having in the system, and the amount of work it
would take to walk though the forward subscriptions.
This patch modifies Stasis so that rather than walking the tree of
forwards on every dispatch, when forwards and subscriptions are changed,
the subscriber list for every topic in the tree is changed.
This has a couple of benefits. First, this reduces the workload of
dispatching messages. It also reduces contention when dispatching to
different topics that happen to forward to the same aggregation topic
(as happens with all of the channel, bridge and endpoint topics).
Since forwards are no longer subscriptions, the bulk of this patch is
simply changing stasis_subscription objects to stasis_forward objects
(which, admittedly, I should have done in the first place.)
Since this required me to yet again put in a growing array, I finally
abstracted that out into a set of ast_vector macros in
asterisk/vector.h.
Review: https://reviewboard.asterisk.org/r/2883/
........
r400181 | dlee | 2013-09-30 13:48:57 -0500 (Mon, 30 Sep 2013) | 28 lines
Remove dispatch object allocation from Stasis publishing
While looking for areas for performance improvement, I realized that an
unused feature in Stasis was negatively impacting performance.
When a message is sent to a subscriber, a dispatch object is allocated
for the dispatch, containing the topic the message was published to, the
subscriber the message is being sent to, and the message itself.
The topic is actually unused by any subscriber in Asterisk today. And
the subscriber is associated with the taskprocessor the message is being
dispatched to.
First, this patch removes the unused topic parameter from Stasis
subscription callbacks.
Second, this patch introduces the concept of taskprocessor local data,
data that may be set on a taskprocessor and provided along with the data
pointer when a task is pushed using the ast_taskprocessor_push_local()
call. This allows the task to have both data specific to that
taskprocessor, in addition to data specific to that invocation.
With those two changes, the dispatch object can be removed completely,
and the message is simply refcounted and sent directly to the
taskprocessor.
Review: https://reviewboard.asterisk.org/r/2884/
........
Merged revisions 399887,400138,400178,400180-400181 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:55:27 +00:00
|
|
|
struct stasis_message *message)
|
2013-06-07 15:54:26 +00:00
|
|
|
{
|
|
|
|
struct ast_channel_blob *channel_blob = stasis_message_data(message);
|
|
|
|
struct stasis_message_type *message_type;
|
|
|
|
const char *event;
|
|
|
|
const char *conference_num;
|
|
|
|
const char *status;
|
|
|
|
struct ast_json *json_cur;
|
|
|
|
RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
|
|
|
|
RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
|
|
|
|
|
|
|
|
if (!channel_blob) {
|
|
|
|
ast_assert(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
message_type = stasis_message_type(message);
|
|
|
|
|
|
|
|
if (!message_type) {
|
|
|
|
ast_assert(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (message_type == meetme_join_type()) {
|
|
|
|
event = "MeetmeJoin";
|
|
|
|
} else if (message_type == meetme_leave_type()) {
|
|
|
|
event = "MeetmeLeave";
|
|
|
|
} else if (message_type == meetme_end_type()) {
|
|
|
|
event = "MeetmeEnd";
|
|
|
|
} else if (message_type == meetme_mute_type()) {
|
|
|
|
event = "MeetmeMute";
|
|
|
|
} else if (message_type == meetme_talking_type()) {
|
|
|
|
event = "MeetmeTalking";
|
|
|
|
} else if (message_type == meetme_talk_request_type()) {
|
|
|
|
event = "MeetmeTalkRequest";
|
|
|
|
} else {
|
|
|
|
ast_assert(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!event) {
|
|
|
|
ast_assert(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
|
|
|
|
if (!conference_num) {
|
|
|
|
ast_assert(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
|
|
|
|
if (status) {
|
|
|
|
ast_str_append_event_header(&extra_text, "Status", status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel_blob->snapshot) {
|
|
|
|
channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
|
|
|
|
int user_number = ast_json_integer_get(json_cur);
|
|
|
|
RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
|
|
|
|
if (!user_prop_str) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_str_set(&user_prop_str, 0, "%d", user_number);
|
|
|
|
ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
|
|
|
|
|
|
|
|
if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
|
|
|
|
int duration = ast_json_integer_get(json_cur);
|
|
|
|
ast_str_set(&user_prop_str, 0, "%d", duration);
|
|
|
|
ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
|
|
|
|
}
|
|
|
|
|
|
|
|
json_cur = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
manager_event(EVENT_FLAG_CALL, event,
|
|
|
|
"Meetme: %s\r\n"
|
|
|
|
"%s"
|
|
|
|
"%s",
|
|
|
|
conference_num,
|
|
|
|
channel_text ? ast_str_buffer(channel_text) : "",
|
|
|
|
extra_text ? ast_str_buffer(extra_text) : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \brief Build a json object from a status value for inclusion in json extras for meetme_stasis_generate_msg
|
|
|
|
* \since 12.0.0
|
|
|
|
*
|
|
|
|
* \param on if true, then status is on. Otherwise status is off
|
|
|
|
* \retval NULL on failure to allocate the JSON blob.
|
|
|
|
* \retval pointer to the JSON blob if successful.
|
|
|
|
*/
|
|
|
|
static struct ast_json *status_to_json(int on)
|
|
|
|
{
|
|
|
|
struct ast_json *json_object = ast_json_pack("{s: s}",
|
|
|
|
"status", on ? "on" : "off");
|
|
|
|
|
|
|
|
return json_object;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \brief Generate a stasis message associated with a meetme event
|
|
|
|
* \since 12.0.0
|
|
|
|
*
|
2021-11-15 13:18:02 +00:00
|
|
|
* \param meetme_conference The conference responsible for generating this message
|
2013-06-07 15:54:26 +00:00
|
|
|
* \param chan The channel involved in the message (NULL allowed)
|
|
|
|
* \param user The conference user involved in the message (NULL allowed)
|
|
|
|
* \param message_type the type the stasis message being generated
|
|
|
|
* \param extras Additional json fields desired for inclusion
|
|
|
|
*/
|
|
|
|
static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan,
|
|
|
|
struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
|
|
|
|
RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
|
|
|
|
|
|
|
|
json_object = ast_json_pack("{s: s}",
|
|
|
|
"Meetme", meetme_conference->confno);
|
|
|
|
|
|
|
|
if (!json_object) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extras) {
|
|
|
|
ast_json_object_update(json_object, extras);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
struct timeval now = ast_tvnow();
|
|
|
|
long duration = (long)(now.tv_sec - user->jointime);
|
2014-02-21 18:04:54 +00:00
|
|
|
struct ast_json *json_user;
|
|
|
|
struct ast_json *json_user_duration;
|
2013-06-07 15:54:26 +00:00
|
|
|
|
2014-02-21 18:04:54 +00:00
|
|
|
json_user = ast_json_integer_create(user->user_no);
|
|
|
|
if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
|
2013-06-07 15:54:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (duration > 0) {
|
|
|
|
json_user_duration = ast_json_integer_create(duration);
|
2014-02-21 18:04:54 +00:00
|
|
|
if (!json_user_duration
|
|
|
|
|| ast_json_object_set(json_object, "duration", json_user_duration)) {
|
2013-06-07 15:54:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-17 23:29:34 +00:00
|
|
|
if (chan) {
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
}
|
|
|
|
msg = ast_channel_blob_create(chan, message_type, json_object);
|
|
|
|
if (chan) {
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
}
|
2013-06-07 15:54:26 +00:00
|
|
|
|
|
|
|
if (!msg) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stasis_publish(ast_channel_topic(chan), msg);
|
|
|
|
}
|
2004-05-22 04:11:22 +00:00
|
|
|
|
2009-05-21 21:13:09 +00:00
|
|
|
static int admin_exec(struct ast_channel *chan, const char *data);
|
2005-01-22 04:51:30 +00:00
|
|
|
static void *recordthread(void *args);
|
|
|
|
|
2009-06-29 23:50:46 +00:00
|
|
|
static const char *istalking(int x)
|
2005-01-30 03:07:21 +00:00
|
|
|
{
|
|
|
|
if (x > 0)
|
|
|
|
return "(talking)";
|
|
|
|
else if (x < 0)
|
|
|
|
return "(unmonitored)";
|
2017-12-22 14:23:22 +00:00
|
|
|
else
|
2005-01-30 03:07:21 +00:00
|
|
|
return "(not talking)";
|
|
|
|
}
|
2003-02-04 15:48:42 +00:00
|
|
|
|
2005-12-20 10:26:53 +00:00
|
|
|
static int careful_write(int fd, unsigned char *data, int len, int block)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
|
|
|
int res;
|
2004-06-02 16:57:14 +00:00
|
|
|
int x;
|
2005-11-08 21:32:51 +00:00
|
|
|
|
|
|
|
while (len) {
|
2005-12-20 10:26:53 +00:00
|
|
|
if (block) {
|
2008-06-12 17:27:55 +00:00
|
|
|
x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
|
|
|
|
res = ioctl(fd, DAHDI_IOMUX, &x);
|
2005-12-20 10:26:53 +00:00
|
|
|
} else
|
|
|
|
res = 0;
|
2004-06-02 16:57:14 +00:00
|
|
|
if (res >= 0)
|
|
|
|
res = write(fd, data, len);
|
2002-05-13 22:29:39 +00:00
|
|
|
if (res < 1) {
|
|
|
|
if (errno != EAGAIN) {
|
|
|
|
ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
len -= res;
|
|
|
|
data += res;
|
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2002-05-13 22:29:39 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-07 01:39:11 +00:00
|
|
|
static int set_talk_volume(struct ast_conf_user *user, int volume)
|
2005-09-07 01:30:01 +00:00
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
char gain_adjust;
|
2005-09-07 01:30:01 +00:00
|
|
|
|
|
|
|
/* attempt to make the adjustment in the channel driver;
|
|
|
|
if successful, don't adjust in the frame reading routine
|
|
|
|
*/
|
|
|
|
gain_adjust = gain_map[volume + 5];
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2005-09-07 01:39:11 +00:00
|
|
|
return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
|
2005-09-07 01:30:01 +00:00
|
|
|
}
|
|
|
|
|
2005-09-07 02:27:58 +00:00
|
|
|
static int set_listen_volume(struct ast_conf_user *user, int volume)
|
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
char gain_adjust;
|
2005-09-07 02:27:58 +00:00
|
|
|
|
|
|
|
/* attempt to make the adjustment in the channel driver;
|
|
|
|
if successful, don't adjust in the frame reading routine
|
|
|
|
*/
|
|
|
|
gain_adjust = gain_map[volume + 5];
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2005-09-07 02:27:58 +00:00
|
|
|
return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tweak_volume(struct volume *vol, enum volume_action action)
|
2005-09-07 01:30:01 +00:00
|
|
|
{
|
|
|
|
switch (action) {
|
|
|
|
case VOL_UP:
|
2017-12-22 14:23:22 +00:00
|
|
|
switch (vol->desired) {
|
2005-09-07 01:30:01 +00:00
|
|
|
case 5:
|
|
|
|
break;
|
|
|
|
case 0:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired = 2;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
case -2:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired = 0;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired++;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VOL_DOWN:
|
2005-09-07 02:27:58 +00:00
|
|
|
switch (vol->desired) {
|
2005-09-07 01:30:01 +00:00
|
|
|
case -5:
|
|
|
|
break;
|
|
|
|
case 2:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired = 0;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired = -2;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-09-07 02:27:58 +00:00
|
|
|
vol->desired--;
|
2005-09-07 01:30:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-09-07 02:27:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
|
|
|
|
{
|
|
|
|
tweak_volume(&user->talk, action);
|
|
|
|
/* attempt to make the adjustment in the channel driver;
|
|
|
|
if successful, don't adjust in the frame reading routine
|
|
|
|
*/
|
|
|
|
if (!set_talk_volume(user, user->talk.desired))
|
|
|
|
user->talk.actual = 0;
|
|
|
|
else
|
|
|
|
user->talk.actual = user->talk.desired;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
|
|
|
|
{
|
|
|
|
tweak_volume(&user->listen, action);
|
2005-09-07 01:30:01 +00:00
|
|
|
/* attempt to make the adjustment in the channel driver;
|
|
|
|
if successful, don't adjust in the frame reading routine
|
|
|
|
*/
|
2005-09-07 02:27:58 +00:00
|
|
|
if (!set_listen_volume(user, user->listen.desired))
|
|
|
|
user->listen.actual = 0;
|
2005-09-07 01:30:01 +00:00
|
|
|
else
|
2005-09-07 02:27:58 +00:00
|
|
|
user->listen.actual = user->listen.desired;
|
2005-09-07 01:30:01 +00:00
|
|
|
}
|
|
|
|
|
2005-09-07 14:15:37 +00:00
|
|
|
static void reset_volumes(struct ast_conf_user *user)
|
|
|
|
{
|
|
|
|
signed char zero_volume = 0;
|
|
|
|
|
|
|
|
ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
|
|
|
|
ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
|
|
|
|
}
|
|
|
|
|
2006-05-21 15:13:19 +00:00
|
|
|
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
|
|
|
unsigned char *data;
|
|
|
|
int len;
|
2005-11-08 21:32:51 +00:00
|
|
|
int res = -1;
|
|
|
|
|
2012-08-29 21:15:24 +00:00
|
|
|
ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
|
2012-08-29 22:40:18 +00:00
|
|
|
"Conference: %s\r\n"
|
|
|
|
"Marked: %d",
|
|
|
|
ast_channel_name(chan),
|
|
|
|
conf->confno,
|
|
|
|
conf->markedusers);
|
2012-08-29 21:15:24 +00:00
|
|
|
|
2007-08-01 15:39:54 +00:00
|
|
|
if (!ast_check_hangup(chan))
|
2005-02-16 03:50:41 +00:00
|
|
|
res = ast_autoservice_start(chan);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2002-05-13 22:29:39 +00:00
|
|
|
switch(sound) {
|
|
|
|
case ENTER:
|
|
|
|
data = enter;
|
|
|
|
len = sizeof(enter);
|
|
|
|
break;
|
|
|
|
case LEAVE:
|
|
|
|
data = leave;
|
|
|
|
len = sizeof(leave);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
data = NULL;
|
|
|
|
len = 0;
|
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
if (data) {
|
2006-01-30 21:16:43 +00:00
|
|
|
careful_write(conf->fd, data, len, 1);
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
if (!res)
|
2005-02-16 03:50:41 +00:00
|
|
|
ast_autoservice_stop(chan);
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
static int user_no_cmp(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
int *user_no = arg;
|
|
|
|
|
|
|
|
if (user->user_no == *user_no) {
|
|
|
|
return (CMP_MATCH | CMP_STOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_max_cmp(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
int *max_no = arg;
|
|
|
|
|
|
|
|
if (user->user_no > *max_no) {
|
|
|
|
*max_no = user->user_no;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
/*!
|
|
|
|
* \brief Find or create a conference
|
|
|
|
*
|
|
|
|
* \param confno The conference name/number
|
|
|
|
* \param pin The regular user pin
|
|
|
|
* \param pinadmin The admin pin
|
|
|
|
* \param make Make the conf if it doesn't exist
|
|
|
|
* \param dynamic Mark the newly created conference as dynamic
|
|
|
|
* \param refcount How many references to mark on the conference
|
2007-05-31 10:26:55 +00:00
|
|
|
* \param chan The asterisk channel
|
2012-09-21 17:14:59 +00:00
|
|
|
* \param test
|
2007-02-10 00:40:57 +00:00
|
|
|
*
|
|
|
|
* \return A pointer to the conference struct, or NULL if it wasn't found and
|
|
|
|
* make or dynamic were not set.
|
|
|
|
*/
|
2009-06-29 23:50:46 +00:00
|
|
|
static struct ast_conference *build_conf(const char *confno, const char *pin,
|
|
|
|
const char *pinadmin, int make, int dynamic, int refcount,
|
2010-07-09 20:01:01 +00:00
|
|
|
const struct ast_channel *chan, struct ast_test *test)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2004-01-11 06:07:36 +00:00
|
|
|
struct ast_conference *cnf;
|
2008-06-12 17:27:55 +00:00
|
|
|
struct dahdi_confinfo dahdic = { 0, };
|
2007-03-29 17:42:48 +00:00
|
|
|
int confno_int = 0;
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
2017-12-22 14:23:22 +00:00
|
|
|
if (!strcmp(confno, cnf->confno))
|
2002-05-13 22:29:39 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
if (cnf || (!make && !dynamic) || !cap_slin)
|
2007-02-10 00:40:57 +00:00
|
|
|
goto cnfout;
|
|
|
|
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ast_format_cap_append(cap_slin, ast_format_slin, 0);
|
2007-02-10 00:40:57 +00:00
|
|
|
/* Make a new one */
|
2018-11-19 20:10:02 +00:00
|
|
|
cnf = ast_calloc(1, sizeof(*cnf));
|
|
|
|
if (!cnf) {
|
|
|
|
goto cnfout;
|
|
|
|
}
|
|
|
|
|
|
|
|
cnf->usercontainer = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
|
|
|
NULL, user_no_cmp);
|
|
|
|
if (!cnf->usercontainer) {
|
2007-02-10 00:40:57 +00:00
|
|
|
goto cnfout;
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
ast_mutex_init(&cnf->playlock);
|
|
|
|
ast_mutex_init(&cnf->listenlock);
|
2007-09-12 20:47:32 +00:00
|
|
|
cnf->recordthread = AST_PTHREADT_NULL;
|
|
|
|
ast_mutex_init(&cnf->recordthreadlock);
|
2008-11-12 18:32:46 +00:00
|
|
|
cnf->announcethread = AST_PTHREADT_NULL;
|
|
|
|
ast_mutex_init(&cnf->announcethreadlock);
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
|
|
|
|
ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
|
|
|
|
ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
|
2007-07-26 01:13:07 +00:00
|
|
|
|
2008-06-12 17:27:55 +00:00
|
|
|
/* Setup a new dahdi conference */
|
|
|
|
dahdic.confno = -1;
|
|
|
|
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
|
|
|
|
cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
|
|
|
|
if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
|
2010-07-09 20:01:01 +00:00
|
|
|
if (test) {
|
2010-07-10 20:49:30 +00:00
|
|
|
/* if we are creating a conference for a unit test, it is not neccesary
|
|
|
|
* to open a pseudo channel, so, if we fail continue creating
|
|
|
|
* the conference. */
|
2010-12-02 13:20:48 +00:00
|
|
|
ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
|
2010-07-10 20:49:30 +00:00
|
|
|
} else {
|
2010-12-02 13:20:48 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
|
2010-07-10 20:49:30 +00:00
|
|
|
if (cnf->fd >= 0)
|
|
|
|
close(cnf->fd);
|
2011-01-28 22:59:27 +00:00
|
|
|
ao2_ref(cnf->usercontainer, -1);
|
|
|
|
ast_mutex_destroy(&cnf->playlock);
|
|
|
|
ast_mutex_destroy(&cnf->listenlock);
|
|
|
|
ast_mutex_destroy(&cnf->recordthreadlock);
|
|
|
|
ast_mutex_destroy(&cnf->announcethreadlock);
|
2010-07-10 20:49:30 +00:00
|
|
|
ast_free(cnf);
|
|
|
|
cnf = NULL;
|
|
|
|
goto cnfout;
|
2010-07-09 20:01:01 +00:00
|
|
|
}
|
2007-07-26 01:13:07 +00:00
|
|
|
}
|
|
|
|
|
2008-06-12 17:27:55 +00:00
|
|
|
cnf->dahdiconf = dahdic.confno;
|
2007-07-26 01:13:07 +00:00
|
|
|
|
|
|
|
/* Setup a new channel for playback of audio files */
|
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it. Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation. This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first. In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-07 15:47:55 +00:00
|
|
|
cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
if (cnf->chan) {
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ast_set_read_format(cnf->chan, ast_format_slin);
|
|
|
|
ast_set_write_format(cnf->chan, ast_format_slin);
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.chan = 0;
|
|
|
|
dahdic.confno = cnf->dahdiconf;
|
|
|
|
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
|
2012-03-01 22:09:18 +00:00
|
|
|
if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
|
2010-07-09 20:01:01 +00:00
|
|
|
if (test) {
|
|
|
|
ast_test_status_update(test, "Error setting conference on pseudo channel\n");
|
|
|
|
}
|
2007-07-26 01:13:07 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
if (cnf->chan)
|
|
|
|
ast_hangup(cnf->chan);
|
|
|
|
else
|
|
|
|
close(cnf->fd);
|
2011-01-28 22:59:27 +00:00
|
|
|
ao2_ref(cnf->usercontainer, -1);
|
|
|
|
ast_mutex_destroy(&cnf->playlock);
|
|
|
|
ast_mutex_destroy(&cnf->listenlock);
|
|
|
|
ast_mutex_destroy(&cnf->recordthreadlock);
|
|
|
|
ast_mutex_destroy(&cnf->announcethreadlock);
|
2007-06-06 21:20:11 +00:00
|
|
|
ast_free(cnf);
|
2007-02-10 00:40:57 +00:00
|
|
|
cnf = NULL;
|
|
|
|
goto cnfout;
|
|
|
|
}
|
2006-03-13 13:56:34 +00:00
|
|
|
}
|
2007-07-26 01:13:07 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
/* Fill the conference struct */
|
|
|
|
cnf->start = time(NULL);
|
2007-10-17 15:13:51 +00:00
|
|
|
cnf->maxusers = 0x7fffffff;
|
2007-02-10 00:40:57 +00:00
|
|
|
cnf->isdynamic = dynamic ? 1 : 0;
|
2008-06-12 17:27:55 +00:00
|
|
|
ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_INSERT_HEAD(&confs, cnf, list);
|
2007-03-29 17:42:48 +00:00
|
|
|
|
|
|
|
/* Reserve conference number in map */
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
|
2007-03-29 17:42:48 +00:00
|
|
|
conf_map[confno_int] = 1;
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
cnfout:
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ao2_cleanup(cap_slin);
|
2007-02-10 00:40:57 +00:00
|
|
|
if (cnf)
|
2007-02-21 01:05:00 +00:00
|
|
|
ast_atomic_fetchadd_int(&cnf->refcount, refcount);
|
2006-07-01 23:54:43 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
|
|
|
return cnf;
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
static char *complete_confno(const char *word, int state)
|
2007-09-19 23:16:51 +00:00
|
|
|
{
|
2012-09-26 18:23:37 +00:00
|
|
|
struct ast_conference *cnf;
|
|
|
|
char *ret = NULL;
|
|
|
|
int which = 0;
|
2007-09-19 23:16:51 +00:00
|
|
|
int len = strlen(word);
|
2012-09-26 18:23:37 +00:00
|
|
|
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
if (!strncmp(word, cnf->confno, len) && ++which > state) {
|
|
|
|
/* dup before releasing the lock */
|
|
|
|
ret = ast_strdup(cnf->confno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *complete_userno(struct ast_conference *cnf, const char *word, int state)
|
|
|
|
{
|
|
|
|
char usrno[50];
|
|
|
|
struct ao2_iterator iter;
|
|
|
|
struct ast_conf_user *usr;
|
|
|
|
char *ret = NULL;
|
2007-09-19 23:16:51 +00:00
|
|
|
int which = 0;
|
2012-09-26 18:23:37 +00:00
|
|
|
int len = strlen(word);
|
|
|
|
|
|
|
|
iter = ao2_iterator_init(cnf->usercontainer, 0);
|
|
|
|
for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
|
|
|
|
snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
|
|
|
|
if (!strncmp(word, usrno, len) && ++which > state) {
|
|
|
|
ao2_ref(usr, -1);
|
|
|
|
ret = ast_strdup(usrno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ao2_iterator_destroy(&iter);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
|
|
|
|
{
|
|
|
|
if (pos == 2) {
|
|
|
|
return complete_confno(word, state);
|
|
|
|
}
|
|
|
|
if (pos == 3) {
|
|
|
|
int len = strlen(word);
|
|
|
|
char *ret = NULL;
|
|
|
|
char *saved = NULL;
|
|
|
|
char *myline;
|
|
|
|
char *confno;
|
|
|
|
struct ast_conference *cnf;
|
|
|
|
|
|
|
|
if (!strncasecmp(word, "all", len)) {
|
|
|
|
if (state == 0) {
|
|
|
|
return ast_strdup("all");
|
|
|
|
}
|
|
|
|
--state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract the confno from the command line. */
|
|
|
|
myline = ast_strdupa(line);
|
|
|
|
strtok_r(myline, " ", &saved);
|
|
|
|
strtok_r(NULL, " ", &saved);
|
|
|
|
confno = strtok_r(NULL, " ", &saved);
|
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
2012-09-26 18:23:37 +00:00
|
|
|
if (!strcmp(confno, cnf->confno)) {
|
|
|
|
ret = complete_userno(cnf, word, state);
|
2007-09-19 23:16:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
2012-09-26 18:23:37 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
return ret;
|
2012-09-26 18:23:37 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-09-19 23:16:51 +00:00
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
static char *complete_meetmecmd_lock(const char *word, int pos, int state)
|
|
|
|
{
|
|
|
|
if (pos == 2) {
|
|
|
|
return complete_confno(word, state);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (pos == 2) {
|
|
|
|
len = strlen(word);
|
|
|
|
if (!strncasecmp(word, STR_CONCISE, len)) {
|
|
|
|
if (state == 0) {
|
|
|
|
return ast_strdup(STR_CONCISE);
|
2007-09-19 23:16:51 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
--state;
|
2008-10-02 18:02:26 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
|
|
|
|
return complete_confno(word, state);
|
2007-09-19 23:16:51 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
if (pos == 3 && state == 0) {
|
|
|
|
char *saved = NULL;
|
|
|
|
char *myline;
|
|
|
|
char *confno;
|
|
|
|
|
|
|
|
/* Extract the confno from the command line. */
|
|
|
|
myline = ast_strdupa(line);
|
|
|
|
strtok_r(myline, " ", &saved);
|
|
|
|
strtok_r(NULL, " ", &saved);
|
|
|
|
confno = strtok_r(NULL, " ", &saved);
|
|
|
|
|
|
|
|
if (!strcasecmp(confno, STR_CONCISE)) {
|
|
|
|
/* There is nothing valid in this position now. */
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-09-19 23:16:51 +00:00
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
len = strlen(word);
|
|
|
|
if (!strncasecmp(word, STR_CONCISE, len)) {
|
|
|
|
return ast_strdup(STR_CONCISE);
|
|
|
|
}
|
|
|
|
}
|
2007-09-19 23:16:51 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-09-28 23:32:14 +00:00
|
|
|
static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
2006-07-01 23:54:43 +00:00
|
|
|
{
|
2004-05-22 04:11:22 +00:00
|
|
|
/* Process the command */
|
2008-10-02 18:02:26 +00:00
|
|
|
struct ast_conf_user *user;
|
2004-05-22 04:11:22 +00:00
|
|
|
struct ast_conference *cnf;
|
2002-05-13 22:29:39 +00:00
|
|
|
int hr, min, sec;
|
2012-09-26 18:23:37 +00:00
|
|
|
int total = 0;
|
2002-05-13 22:29:39 +00:00
|
|
|
time_t now;
|
2008-03-18 15:43:34 +00:00
|
|
|
#define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
|
|
|
|
#define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
|
2004-05-23 14:19:45 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
2012-09-26 18:23:37 +00:00
|
|
|
e->command = "meetme list";
|
2007-09-19 23:16:51 +00:00
|
|
|
e->usage =
|
2012-09-26 18:23:37 +00:00
|
|
|
"Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
|
|
|
|
" List all conferences or a specific conference.\n";
|
2007-09-19 23:16:51 +00:00
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
2012-09-26 18:23:37 +00:00
|
|
|
return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
|
2007-09-19 23:16:51 +00:00
|
|
|
}
|
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
|
|
|
|
/* List all the conferences */
|
|
|
|
int concise = (a->argc == 3);
|
|
|
|
struct ast_str *marked_users;
|
2008-08-06 17:33:48 +00:00
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
if (!(marked_users = ast_str_create(30))) {
|
|
|
|
return CLI_FAILURE;
|
|
|
|
}
|
2008-08-06 17:33:48 +00:00
|
|
|
|
2005-11-06 04:52:44 +00:00
|
|
|
now = time(NULL);
|
2007-06-05 23:02:11 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2006-01-26 19:33:27 +00:00
|
|
|
if (AST_LIST_EMPTY(&confs)) {
|
2008-08-06 17:33:48 +00:00
|
|
|
if (!concise) {
|
2007-11-06 23:44:39 +00:00
|
|
|
ast_cli(a->fd, "No active MeetMe conferences.\n");
|
2008-08-06 17:33:48 +00:00
|
|
|
}
|
2007-06-05 23:02:11 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2012-09-26 18:23:37 +00:00
|
|
|
ast_free(marked_users);
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SUCCESS;
|
2005-11-06 04:52:44 +00:00
|
|
|
}
|
2008-08-06 17:33:48 +00:00
|
|
|
if (!concise) {
|
2008-03-18 15:43:34 +00:00
|
|
|
ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
|
2008-08-06 17:33:48 +00:00
|
|
|
}
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
2004-05-30 20:38:05 +00:00
|
|
|
hr = (now - cnf->start) / 3600;
|
|
|
|
min = ((now - cnf->start) % 3600) / 60;
|
|
|
|
sec = (now - cnf->start) % 60;
|
2008-08-06 17:33:48 +00:00
|
|
|
if (!concise) {
|
2012-09-26 18:23:37 +00:00
|
|
|
if (cnf->markedusers == 0) {
|
|
|
|
ast_str_set(&marked_users, 0, "N/A ");
|
|
|
|
} else {
|
|
|
|
ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
|
|
|
|
}
|
|
|
|
ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
|
|
|
|
ast_str_buffer(marked_users), hr, min, sec,
|
|
|
|
cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
|
2008-08-06 17:33:48 +00:00
|
|
|
} else {
|
|
|
|
ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
|
|
|
|
cnf->confno,
|
|
|
|
cnf->users,
|
|
|
|
cnf->markedusers,
|
2007-11-06 23:44:39 +00:00
|
|
|
hr, min, sec,
|
2008-08-06 17:33:48 +00:00
|
|
|
cnf->isdynamic,
|
2007-11-06 23:44:39 +00:00
|
|
|
cnf->locked);
|
|
|
|
}
|
2004-01-11 06:07:36 +00:00
|
|
|
|
2008-08-06 17:33:48 +00:00
|
|
|
total += cnf->users;
|
2004-05-23 14:19:45 +00:00
|
|
|
}
|
2007-06-05 23:02:11 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2008-08-06 17:33:48 +00:00
|
|
|
if (!concise) {
|
2007-11-06 23:44:39 +00:00
|
|
|
ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
|
2008-08-06 17:33:48 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
ast_free(marked_users);
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SUCCESS;
|
2012-09-26 18:23:37 +00:00
|
|
|
}
|
|
|
|
if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
|
2010-07-13 17:37:40 +00:00
|
|
|
struct ao2_iterator user_iter;
|
2012-09-26 18:23:37 +00:00
|
|
|
int concise = (a->argc == 4);
|
|
|
|
|
2008-10-02 18:02:26 +00:00
|
|
|
/* List all the users in a conference */
|
|
|
|
if (AST_LIST_EMPTY(&confs)) {
|
|
|
|
if (!concise) {
|
|
|
|
ast_cli(a->fd, "No active MeetMe conferences.\n");
|
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
return CLI_SUCCESS;
|
2008-10-02 18:02:26 +00:00
|
|
|
}
|
|
|
|
/* Find the right conference */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
if (strcmp(cnf->confno, a->argv[2]) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!cnf) {
|
|
|
|
if (!concise)
|
|
|
|
ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
}
|
|
|
|
/* Show all the users */
|
|
|
|
time(&now);
|
2010-07-13 17:37:40 +00:00
|
|
|
user_iter = ao2_iterator_init(cnf->usercontainer, 0);
|
|
|
|
while((user = ao2_iterator_next(&user_iter))) {
|
2008-10-02 18:02:26 +00:00
|
|
|
hr = (now - user->jointime) / 3600;
|
|
|
|
min = ((now - user->jointime) % 3600) / 60;
|
|
|
|
sec = (now - user->jointime) % 60;
|
|
|
|
if (!concise) {
|
|
|
|
ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
|
|
|
|
user->user_no,
|
2012-02-29 16:52:47 +00:00
|
|
|
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
|
|
|
|
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(user->chan),
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
|
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
|
2008-10-02 18:02:26 +00:00
|
|
|
user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
|
|
|
|
user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
|
2017-12-22 14:23:22 +00:00
|
|
|
istalking(user->talking), hr, min, sec);
|
2008-10-02 18:02:26 +00:00
|
|
|
} else {
|
|
|
|
ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
|
|
|
|
user->user_no,
|
2012-02-29 16:52:47 +00:00
|
|
|
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, ""),
|
|
|
|
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, ""),
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(user->chan),
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
|
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
|
2008-10-02 18:02:26 +00:00
|
|
|
user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
|
|
|
|
user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
|
|
|
|
user->talking, hr, min, sec);
|
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_ref(user, -1);
|
2008-10-02 18:02:26 +00:00
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_iterator_destroy(&user_iter);
|
2008-10-02 18:02:26 +00:00
|
|
|
if (!concise) {
|
|
|
|
ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
return CLI_SUCCESS;
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
return CLI_SHOWUSAGE;
|
2008-09-28 23:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
static char *meetme_cmd_helper(struct ast_cli_args *a)
|
2008-09-28 23:32:14 +00:00
|
|
|
{
|
|
|
|
/* Process the command */
|
2012-09-26 18:23:37 +00:00
|
|
|
struct ast_str *cmdline;
|
2008-09-28 23:32:14 +00:00
|
|
|
|
|
|
|
/* Max confno length */
|
|
|
|
if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
|
|
|
|
return CLI_FAILURE;
|
|
|
|
}
|
|
|
|
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */
|
2012-09-26 18:23:37 +00:00
|
|
|
if (strcasestr(a->argv[1], "lock")) {
|
|
|
|
if (strcasecmp(a->argv[1], "lock") == 0) {
|
2004-05-22 04:11:22 +00:00
|
|
|
/* Lock */
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",L");
|
2004-05-22 04:11:22 +00:00
|
|
|
} else {
|
|
|
|
/* Unlock */
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",l");
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
} else if (strcasestr(a->argv[1], "mute")) {
|
2012-09-26 18:23:37 +00:00
|
|
|
if (strcasecmp(a->argv[1], "mute") == 0) {
|
2004-05-22 04:11:22 +00:00
|
|
|
/* Mute */
|
2012-09-26 18:23:37 +00:00
|
|
|
if (strcasecmp(a->argv[3], "all") == 0) {
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",N");
|
2004-10-11 15:40:24 +00:00
|
|
|
} else {
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
|
2004-10-11 15:40:24 +00:00
|
|
|
}
|
2004-05-22 04:11:22 +00:00
|
|
|
} else {
|
|
|
|
/* Unmute */
|
2012-09-26 18:23:37 +00:00
|
|
|
if (strcasecmp(a->argv[3], "all") == 0) {
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",n");
|
2004-10-11 15:40:24 +00:00
|
|
|
} else {
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
|
2004-10-11 15:40:24 +00:00
|
|
|
}
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2012-09-26 18:23:37 +00:00
|
|
|
} else if (strcasecmp(a->argv[1], "kick") == 0) {
|
|
|
|
if (strcasecmp(a->argv[3], "all") == 0) {
|
2004-05-22 04:11:22 +00:00
|
|
|
/* Kick all */
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",K");
|
2004-05-22 04:11:22 +00:00
|
|
|
} else {
|
|
|
|
/* Kick a single user */
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
|
2007-07-31 01:10:47 +00:00
|
|
|
}
|
2008-08-06 17:33:48 +00:00
|
|
|
} else {
|
2012-09-26 18:23:37 +00:00
|
|
|
/*
|
|
|
|
* Should never get here because it is already filtered by the
|
|
|
|
* callers.
|
|
|
|
*/
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_free(cmdline);
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SHOWUSAGE;
|
2008-08-06 17:33:48 +00:00
|
|
|
}
|
2006-10-03 15:53:07 +00:00
|
|
|
|
2008-12-13 08:36:35 +00:00
|
|
|
ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
|
2006-10-03 15:53:07 +00:00
|
|
|
|
2008-12-13 08:36:35 +00:00
|
|
|
admin_exec(NULL, ast_str_buffer(cmdline));
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_free(cmdline);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SUCCESS;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
|
2012-09-26 18:23:37 +00:00
|
|
|
static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "meetme {lock|unlock}";
|
|
|
|
e->usage =
|
|
|
|
"Usage: meetme lock|unlock <confno>\n"
|
|
|
|
" Lock or unlock a conference to new users.\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return complete_meetmecmd_lock(a->word, a->pos, a->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->argc != 3) {
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return meetme_cmd_helper(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "meetme kick";
|
|
|
|
e->usage =
|
|
|
|
"Usage: meetme kick <confno> all|<userno>\n"
|
|
|
|
" Kick a conference or a user in a conference.\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->argc != 4) {
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return meetme_cmd_helper(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "meetme {mute|unmute}";
|
|
|
|
e->usage =
|
|
|
|
"Usage: meetme mute|unmute <confno> all|<userno>\n"
|
|
|
|
" Mute or unmute a conference or a user in a conference.\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->argc != 4) {
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return meetme_cmd_helper(a);
|
|
|
|
}
|
|
|
|
|
2007-02-28 22:09:33 +00:00
|
|
|
static const char *sla_hold_str(unsigned int hold_access)
|
|
|
|
{
|
|
|
|
const char *hold = "Unknown";
|
|
|
|
|
|
|
|
switch (hold_access) {
|
|
|
|
case SLA_HOLD_OPEN:
|
|
|
|
hold = "Open";
|
|
|
|
break;
|
|
|
|
case SLA_HOLD_PRIVATE:
|
|
|
|
hold = "Private";
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hold;
|
|
|
|
}
|
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct ao2_iterator i;
|
|
|
|
struct sla_trunk *trunk;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "sla show trunks";
|
|
|
|
e->usage =
|
|
|
|
"Usage: sla show trunks\n"
|
|
|
|
" This will list all trunks defined in sla.conf\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_cli(a->fd, "\n"
|
2007-02-28 18:21:47 +00:00
|
|
|
"=============================================================\n"
|
|
|
|
"=== Configured SLA Trunks ===================================\n"
|
|
|
|
"=============================================================\n"
|
|
|
|
"===\n");
|
2013-07-10 01:56:15 +00:00
|
|
|
i = ao2_iterator_init(sla_trunks, 0);
|
|
|
|
for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station_ref *station_ref;
|
2007-02-22 23:12:26 +00:00
|
|
|
char ring_timeout[16] = "(none)";
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
ao2_lock(trunk);
|
|
|
|
|
|
|
|
if (trunk->ring_timeout) {
|
2007-02-22 23:12:26 +00:00
|
|
|
snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
|
2007-02-28 19:57:41 +00:00
|
|
|
"=== Trunk Name: %s\n"
|
|
|
|
"=== ==> Device: %s\n"
|
2007-02-28 19:59:26 +00:00
|
|
|
"=== ==> AutoContext: %s\n"
|
|
|
|
"=== ==> RingTimeout: %s\n"
|
|
|
|
"=== ==> BargeAllowed: %s\n"
|
2007-02-28 22:09:33 +00:00
|
|
|
"=== ==> HoldAccess: %s\n"
|
2007-02-28 19:59:26 +00:00
|
|
|
"=== ==> Stations ...\n",
|
2017-12-22 14:23:22 +00:00
|
|
|
trunk->name, trunk->device,
|
|
|
|
S_OR(trunk->autocontext, "(none)"),
|
2007-02-28 19:59:26 +00:00
|
|
|
ring_timeout,
|
2007-02-28 22:09:33 +00:00
|
|
|
trunk->barge_disabled ? "No" : "Yes",
|
|
|
|
sla_hold_str(trunk->hold_access));
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
ao2_unlock(trunk);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_iterator_destroy(&i);
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=============================================================\n\n");
|
2006-09-18 19:54:18 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SUCCESS;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *trunkstate2str(enum sla_trunk_state state)
|
|
|
|
{
|
|
|
|
#define S(e) case e: return # e;
|
|
|
|
switch (state) {
|
|
|
|
S(SLA_TRUNK_STATE_IDLE)
|
|
|
|
S(SLA_TRUNK_STATE_RINGING)
|
|
|
|
S(SLA_TRUNK_STATE_UP)
|
|
|
|
S(SLA_TRUNK_STATE_ONHOLD)
|
2007-03-08 20:56:57 +00:00
|
|
|
S(SLA_TRUNK_STATE_ONHOLD_BYME)
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
return "Uknown State";
|
|
|
|
#undef S
|
|
|
|
}
|
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct ao2_iterator i;
|
|
|
|
struct sla_station *station;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "sla show stations";
|
|
|
|
e->usage =
|
|
|
|
"Usage: sla show stations\n"
|
|
|
|
" This will list all stations defined in sla.conf\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_cli(a->fd, "\n"
|
2007-02-28 18:21:47 +00:00
|
|
|
"=============================================================\n"
|
|
|
|
"=== Configured SLA Stations =================================\n"
|
|
|
|
"=============================================================\n"
|
|
|
|
"===\n");
|
2013-07-10 01:56:15 +00:00
|
|
|
i = ao2_iterator_init(sla_stations, 0);
|
|
|
|
for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2007-02-22 23:12:26 +00:00
|
|
|
char ring_timeout[16] = "(none)";
|
2007-02-28 18:21:47 +00:00
|
|
|
char ring_delay[16] = "(none)";
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
ao2_lock(station);
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
if (station->ring_timeout) {
|
2017-12-22 14:23:22 +00:00
|
|
|
snprintf(ring_timeout, sizeof(ring_timeout),
|
2007-02-22 23:12:26 +00:00
|
|
|
"%u", station->ring_timeout);
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
if (station->ring_delay) {
|
2017-12-22 14:23:22 +00:00
|
|
|
snprintf(ring_delay, sizeof(ring_delay),
|
2007-02-28 18:21:47 +00:00
|
|
|
"%u", station->ring_delay);
|
|
|
|
}
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
|
2007-02-28 18:21:47 +00:00
|
|
|
"=== Station Name: %s\n"
|
|
|
|
"=== ==> Device: %s\n"
|
2007-02-28 22:09:33 +00:00
|
|
|
"=== ==> AutoContext: %s\n"
|
|
|
|
"=== ==> RingTimeout: %s\n"
|
|
|
|
"=== ==> RingDelay: %s\n"
|
|
|
|
"=== ==> HoldAccess: %s\n"
|
|
|
|
"=== ==> Trunks ...\n",
|
|
|
|
station->name, station->device,
|
2017-12-22 14:23:22 +00:00
|
|
|
S_OR(station->autocontext, "(none)"),
|
2007-02-28 22:09:33 +00:00
|
|
|
ring_timeout, ring_delay,
|
|
|
|
sla_hold_str(station->hold_access));
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
if (trunk_ref->ring_timeout) {
|
|
|
|
snprintf(ring_timeout, sizeof(ring_timeout),
|
|
|
|
"%u", trunk_ref->ring_timeout);
|
2017-09-25 12:25:06 +00:00
|
|
|
} else {
|
2007-02-22 23:12:26 +00:00
|
|
|
strcpy(ring_timeout, "(none)");
|
2017-09-25 12:25:06 +00:00
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
if (trunk_ref->ring_delay) {
|
|
|
|
snprintf(ring_delay, sizeof(ring_delay),
|
|
|
|
"%u", trunk_ref->ring_delay);
|
2017-09-25 12:25:06 +00:00
|
|
|
} else {
|
2007-02-28 18:21:47 +00:00
|
|
|
strcpy(ring_delay, "(none)");
|
2017-09-25 12:25:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
|
|
|
|
"=== ==> State: %s\n"
|
|
|
|
"=== ==> RingTimeout: %s\n"
|
|
|
|
"=== ==> RingDelay: %s\n",
|
|
|
|
trunk_ref->trunk->name,
|
|
|
|
trunkstate2str(trunk_ref->state),
|
|
|
|
ring_timeout, ring_delay);
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
|
2007-02-28 18:21:47 +00:00
|
|
|
"===\n");
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
ao2_unlock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_iterator_destroy(&i);
|
2007-09-19 23:16:51 +00:00
|
|
|
ast_cli(a->fd, "============================================================\n"
|
2007-02-22 23:12:26 +00:00
|
|
|
"\n");
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-09-19 23:16:51 +00:00
|
|
|
return CLI_SUCCESS;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2006-09-18 19:54:18 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
static struct ast_cli_entry cli_meetme[] = {
|
2012-09-26 18:23:37 +00:00
|
|
|
AST_CLI_DEFINE(meetme_kick_cmd, "Kick a conference or a user in a conference."),
|
|
|
|
AST_CLI_DEFINE(meetme_show_cmd, "List all conferences or a specific conference."),
|
|
|
|
AST_CLI_DEFINE(meetme_lock_cmd, "Lock or unlock a conference to new users."),
|
|
|
|
AST_CLI_DEFINE(meetme_mute_cmd, "Mute or unmute a conference or a user in a conference."),
|
2007-10-22 20:05:18 +00:00
|
|
|
AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
|
|
|
|
AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
|
2006-09-18 19:54:18 +00:00
|
|
|
};
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2005-11-08 23:19:30 +00:00
|
|
|
static void conf_flush(int fd, struct ast_channel *chan)
|
2005-03-03 23:33:11 +00:00
|
|
|
{
|
|
|
|
int x;
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2005-11-08 23:19:30 +00:00
|
|
|
/* read any frames that may be waiting on the channel
|
|
|
|
and throw them away
|
|
|
|
*/
|
|
|
|
if (chan) {
|
|
|
|
struct ast_frame *f;
|
|
|
|
|
|
|
|
/* when no frames are available, this will wait
|
|
|
|
for 1 millisecond maximum
|
|
|
|
*/
|
2012-11-07 19:15:26 +00:00
|
|
|
while (ast_waitfor(chan, 1) > 0) {
|
2005-11-08 23:19:30 +00:00
|
|
|
f = ast_read(chan);
|
|
|
|
if (f)
|
|
|
|
ast_frfree(f);
|
2006-03-23 20:48:08 +00:00
|
|
|
else /* channel was hung up or something else happened */
|
|
|
|
break;
|
2005-11-08 23:19:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flush any data sitting in the pseudo channel */
|
2008-06-12 17:27:55 +00:00
|
|
|
x = DAHDI_FLUSH_ALL;
|
|
|
|
if (ioctl(fd, DAHDI_FLUSH, &x))
|
2005-03-03 23:33:11 +00:00
|
|
|
ast_log(LOG_WARNING, "Error flushing channel\n");
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2005-03-03 23:33:11 +00:00
|
|
|
}
|
|
|
|
|
2009-08-18 18:57:28 +00:00
|
|
|
/*! \brief Remove the conference from the list and free it.
|
|
|
|
|
2005-07-07 22:36:40 +00:00
|
|
|
We assume that this was called while holding conflock. */
|
|
|
|
static int conf_free(struct ast_conference *conf)
|
|
|
|
{
|
2005-12-20 13:07:02 +00:00
|
|
|
int x;
|
2008-11-12 18:32:46 +00:00
|
|
|
struct announce_listitem *item;
|
2013-06-07 15:54:26 +00:00
|
|
|
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_REMOVE(&confs, conf, list);
|
2013-06-07 15:54:26 +00:00
|
|
|
|
|
|
|
meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
|
2005-07-07 22:36:40 +00:00
|
|
|
|
|
|
|
if (conf->recording == MEETME_RECORD_ACTIVE) {
|
|
|
|
conf->recording = MEETME_RECORD_TERMINATE;
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-07-07 22:36:40 +00:00
|
|
|
while (1) {
|
2007-02-21 01:05:00 +00:00
|
|
|
usleep(1);
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2005-07-07 22:36:40 +00:00
|
|
|
if (conf->recording == MEETME_RECORD_OFF)
|
|
|
|
break;
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-07-07 22:36:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-13 23:10:42 +00:00
|
|
|
for (x = 0; x < AST_FRAME_BITS; x++) {
|
2005-12-20 13:07:02 +00:00
|
|
|
if (conf->transframe[x])
|
|
|
|
ast_frfree(conf->transframe[x]);
|
|
|
|
if (conf->transpath[x])
|
|
|
|
ast_translator_free_path(conf->transpath[x]);
|
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
if (conf->announcethread != AST_PTHREADT_NULL) {
|
|
|
|
ast_mutex_lock(&conf->announcelistlock);
|
|
|
|
conf->announcethread_stop = 1;
|
|
|
|
ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
|
|
|
|
ast_cond_signal(&conf->announcelist_addition);
|
|
|
|
ast_mutex_unlock(&conf->announcelistlock);
|
|
|
|
pthread_join(conf->announcethread, NULL);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2008-11-12 18:32:46 +00:00
|
|
|
while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
|
2010-11-24 23:46:14 +00:00
|
|
|
/* If it's a voicemail greeting file we don't want to remove it */
|
|
|
|
if (!item->vmrec){
|
|
|
|
ast_filedelete(item->namerecloc, NULL);
|
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
ao2_ref(item, -1);
|
|
|
|
}
|
|
|
|
ast_mutex_destroy(&conf->announcelistlock);
|
|
|
|
}
|
2010-07-08 14:48:42 +00:00
|
|
|
|
2005-12-20 23:36:22 +00:00
|
|
|
if (conf->origframe)
|
|
|
|
ast_frfree(conf->origframe);
|
2013-07-17 22:30:28 +00:00
|
|
|
ast_hangup(conf->lchan);
|
|
|
|
ast_hangup(conf->chan);
|
2007-12-03 22:07:57 +00:00
|
|
|
if (conf->fd >= 0)
|
2005-07-07 22:36:40 +00:00
|
|
|
close(conf->fd);
|
2008-04-30 19:21:04 +00:00
|
|
|
if (conf->recordingfilename) {
|
|
|
|
ast_free(conf->recordingfilename);
|
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
if (conf->usercontainer) {
|
|
|
|
ao2_ref(conf->usercontainer, -1);
|
|
|
|
}
|
2008-04-30 19:21:04 +00:00
|
|
|
if (conf->recordingformat) {
|
|
|
|
ast_free(conf->recordingformat);
|
|
|
|
}
|
2007-09-12 20:47:32 +00:00
|
|
|
ast_mutex_destroy(&conf->playlock);
|
|
|
|
ast_mutex_destroy(&conf->listenlock);
|
|
|
|
ast_mutex_destroy(&conf->recordthreadlock);
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_mutex_destroy(&conf->announcethreadlock);
|
2007-06-06 21:20:11 +00:00
|
|
|
ast_free(conf);
|
2005-07-07 22:36:40 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
static void conf_queue_dtmf(const struct ast_conference *conf,
|
2007-03-01 23:44:09 +00:00
|
|
|
const struct ast_conf_user *sender, struct ast_frame *f)
|
2006-07-08 02:24:07 +00:00
|
|
|
{
|
|
|
|
struct ast_conf_user *user;
|
2010-07-13 17:37:40 +00:00
|
|
|
struct ao2_iterator user_iter;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
user_iter = ao2_iterator_init(conf->usercontainer, 0);
|
|
|
|
while ((user = ao2_iterator_next(&user_iter))) {
|
|
|
|
if (user == sender) {
|
|
|
|
ao2_ref(user, -1);
|
2007-02-10 00:40:57 +00:00
|
|
|
continue;
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2007-03-01 23:44:09 +00:00
|
|
|
if (ast_write(user->chan, f) < 0)
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_ref(user, -1);
|
2006-07-08 02:24:07 +00:00
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_iterator_destroy(&user_iter);
|
2006-07-08 02:24:07 +00:00
|
|
|
}
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
static void sla_queue_event_full(enum sla_event_type type,
|
2007-02-22 23:12:26 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
|
2006-07-08 02:24:07 +00:00
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_event *event;
|
2007-02-22 23:12:26 +00:00
|
|
|
|
2008-11-12 19:28:22 +00:00
|
|
|
if (sla.thread == AST_PTHREADT_NULL) {
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(station, -1);
|
|
|
|
ao2_ref(trunk_ref, -1);
|
2008-11-12 19:28:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!(event = ast_calloc(1, sizeof(*event)))) {
|
|
|
|
ao2_ref(station, -1);
|
|
|
|
ao2_ref(trunk_ref, -1);
|
2007-02-22 23:12:26 +00:00
|
|
|
return;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
|
|
|
|
event->type = type;
|
|
|
|
event->trunk_ref = trunk_ref;
|
|
|
|
event->station = station;
|
|
|
|
|
|
|
|
if (!lock) {
|
|
|
|
AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
|
|
|
|
ast_cond_signal(&sla.cond);
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_queue_event_nolock(enum sla_event_type type)
|
|
|
|
{
|
|
|
|
sla_queue_event_full(type, NULL, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_queue_event(enum sla_event_type type)
|
|
|
|
{
|
|
|
|
sla_queue_event_full(type, NULL, NULL, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Queue a SLA event from the conference */
|
2007-03-08 20:56:57 +00:00
|
|
|
static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
|
2007-02-22 23:12:26 +00:00
|
|
|
struct ast_conference *conf)
|
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station *station;
|
|
|
|
struct sla_trunk_ref *trunk_ref = NULL;
|
|
|
|
char *trunk_name;
|
2013-07-10 01:56:15 +00:00
|
|
|
struct ao2_iterator i;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
trunk_name = ast_strdupa(conf->confno);
|
|
|
|
strsep(&trunk_name, "_");
|
|
|
|
if (ast_strlen_zero(trunk_name)) {
|
|
|
|
ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
|
|
|
|
return;
|
2006-07-08 02:24:07 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
i = ao2_iterator_init(sla_stations, 0);
|
|
|
|
while ((station = ao2_iterator_next(&i))) {
|
|
|
|
ao2_lock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
2013-07-10 01:56:15 +00:00
|
|
|
if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
|
|
|
|
ao2_ref(trunk_ref, 1);
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_unlock(station);
|
|
|
|
if (trunk_ref) {
|
|
|
|
/* station reference given to sla_queue_event_full() */
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
ao2_ref(station, -1);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_iterator_destroy(&i);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
if (!trunk_ref) {
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "Trunk not found for event!\n");
|
2007-02-10 00:40:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_queue_event_full(type, trunk_ref, station, 1);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2006-07-08 02:24:07 +00:00
|
|
|
|
2009-08-18 18:57:28 +00:00
|
|
|
/*! \brief Decrement reference counts, as incremented by find_conf() */
|
2007-02-21 01:05:00 +00:00
|
|
|
static int dispose_conf(struct ast_conference *conf)
|
|
|
|
{
|
|
|
|
int res = 0;
|
2007-03-29 17:42:48 +00:00
|
|
|
int confno_int = 0;
|
2007-02-21 01:05:00 +00:00
|
|
|
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
if (ast_atomic_dec_and_test(&conf->refcount)) {
|
2007-03-29 17:42:48 +00:00
|
|
|
/* Take the conference room number out of an inuse state */
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
|
2007-03-29 17:42:48 +00:00
|
|
|
conf_map[confno_int] = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-02-21 01:05:00 +00:00
|
|
|
conf_free(conf);
|
|
|
|
res = 1;
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-06-29 23:50:46 +00:00
|
|
|
static int rt_extend_conf(const char *confno)
|
2008-10-01 23:02:25 +00:00
|
|
|
{
|
|
|
|
char currenttime[32];
|
|
|
|
char endtime[32];
|
|
|
|
struct timeval now;
|
|
|
|
struct ast_tm tm;
|
2008-12-17 21:17:20 +00:00
|
|
|
struct ast_variable *var, *orig_var;
|
2009-07-14 20:14:45 +00:00
|
|
|
char bookid[51];
|
2008-10-01 23:02:25 +00:00
|
|
|
|
|
|
|
if (!extendby) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
now = ast_tvnow();
|
|
|
|
|
|
|
|
ast_localtime(&now, &tm, NULL);
|
|
|
|
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
|
|
|
|
|
|
|
var = ast_load_realtime("meetme", "confno",
|
|
|
|
confno, "startTime<= ", currenttime,
|
|
|
|
"endtime>= ", currenttime, NULL);
|
|
|
|
|
2008-12-17 21:29:30 +00:00
|
|
|
orig_var = var;
|
2008-12-17 21:17:20 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
/* Identify the specific RealTime conference */
|
|
|
|
while (var) {
|
|
|
|
if (!strcasecmp(var->name, "bookid")) {
|
|
|
|
ast_copy_string(bookid, var->value, sizeof(bookid));
|
|
|
|
}
|
|
|
|
if (!strcasecmp(var->name, "endtime")) {
|
|
|
|
ast_copy_string(endtime, var->value, sizeof(endtime));
|
|
|
|
}
|
|
|
|
|
|
|
|
var = var->next;
|
|
|
|
}
|
2008-12-17 21:17:20 +00:00
|
|
|
ast_variables_destroy(orig_var);
|
2008-10-01 23:02:25 +00:00
|
|
|
|
|
|
|
ast_strptime(endtime, DATE_FORMAT, &tm);
|
|
|
|
now = ast_mktime(&tm, NULL);
|
|
|
|
|
|
|
|
now.tv_sec += extendby;
|
|
|
|
|
|
|
|
ast_localtime(&now, &tm, NULL);
|
|
|
|
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
|
|
|
strcat(currenttime, "0"); /* Seconds needs to be 00 */
|
|
|
|
|
|
|
|
var = ast_load_realtime("meetme", "confno",
|
|
|
|
confno, "startTime<= ", currenttime,
|
|
|
|
"endtime>= ", currenttime, NULL);
|
|
|
|
|
|
|
|
/* If there is no conflict with extending the conference, update the DB */
|
|
|
|
if (!var) {
|
|
|
|
ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
|
|
|
|
ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_variables_destroy(var);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-11-21 00:21:38 +00:00
|
|
|
static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
|
|
|
|
{
|
2011-02-04 16:55:39 +00:00
|
|
|
char *original_moh;
|
2007-11-21 00:21:38 +00:00
|
|
|
|
|
|
|
ast_channel_lock(chan);
|
2012-01-24 20:12:09 +00:00
|
|
|
original_moh = ast_strdupa(ast_channel_musicclass(chan));
|
|
|
|
ast_channel_musicclass_set(chan, musicclass);
|
2007-11-21 00:21:38 +00:00
|
|
|
ast_channel_unlock(chan);
|
|
|
|
|
|
|
|
ast_moh_start(chan, original_moh, NULL);
|
|
|
|
|
|
|
|
ast_channel_lock(chan);
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_channel_musicclass_set(chan, original_moh);
|
2007-11-21 00:21:38 +00:00
|
|
|
ast_channel_unlock(chan);
|
|
|
|
}
|
2007-02-21 01:05:00 +00:00
|
|
|
|
2008-11-12 18:32:46 +00:00
|
|
|
static const char *get_announce_filename(enum announcetypes type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case CONF_HASLEFT:
|
|
|
|
return "conf-hasleft";
|
|
|
|
break;
|
|
|
|
case CONF_HASJOIN:
|
|
|
|
return "conf-hasjoin";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *announce_thread(void *data)
|
|
|
|
{
|
|
|
|
struct announce_listitem *current;
|
|
|
|
struct ast_conference *conf = data;
|
|
|
|
int res;
|
|
|
|
char filename[PATH_MAX] = "";
|
|
|
|
AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
|
|
|
|
AST_LIST_HEAD_INIT_NOLOCK(&local_list);
|
|
|
|
|
|
|
|
while (!conf->announcethread_stop) {
|
|
|
|
ast_mutex_lock(&conf->announcelistlock);
|
|
|
|
if (conf->announcethread_stop) {
|
|
|
|
ast_mutex_unlock(&conf->announcelistlock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (AST_LIST_EMPTY(&conf->announcelist))
|
|
|
|
ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
|
|
|
|
|
|
|
|
AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
|
|
|
|
AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
|
|
|
|
|
|
|
|
ast_mutex_unlock(&conf->announcelistlock);
|
|
|
|
if (conf->announcethread_stop) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-11-12 19:11:15 +00:00
|
|
|
for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
|
2011-02-04 16:55:39 +00:00
|
|
|
ast_debug(1, "About to play %s\n", current->namerecloc);
|
2008-11-12 18:32:46 +00:00
|
|
|
if (!ast_fileexists(current->namerecloc, NULL, NULL))
|
|
|
|
continue;
|
|
|
|
if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
|
|
|
|
if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
|
|
|
|
res = ast_waitstream(current->confchan, "");
|
|
|
|
if (!res) {
|
|
|
|
ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
|
|
|
|
if (!ast_streamfile(current->confchan, filename, current->language))
|
|
|
|
ast_waitstream(current->confchan, "");
|
|
|
|
}
|
|
|
|
}
|
2010-11-24 23:46:14 +00:00
|
|
|
if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
|
|
|
|
/* only remove it if it isn't a VM recording file */
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_filedelete(current->namerecloc, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* thread marked to stop, clean up */
|
|
|
|
while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
|
2010-11-24 23:46:14 +00:00
|
|
|
/* only delete if it's a vm rec */
|
|
|
|
if (!current->vmrec) {
|
|
|
|
ast_filedelete(current->namerecloc, NULL);
|
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
ao2_ref(current, -1);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
|
2008-12-09 20:59:54 +00:00
|
|
|
{
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
|
2008-12-09 20:59:54 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
return (ast_channel_state(chan) == AST_STATE_UP);
|
2008-12-09 20:59:54 +00:00
|
|
|
}
|
|
|
|
|
2009-12-11 23:17:09 +00:00
|
|
|
static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
|
|
|
|
{
|
2013-06-07 15:54:26 +00:00
|
|
|
RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
|
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
|
2009-12-11 23:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
|
|
|
|
{
|
|
|
|
int last_talking = user->talking;
|
|
|
|
if (last_talking == talking)
|
|
|
|
return;
|
|
|
|
|
|
|
|
user->talking = talking;
|
|
|
|
|
|
|
|
if (monitor) {
|
|
|
|
/* Check if talking state changed. Take care of -1 which means unmonitored */
|
|
|
|
int was_talking = (last_talking > 0);
|
|
|
|
int now_talking = (talking > 0);
|
|
|
|
if (was_talking != now_talking) {
|
|
|
|
send_talking_event(chan, conf, user, now_talking);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-15 12:50:40 +00:00
|
|
|
static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
/* actual pointer contents of check_admin_arg is irrelevant */
|
|
|
|
|
|
|
|
if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
|
|
|
|
user->adminflags |= ADMINFLAG_HANGUP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
/* actual pointer contents of check_admin_arg is irrelevant */
|
|
|
|
|
|
|
|
if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
|
|
|
|
user->adminflags |= ADMINFLAG_KICKME;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
/* actual pointer contents of check_admin_arg is irrelevant */
|
|
|
|
|
|
|
|
if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
|
|
|
|
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
/* actual pointer contents of check_admin_arg is irrelevant */
|
|
|
|
|
|
|
|
if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
|
|
|
|
user->adminflags |= ADMINFLAG_MUTED;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-22 19:29:50 +00:00
|
|
|
enum menu_modes {
|
|
|
|
MENU_DISABLED = 0,
|
|
|
|
MENU_NORMAL,
|
|
|
|
MENU_ADMIN,
|
|
|
|
MENU_ADMIN_EXTENDED,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
* \brief Processes menu options for the standard menu (accessible through the 's' option for app_meetme)
|
|
|
|
*
|
|
|
|
* \param menu_mode a pointer to the currently active menu_mode.
|
|
|
|
* \param dtmf a pointer to the dtmf value currently being processed against the menu.
|
|
|
|
* \param conf the active conference for which the user has called the menu from.
|
|
|
|
* \param confflags flags used by conf for various options
|
|
|
|
* \param chan ast_channel belonging to the user who called the menu
|
|
|
|
* \param user which meetme conference user invoked the menu
|
|
|
|
*/
|
|
|
|
static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
|
|
|
|
{
|
|
|
|
switch (*dtmf) {
|
|
|
|
case '1': /* Un/Mute */
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
|
|
|
|
/* user can only toggle the self-muted state */
|
|
|
|
user->adminflags ^= ADMINFLAG_SELFMUTED;
|
|
|
|
|
|
|
|
/* they can't override the admin mute state */
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
|
|
|
|
if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2':
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
|
|
|
|
user->adminflags |= ADMINFLAG_T_REQUEST;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user->adminflags & ADMINFLAG_T_REQUEST) {
|
|
|
|
if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '4':
|
|
|
|
tweak_listen_volume(user, VOL_DOWN);
|
|
|
|
break;
|
|
|
|
case '5':
|
|
|
|
/* Extend RT conference */
|
|
|
|
if (rt_schedule) {
|
|
|
|
rt_extend_conf(conf->confno);
|
|
|
|
}
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '6':
|
|
|
|
tweak_listen_volume(user, VOL_UP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '7':
|
|
|
|
tweak_talk_volume(user, VOL_DOWN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '8':
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '9':
|
|
|
|
tweak_talk_volume(user, VOL_UP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
2021-10-31 01:04:41 +00:00
|
|
|
* \brief Processes menu options for the administrator menu (accessible through the 's' option for app_meetme)
|
2013-01-22 19:29:50 +00:00
|
|
|
*
|
|
|
|
* \param menu_mode a pointer to the currently active menu_mode.
|
|
|
|
* \param dtmf a pointer to the dtmf value currently being processed against the menu.
|
|
|
|
* \param conf the active conference for which the user has called the menu from.
|
|
|
|
* \param confflags flags used by conf for various options
|
|
|
|
* \param chan ast_channel belonging to the user who called the menu
|
|
|
|
* \param user which meetme conference user invoked the menu
|
|
|
|
*/
|
|
|
|
static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
|
|
|
|
{
|
|
|
|
switch(*dtmf) {
|
|
|
|
case '1': /* Un/Mute */
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
/* for admin, change both admin and use flags */
|
|
|
|
if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
|
|
|
|
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
|
|
|
|
} else {
|
|
|
|
user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
|
|
|
|
if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2': /* Un/Lock the Conference */
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
if (conf->locked) {
|
|
|
|
conf->locked = 0;
|
|
|
|
if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
conf->locked = 1;
|
|
|
|
if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '3': /* Eject last user */
|
|
|
|
{
|
|
|
|
struct ast_conf_user *usr = NULL;
|
|
|
|
int max_no = 0;
|
|
|
|
ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
usr = ao2_find(conf->usercontainer, &max_no, 0);
|
|
|
|
if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
|
|
|
|
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
usr->adminflags |= ADMINFLAG_KICKME;
|
|
|
|
}
|
|
|
|
ao2_ref(usr, -1);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case '4':
|
|
|
|
tweak_listen_volume(user, VOL_DOWN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '5':
|
|
|
|
/* Extend RT conference */
|
|
|
|
if (rt_schedule) {
|
|
|
|
if (!rt_extend_conf(conf->confno)) {
|
|
|
|
if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_stopstream(chan);
|
|
|
|
}
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '6':
|
|
|
|
tweak_listen_volume(user, VOL_UP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '7':
|
|
|
|
tweak_talk_volume(user, VOL_DOWN);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '8':
|
|
|
|
if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
|
|
|
|
/* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
|
|
|
|
*dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
}
|
|
|
|
*menu_mode = MENU_ADMIN_EXTENDED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '9':
|
|
|
|
tweak_talk_volume(user, VOL_UP);
|
|
|
|
break;
|
|
|
|
default:
|
2016-02-01 19:04:06 +00:00
|
|
|
*menu_mode = MENU_DISABLED;
|
2013-01-22 19:29:50 +00:00
|
|
|
/* Play an error message! */
|
|
|
|
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
* \brief Processes menu options for the extended administrator menu (accessible through option 8 on the administrator menu)
|
|
|
|
*
|
|
|
|
* \param menu_mode a pointer to the currently active menu_mode.
|
|
|
|
* \param dtmf a pointer to the dtmf value currently being processed against the menu.
|
|
|
|
* \param conf the active conference for which the user has called the menu from.
|
|
|
|
* \param confflags flags used by conf for various options
|
|
|
|
* \param chan ast_channel belonging to the user who called the menu
|
|
|
|
* \param user which meetme conference user invoked the menu
|
2021-11-15 13:18:02 +00:00
|
|
|
* \param recordingtmp, recordingtmp_size character buffer which may hold the name of the conference recording file
|
|
|
|
* \param cap_slin
|
2013-01-22 19:29:50 +00:00
|
|
|
*/
|
2014-05-15 22:02:32 +00:00
|
|
|
static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf,
|
|
|
|
struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
|
|
|
|
struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
|
|
|
|
struct ast_format_cap *cap_slin)
|
2013-01-22 19:29:50 +00:00
|
|
|
{
|
|
|
|
int keepplaying;
|
|
|
|
int playednamerec;
|
|
|
|
int res;
|
|
|
|
struct ao2_iterator user_iter;
|
|
|
|
struct ast_conf_user *usr = NULL;
|
|
|
|
|
|
|
|
switch(*dtmf) {
|
|
|
|
case '1': /* *81 Roll call */
|
|
|
|
keepplaying = 1;
|
|
|
|
playednamerec = 0;
|
|
|
|
if (conf->users == 1) {
|
|
|
|
if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (conf->users == 2) {
|
|
|
|
if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (keepplaying) {
|
|
|
|
res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
user_iter = ao2_iterator_init(conf->usercontainer, 0);
|
|
|
|
while((usr = ao2_iterator_next(&user_iter))) {
|
|
|
|
if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
|
|
|
|
if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
playednamerec = 1;
|
|
|
|
}
|
|
|
|
ao2_ref(usr, -1);
|
|
|
|
}
|
|
|
|
ao2_iterator_destroy(&user_iter);
|
|
|
|
if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
|
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
if (res > 0) {
|
|
|
|
keepplaying = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2': /* *82 Eject all non-admins */
|
|
|
|
if (conf->users == 1) {
|
|
|
|
if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
|
|
|
|
}
|
|
|
|
ast_stopstream(chan);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '3': /* *83 (Admin) mute/unmute all non-admins */
|
|
|
|
if(conf->gmuted) {
|
|
|
|
conf->gmuted = 0;
|
|
|
|
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
|
|
|
|
if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
conf->gmuted = 1;
|
|
|
|
ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
|
|
|
|
if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_stopstream(chan);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '4': /* *84 Record conference */
|
|
|
|
if (conf->recording != MEETME_RECORD_ACTIVE) {
|
|
|
|
ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
|
|
|
|
if (!conf->recordingfilename) {
|
|
|
|
const char *var;
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
|
|
|
|
conf->recordingfilename = ast_strdup(var);
|
|
|
|
}
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
|
|
|
|
conf->recordingformat = ast_strdup(var);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
if (!conf->recordingfilename) {
|
2014-01-03 18:31:35 +00:00
|
|
|
snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
|
2013-01-22 19:29:50 +00:00
|
|
|
conf->recordingfilename = ast_strdup(recordingtmp);
|
|
|
|
}
|
|
|
|
if (!conf->recordingformat) {
|
|
|
|
conf->recordingformat = ast_strdup("wav");
|
|
|
|
}
|
|
|
|
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
|
|
|
|
conf->confno, conf->recordingfilename, conf->recordingformat);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_mutex_lock(&conf->recordthreadlock);
|
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it. Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation. This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first. In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-07 15:47:55 +00:00
|
|
|
if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
|
2014-05-15 22:02:32 +00:00
|
|
|
struct dahdi_confinfo dahdic;
|
|
|
|
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ast_set_read_format(conf->lchan, ast_format_slin);
|
|
|
|
ast_set_write_format(conf->lchan, ast_format_slin);
|
2014-05-15 22:02:32 +00:00
|
|
|
dahdic.chan = 0;
|
|
|
|
dahdic.confno = conf->dahdiconf;
|
|
|
|
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
|
|
|
|
if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
|
2013-01-22 19:29:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Error starting listen channel\n");
|
|
|
|
ast_hangup(conf->lchan);
|
|
|
|
conf->lchan = NULL;
|
|
|
|
} else {
|
|
|
|
ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_mutex_unlock(&conf->recordthreadlock);
|
|
|
|
if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '8': /* *88 Exit the menu and return to the conference... without an error message */
|
|
|
|
ast_stopstream(chan);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
ast_stopstream(chan);
|
|
|
|
*menu_mode = MENU_DISABLED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \internal
|
|
|
|
* \brief Processes menu options for the various menu types (accessible through the 's' option for app_meetme)
|
|
|
|
*
|
|
|
|
* \param menu_mode a pointer to the currently active menu_mode.
|
|
|
|
* \param dtmf a pointer to the dtmf value currently being processed against the menu.
|
|
|
|
* \param conf the active conference for which the user has called the menu from.
|
|
|
|
* \param confflags flags used by conf for various options
|
|
|
|
* \param chan ast_channel belonging to the user who called the menu
|
|
|
|
* \param user which meetme conference user invoked the menu
|
2021-11-15 13:18:02 +00:00
|
|
|
* \param recordingtmp,recordingtmp_size character buffer which may hold the name of the conference recording file
|
|
|
|
* \param cap_slin
|
2013-01-22 19:29:50 +00:00
|
|
|
*/
|
2014-05-15 22:02:32 +00:00
|
|
|
static void meetme_menu(enum menu_modes *menu_mode, int *dtmf,
|
|
|
|
struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
|
|
|
|
struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
|
|
|
|
struct ast_format_cap *cap_slin)
|
2013-01-22 19:29:50 +00:00
|
|
|
{
|
|
|
|
switch (*menu_mode) {
|
|
|
|
case MENU_DISABLED:
|
|
|
|
break;
|
|
|
|
case MENU_NORMAL:
|
|
|
|
meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
|
|
|
|
break;
|
|
|
|
case MENU_ADMIN:
|
|
|
|
meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
|
|
|
|
/* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
|
|
|
|
if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MENU_ADMIN_EXTENDED:
|
2014-05-15 22:02:32 +00:00
|
|
|
meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user,
|
|
|
|
recordingtmp, recordingtmp_size, cap_slin);
|
2013-01-22 19:29:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2006-01-13 03:34:31 +00:00
|
|
|
struct ast_conf_user *user = NULL;
|
2002-05-13 22:29:39 +00:00
|
|
|
int fd;
|
2008-06-12 17:27:55 +00:00
|
|
|
struct dahdi_confinfo dahdic, dahdic_empty;
|
2002-05-13 22:29:39 +00:00
|
|
|
struct ast_frame *f;
|
|
|
|
struct ast_channel *c;
|
|
|
|
struct ast_frame fr;
|
|
|
|
int outfd;
|
|
|
|
int ms;
|
|
|
|
int nfds;
|
|
|
|
int res;
|
2008-06-12 17:27:55 +00:00
|
|
|
int retrydahdi;
|
2003-02-04 15:48:42 +00:00
|
|
|
int origfd;
|
2009-09-08 20:28:41 +00:00
|
|
|
int musiconhold = 0, mohtempstopped = 0;
|
2003-02-04 15:48:42 +00:00
|
|
|
int firstpass = 0;
|
2005-03-17 20:29:51 +00:00
|
|
|
int lastmarked = 0;
|
|
|
|
int currentmarked = 0;
|
2003-02-04 15:48:42 +00:00
|
|
|
int ret = -1;
|
2003-06-30 02:00:02 +00:00
|
|
|
int x;
|
2013-01-22 19:29:50 +00:00
|
|
|
enum menu_modes menu_mode = MENU_DISABLED;
|
2007-10-25 18:59:22 +00:00
|
|
|
int talkreq_manager = 0;
|
2004-05-30 20:24:48 +00:00
|
|
|
int using_pseudo = 0;
|
2007-12-13 23:10:42 +00:00
|
|
|
int duration = 20;
|
2006-05-25 21:06:08 +00:00
|
|
|
int sent_event = 0;
|
2007-10-17 15:13:51 +00:00
|
|
|
int checked = 0;
|
|
|
|
int announcement_played = 0;
|
|
|
|
struct timeval now;
|
2007-12-13 23:10:42 +00:00
|
|
|
struct ast_dsp *dsp = NULL;
|
2008-08-10 14:45:25 +00:00
|
|
|
struct ast_app *agi_app;
|
2017-10-30 05:32:32 +00:00
|
|
|
char *agifile;
|
2008-08-10 14:45:25 +00:00
|
|
|
const char *agifiledefault = "conf-background.agi", *tmpvar;
|
2004-07-14 07:22:30 +00:00
|
|
|
char meetmesecs[30] = "";
|
2005-07-10 23:49:57 +00:00
|
|
|
char exitcontext[AST_MAX_CONTEXT] = "";
|
2017-09-25 12:25:06 +00:00
|
|
|
char recordingtmp[AST_MAX_EXTENSION * 2] = "";
|
2006-03-07 01:12:09 +00:00
|
|
|
char members[10] = "";
|
2013-01-22 19:29:50 +00:00
|
|
|
int dtmf = 0, opt_waitmarked_timeout = 0;
|
2006-09-11 22:17:46 +00:00
|
|
|
time_t timeout = 0;
|
2008-07-29 22:22:13 +00:00
|
|
|
struct dahdi_bufferinfo bi;
|
2002-05-13 22:29:39 +00:00
|
|
|
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
|
|
|
|
char *buf = __buf + AST_FRIENDLY_OFFSET;
|
2007-07-03 21:21:51 +00:00
|
|
|
char *exitkeys = NULL;
|
2011-02-04 16:55:39 +00:00
|
|
|
unsigned int calldurationlimit = 0;
|
|
|
|
long timelimit = 0;
|
|
|
|
long play_warning = 0;
|
|
|
|
long warning_freq = 0;
|
|
|
|
const char *warning_sound = NULL;
|
|
|
|
const char *end_sound = NULL;
|
|
|
|
char *parse;
|
|
|
|
long time_left_ms = 0;
|
|
|
|
struct timeval nexteventts = { 0, };
|
|
|
|
int to;
|
2007-12-12 21:22:58 +00:00
|
|
|
int setusercount = 0;
|
2009-09-08 20:28:41 +00:00
|
|
|
int confsilence = 0, totalsilence = 0;
|
2010-11-24 23:46:14 +00:00
|
|
|
char *mailbox, *context;
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
if (!cap_slin) {
|
|
|
|
goto conf_run_cleanup;
|
|
|
|
}
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ast_format_cap_append(cap_slin, ast_format_slin, 0);
|
2007-12-12 21:22:58 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
if (!(user = ao2_alloc(sizeof(*user), NULL))) {
|
2011-02-03 16:22:10 +00:00
|
|
|
goto conf_run_cleanup;
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2004-07-14 07:22:30 +00:00
|
|
|
|
2006-09-11 22:17:46 +00:00
|
|
|
/* Possible timeout waiting for marked user */
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
|
2006-09-11 22:17:46 +00:00
|
|
|
!ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
|
2009-08-10 19:20:57 +00:00
|
|
|
(sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
|
2006-09-11 22:17:46 +00:00
|
|
|
(opt_waitmarked_timeout > 0)) {
|
|
|
|
timeout = time(NULL) + opt_waitmarked_timeout;
|
|
|
|
}
|
2011-02-04 16:55:39 +00:00
|
|
|
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
|
|
|
|
calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
|
2014-07-22 14:22:00 +00:00
|
|
|
ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
|
2011-02-04 16:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
|
|
|
|
char *limit_str, *warning_str, *warnfreq_str;
|
2007-11-06 22:15:32 +00:00
|
|
|
const char *var;
|
2011-02-04 16:55:39 +00:00
|
|
|
|
|
|
|
parse = optargs[OPT_ARG_DURATION_LIMIT];
|
|
|
|
limit_str = strsep(&parse, ":");
|
|
|
|
warning_str = strsep(&parse, ":");
|
|
|
|
warnfreq_str = parse;
|
|
|
|
|
|
|
|
timelimit = atol(limit_str);
|
|
|
|
if (warning_str)
|
|
|
|
play_warning = atol(warning_str);
|
|
|
|
if (warnfreq_str)
|
|
|
|
warning_freq = atol(warnfreq_str);
|
|
|
|
|
|
|
|
if (!timelimit) {
|
|
|
|
timelimit = play_warning = warning_freq = 0;
|
|
|
|
warning_sound = NULL;
|
|
|
|
} else if (play_warning > timelimit) {
|
|
|
|
if (!warning_freq) {
|
|
|
|
play_warning = 0;
|
|
|
|
} else {
|
|
|
|
while (play_warning > timelimit)
|
|
|
|
play_warning -= warning_freq;
|
|
|
|
if (play_warning < 1)
|
|
|
|
play_warning = warning_freq = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-05 13:55:41 +00:00
|
|
|
ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
|
|
|
|
if (play_warning) {
|
|
|
|
ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
|
|
|
|
}
|
|
|
|
if (warning_freq) {
|
|
|
|
ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
|
|
|
|
}
|
|
|
|
|
2008-04-30 19:21:04 +00:00
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
|
|
|
|
var = ast_strdupa(var);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
|
2011-02-04 16:55:39 +00:00
|
|
|
warning_sound = var ? var : "timeleft";
|
|
|
|
|
2008-04-30 19:21:04 +00:00
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
|
|
|
|
var = ast_strdupa(var);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
2011-02-04 16:55:39 +00:00
|
|
|
|
2008-04-30 19:21:04 +00:00
|
|
|
end_sound = var ? var : NULL;
|
2011-02-04 16:55:39 +00:00
|
|
|
|
|
|
|
/* undo effect of S(x) in case they are both used */
|
|
|
|
calldurationlimit = 0;
|
|
|
|
/* more efficient do it like S(x) does since no advanced opts */
|
|
|
|
if (!play_warning && !end_sound && timelimit) {
|
|
|
|
calldurationlimit = timelimit / 1000;
|
|
|
|
timelimit = play_warning = warning_freq = 0;
|
|
|
|
} else {
|
|
|
|
ast_debug(2, "Limit Data for this call:\n");
|
2007-11-06 22:15:32 +00:00
|
|
|
ast_debug(2, "- timelimit = %ld\n", timelimit);
|
2011-02-04 16:55:39 +00:00
|
|
|
ast_debug(2, "- play_warning = %ld\n", play_warning);
|
|
|
|
ast_debug(2, "- warning_freq = %ld\n", warning_freq);
|
|
|
|
ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
|
|
|
|
ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
|
|
|
|
}
|
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
|
2007-07-03 20:34:27 +00:00
|
|
|
/* Get exit keys */
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
|
2007-07-03 20:34:27 +00:00
|
|
|
if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
|
|
|
|
exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
|
|
|
|
else
|
|
|
|
exitkeys = ast_strdupa("#"); /* Default */
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
|
2005-01-22 04:51:30 +00:00
|
|
|
if (!conf->recordingfilename) {
|
2008-04-30 19:21:04 +00:00
|
|
|
const char *var;
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
|
|
|
|
conf->recordingfilename = ast_strdup(var);
|
|
|
|
}
|
|
|
|
if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
|
|
|
|
conf->recordingformat = ast_strdup(var);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
2005-12-20 13:07:02 +00:00
|
|
|
if (!conf->recordingfilename) {
|
2012-01-24 20:12:09 +00:00
|
|
|
snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
|
2008-04-30 19:21:04 +00:00
|
|
|
conf->recordingfilename = ast_strdup(recordingtmp);
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
|
|
|
if (!conf->recordingformat) {
|
2008-04-30 19:21:04 +00:00
|
|
|
conf->recordingformat = ast_strdup("wav");
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
2007-07-26 15:49:18 +00:00
|
|
|
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
|
2005-12-20 13:07:02 +00:00
|
|
|
conf->confno, conf->recordingfilename, conf->recordingformat);
|
2005-01-22 04:51:30 +00:00
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
|
|
|
|
2007-09-12 20:47:32 +00:00
|
|
|
ast_mutex_lock(&conf->recordthreadlock);
|
2009-12-10 17:31:23 +00:00
|
|
|
if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
|
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it. Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation. This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first. In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-07 15:47:55 +00:00
|
|
|
((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ast_set_read_format(conf->lchan, ast_format_slin);
|
|
|
|
ast_set_write_format(conf->lchan, ast_format_slin);
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.chan = 0;
|
|
|
|
dahdic.confno = conf->dahdiconf;
|
|
|
|
dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
|
2012-03-01 22:09:18 +00:00
|
|
|
if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
|
2007-03-05 18:46:59 +00:00
|
|
|
ast_log(LOG_WARNING, "Error starting listen channel\n");
|
|
|
|
ast_hangup(conf->lchan);
|
|
|
|
conf->lchan = NULL;
|
|
|
|
} else {
|
2007-05-26 06:07:38 +00:00
|
|
|
ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
|
2007-03-05 18:46:59 +00:00
|
|
|
}
|
2005-01-22 04:51:30 +00:00
|
|
|
}
|
2007-09-12 20:47:32 +00:00
|
|
|
ast_mutex_unlock(&conf->recordthreadlock);
|
2005-01-22 04:51:30 +00:00
|
|
|
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_mutex_lock(&conf->announcethreadlock);
|
2009-12-10 17:31:23 +00:00
|
|
|
if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
2010-11-24 23:46:14 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_mutex_init(&conf->announcelistlock);
|
|
|
|
AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
|
|
|
|
ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
|
|
|
|
}
|
|
|
|
ast_mutex_unlock(&conf->announcethreadlock);
|
|
|
|
|
2004-11-25 03:23:07 +00:00
|
|
|
time(&user->jointime);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
user->timelimit = timelimit;
|
|
|
|
user->play_warning = play_warning;
|
|
|
|
user->warning_freq = warning_freq;
|
|
|
|
user->warning_sound = warning_sound;
|
2017-12-22 14:23:22 +00:00
|
|
|
user->end_sound = end_sound;
|
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
if (calldurationlimit > 0) {
|
|
|
|
time(&user->kicktime);
|
|
|
|
user->kicktime = user->kicktime + calldurationlimit;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
if (ast_tvzero(user->start_time))
|
|
|
|
user->start_time = ast_tvnow();
|
|
|
|
time_left_ms = user->timelimit;
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
if (user->timelimit) {
|
|
|
|
nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
|
|
|
|
nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
|
|
|
|
}
|
2004-11-25 03:23:07 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
|
2017-12-22 14:23:22 +00:00
|
|
|
/* Sorry, but this conference is locked! */
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
|
2004-05-22 04:11:22 +00:00
|
|
|
ast_waitstream(chan, "");
|
|
|
|
goto outrun;
|
|
|
|
}
|
2005-01-07 07:23:31 +00:00
|
|
|
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_mutex_lock(&conf->playlock);
|
2006-05-13 11:06:34 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
if (rt_schedule && conf->maxusers) {
|
2009-01-15 15:33:18 +00:00
|
|
|
if (conf->users >= conf->maxusers) {
|
2017-12-22 14:23:22 +00:00
|
|
|
/* Sorry, but this confernce has reached the participant limit! */
|
2014-05-15 22:02:32 +00:00
|
|
|
ast_mutex_unlock(&conf->playlock);
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
|
|
|
goto outrun;
|
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_lock(conf->usercontainer);
|
|
|
|
ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
|
|
|
|
user->user_no++;
|
|
|
|
ao2_link(conf->usercontainer, user);
|
|
|
|
ao2_unlock(conf->usercontainer);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2004-05-22 04:11:22 +00:00
|
|
|
user->chan = chan;
|
2009-12-10 17:31:23 +00:00
|
|
|
user->userflags = *confflags;
|
|
|
|
user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
|
2019-03-07 23:15:05 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
|
|
|
|
user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
|
|
|
|
}
|
2005-01-30 03:07:21 +00:00
|
|
|
user->talking = -1;
|
2007-12-12 21:22:58 +00:00
|
|
|
|
|
|
|
ast_mutex_unlock(&conf->playlock);
|
|
|
|
|
2010-11-24 23:46:14 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC))) {
|
2008-04-10 15:10:47 +00:00
|
|
|
char destdir[PATH_MAX];
|
|
|
|
|
|
|
|
snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
|
|
|
|
|
2008-04-13 14:35:43 +00:00
|
|
|
if (ast_mkdir(destdir, 0777) != 0) {
|
2008-04-10 15:10:47 +00:00
|
|
|
ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
|
|
|
|
goto outrun;
|
|
|
|
}
|
|
|
|
|
2010-11-24 23:46:14 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
|
|
|
|
context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
|
|
|
|
mailbox = strsep(&context, "@");
|
|
|
|
|
|
|
|
if (ast_strlen_zero(mailbox)) {
|
|
|
|
/* invalid input, clear the v flag*/
|
|
|
|
ast_clear_flag64(confflags,CONFFLAG_INTROUSER_VMREC);
|
|
|
|
ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
|
|
|
|
} else {
|
|
|
|
if (ast_strlen_zero(context)) {
|
|
|
|
context = "default";
|
|
|
|
}
|
|
|
|
/* if there is no mailbox we don't need to do this logic */
|
|
|
|
snprintf(user->namerecloc, sizeof(user->namerecloc),
|
|
|
|
"%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
|
|
|
|
|
|
|
|
/* if the greeting doesn't exist then use the temp file method instead, clear flag v */
|
|
|
|
if (!ast_fileexists(user->namerecloc, NULL, NULL)){
|
|
|
|
snprintf(user->namerecloc, sizeof(user->namerecloc),
|
|
|
|
"%s/meetme-username-%s-%d", destdir,
|
|
|
|
conf->confno, user->user_no);
|
|
|
|
ast_clear_flag64(confflags, CONFFLAG_INTROUSER_VMREC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
snprintf(user->namerecloc, sizeof(user->namerecloc),
|
|
|
|
"%s/meetme-username-%s-%d", destdir,
|
|
|
|
conf->confno, user->user_no);
|
|
|
|
}
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
|
Merged revisions 337120 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/10
................
r337120 | mjordan | 2011-09-20 17:49:36 -0500 (Tue, 20 Sep 2011) | 28 lines
Merged revisions 337118 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8
........
r337118 | mjordan | 2011-09-20 17:38:54 -0500 (Tue, 20 Sep 2011) | 21 lines
Fix for incorrect voicemail duration in external notifications
This patch fixes an issue where the voicemail duration was being reported
with a duration significantly less than the actual sound file duration.
Voicemails that contained mostly silence were reporting the duration of
only the sound in the file, as opposed to the duration of the file with
the silence. This patch fixes this by having two durations reported in
the __ast_play_and_record family of functions - the sound_duration and the
actual duration of the file. The sound_duration, which is optional, now
reports the duration of the sound in the file, while the actual full duration
of the file is reported in the duration parameter. This allows the voicemail
applications to use the sound_duration for minimum duration checking, while
reporting the full duration to external parties if the voicemail is kept.
(issue ASTERISK-2234)
(closes issue ASTERISK-16981)
Reported by: Mary Ciuciu, Byron Clark, Brad House, Karsten Wemheuer, KevinH
Tested by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/1443
........
................
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@337124 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-09-20 23:02:25 +00:00
|
|
|
res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
|
2010-11-24 23:46:14 +00:00
|
|
|
else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
|
2007-12-12 21:22:58 +00:00
|
|
|
res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
|
|
|
|
if (res == -1)
|
|
|
|
goto outrun;
|
2010-11-24 23:46:14 +00:00
|
|
|
|
2007-12-12 21:22:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ast_mutex_lock(&conf->playlock);
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
|
2007-12-12 21:22:58 +00:00
|
|
|
conf->markedusers++;
|
2005-11-08 21:32:51 +00:00
|
|
|
conf->users++;
|
2007-10-17 15:13:51 +00:00
|
|
|
if (rt_log_members) {
|
|
|
|
/* Update table */
|
|
|
|
snprintf(members, sizeof(members), "%d", conf->users);
|
2008-06-09 22:51:59 +00:00
|
|
|
ast_realtime_require_field("meetme",
|
|
|
|
"confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
|
|
|
|
"members", RQ_UINTEGER1, strlen(members),
|
|
|
|
NULL);
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
|
|
|
|
}
|
2007-12-12 21:22:58 +00:00
|
|
|
setusercount = 1;
|
|
|
|
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
/* This device changed state now - if this is the first user */
|
|
|
|
if (conf->users == 1)
|
2013-01-02 18:11:59 +00:00
|
|
|
ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_mutex_unlock(&conf->playlock);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2007-05-02 23:50:07 +00:00
|
|
|
/* return the unique ID of the conference */
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
|
2008-04-30 19:21:04 +00:00
|
|
|
ast_channel_lock(chan);
|
2008-08-10 14:45:25 +00:00
|
|
|
if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
|
|
|
|
ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
|
2012-02-13 17:27:06 +00:00
|
|
|
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
|
|
|
ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
|
2008-04-30 19:21:04 +00:00
|
|
|
} else {
|
2012-02-13 17:27:06 +00:00
|
|
|
ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
|
2008-04-30 19:21:04 +00:00
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
2004-08-03 06:31:20 +00:00
|
|
|
}
|
2005-01-07 07:23:31 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
/* Play an arbitrary intro message */
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
|
|
|
|
!ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
|
|
|
|
if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2003-02-04 15:48:42 +00:00
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2012-02-06 16:38:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
|
2005-11-08 21:32:51 +00:00
|
|
|
int keepplaying = 1;
|
2005-03-20 03:04:46 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
if (conf->users == 2) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
|
2005-03-20 03:04:46 +00:00
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
2006-09-28 16:19:22 +00:00
|
|
|
ast_stopstream(chan);
|
2005-03-20 03:04:46 +00:00
|
|
|
if (res > 0)
|
2007-12-13 23:10:42 +00:00
|
|
|
keepplaying = 0;
|
2005-03-20 03:04:46 +00:00
|
|
|
else if (res == -1)
|
|
|
|
goto outrun;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
} else {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
|
2005-03-20 03:04:46 +00:00
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
2006-09-28 16:19:22 +00:00
|
|
|
ast_stopstream(chan);
|
2005-03-20 03:04:46 +00:00
|
|
|
if (res > 0)
|
2007-12-13 23:10:42 +00:00
|
|
|
keepplaying = 0;
|
2005-03-20 03:04:46 +00:00
|
|
|
else if (res == -1)
|
|
|
|
goto outrun;
|
|
|
|
}
|
|
|
|
if (keepplaying) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
|
2005-03-20 03:04:46 +00:00
|
|
|
if (res > 0)
|
2007-12-13 23:10:42 +00:00
|
|
|
keepplaying = 0;
|
2005-03-20 03:04:46 +00:00
|
|
|
else if (res == -1)
|
|
|
|
goto outrun;
|
|
|
|
}
|
2012-01-24 20:12:09 +00:00
|
|
|
if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
|
2005-03-20 03:04:46 +00:00
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
2006-09-28 16:19:22 +00:00
|
|
|
ast_stopstream(chan);
|
2005-03-20 03:04:46 +00:00
|
|
|
if (res > 0)
|
2007-12-13 23:10:42 +00:00
|
|
|
keepplaying = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
else if (res == -1)
|
2005-03-20 03:04:46 +00:00
|
|
|
goto outrun;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
|
2008-12-09 20:59:54 +00:00
|
|
|
/* We're leaving this alone until the state gets changed to up */
|
|
|
|
ast_indicate(chan, -1);
|
|
|
|
}
|
2006-02-13 17:50:53 +00:00
|
|
|
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
if (ast_set_write_format(chan, ast_format_slin) < 0) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
|
2004-06-14 03:12:46 +00:00
|
|
|
goto outrun;
|
|
|
|
}
|
2003-06-30 02:00:02 +00:00
|
|
|
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
if (ast_set_read_format(chan, ast_format_slin) < 0) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
|
2004-06-14 03:12:46 +00:00
|
|
|
goto outrun;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2009-10-21 15:21:30 +00:00
|
|
|
/* Reduce background noise from each participant */
|
2017-12-29 08:57:17 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
|
2009-10-21 15:21:30 +00:00
|
|
|
ast_func_write(chan, "DENOISE(rx)", "on");
|
|
|
|
}
|
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan) || ast_channel_monitor(chan)) ? 1 : 0);
|
2008-06-12 17:27:55 +00:00
|
|
|
user->dahdichannel = !retrydahdi;
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdiretry:
|
2012-03-01 22:09:18 +00:00
|
|
|
origfd = ast_channel_fd(chan, 0);
|
2008-06-12 17:27:55 +00:00
|
|
|
if (retrydahdi) {
|
2009-02-16 21:40:40 +00:00
|
|
|
/* open pseudo in non-blocking mode */
|
|
|
|
fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
|
2002-05-13 22:29:39 +00:00
|
|
|
if (fd < 0) {
|
2010-12-02 13:20:48 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
|
2002-05-13 22:29:39 +00:00
|
|
|
goto outrun;
|
|
|
|
}
|
2004-05-30 20:24:48 +00:00
|
|
|
using_pseudo = 1;
|
2002-05-13 22:29:39 +00:00
|
|
|
/* Setup buffering information */
|
|
|
|
memset(&bi, 0, sizeof(bi));
|
2007-12-13 23:10:42 +00:00
|
|
|
bi.bufsize = CONF_SIZE / 2;
|
2008-06-12 17:27:55 +00:00
|
|
|
bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
|
|
|
|
bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
|
2005-11-08 23:19:30 +00:00
|
|
|
bi.numbufs = audio_buffers;
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
|
2002-05-13 22:29:39 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
|
|
|
}
|
2004-06-14 03:12:46 +00:00
|
|
|
x = 1;
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
|
2004-06-14 03:12:46 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
2003-06-30 02:00:02 +00:00
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
nfds = 1;
|
|
|
|
} else {
|
|
|
|
/* XXX Make sure we're not running on a pseudo channel XXX */
|
2012-03-01 22:09:18 +00:00
|
|
|
fd = ast_channel_fd(chan, 0);
|
2002-05-13 22:29:39 +00:00
|
|
|
nfds = 0;
|
|
|
|
}
|
2008-06-12 17:27:55 +00:00
|
|
|
memset(&dahdic, 0, sizeof(dahdic));
|
|
|
|
memset(&dahdic_empty, 0, sizeof(dahdic_empty));
|
2002-05-13 22:29:39 +00:00
|
|
|
/* Check to see if we're in a conference... */
|
2011-02-04 16:55:39 +00:00
|
|
|
dahdic.chan = 0;
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
|
2002-05-13 22:29:39 +00:00
|
|
|
ast_log(LOG_WARNING, "Error getting conference\n");
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
|
|
|
}
|
2008-06-12 17:27:55 +00:00
|
|
|
if (dahdic.confmode) {
|
2002-05-13 22:29:39 +00:00
|
|
|
/* Whoa, already in a conference... Retry... */
|
2008-06-12 17:27:55 +00:00
|
|
|
if (!retrydahdi) {
|
|
|
|
ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
|
|
|
|
retrydahdi = 1;
|
|
|
|
goto dahdiretry;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
2008-06-12 17:27:55 +00:00
|
|
|
memset(&dahdic, 0, sizeof(dahdic));
|
2002-05-13 22:29:39 +00:00
|
|
|
/* Add us to the conference */
|
2011-02-04 16:55:39 +00:00
|
|
|
dahdic.chan = 0;
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confno = conf->dahdiconf;
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
|
2010-11-24 23:46:14 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) || ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)) && conf->users > 1) {
|
2008-11-12 18:32:46 +00:00
|
|
|
struct announce_listitem *item;
|
|
|
|
if (!(item = ao2_alloc(sizeof(*item), NULL)))
|
2011-01-29 18:10:34 +00:00
|
|
|
goto outrun;
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
|
2008-11-12 18:32:46 +00:00
|
|
|
item->confchan = conf->chan;
|
|
|
|
item->confusers = conf->users;
|
2010-11-24 23:46:14 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
|
|
|
|
item->vmrec = 1;
|
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
item->announcetype = CONF_HASJOIN;
|
|
|
|
ast_mutex_lock(&conf->announcelistlock);
|
|
|
|
ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
|
|
|
|
AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
|
|
|
|
ast_cond_signal(&conf->announcelist_addition);
|
|
|
|
ast_mutex_unlock(&conf->announcelistlock);
|
|
|
|
|
|
|
|
while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
|
|
|
|
;
|
2005-01-07 07:23:31 +00:00
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
ao2_ref(item, -1);
|
2005-01-07 07:23:31 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 18:57:02 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF;
|
2009-12-10 17:31:23 +00:00
|
|
|
else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
|
2009-12-10 17:31:23 +00:00
|
|
|
else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
|
2011-02-04 16:55:39 +00:00
|
|
|
else
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
|
2003-02-04 15:48:42 +00:00
|
|
|
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2002-05-13 22:29:39 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
|
|
|
}
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
|
2004-05-13 19:02:47 +00:00
|
|
|
|
2006-05-25 21:06:08 +00:00
|
|
|
if (!sent_event) {
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
|
2006-05-25 21:06:08 +00:00
|
|
|
sent_event = 1;
|
|
|
|
}
|
2004-05-13 19:02:47 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
|
|
|
|
!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
|
2003-02-04 15:48:42 +00:00
|
|
|
firstpass = 1;
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
|
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
|
|
|
|
(conf->markedusers >= 1))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
conf_play(chan, conf, ENTER);
|
2009-12-10 17:31:23 +00:00
|
|
|
}
|
2003-02-04 15:48:42 +00:00
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2005-11-08 23:19:30 +00:00
|
|
|
conf_flush(fd, chan);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2010-07-29 16:47:23 +00:00
|
|
|
if (dsp)
|
|
|
|
ast_dsp_free(dsp);
|
|
|
|
|
2009-09-08 20:28:41 +00:00
|
|
|
if (!(dsp = ast_dsp_new())) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
|
2003-09-28 21:18:51 +00:00
|
|
|
/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
|
2005-11-08 21:32:51 +00:00
|
|
|
or use default filename of conf-background.agi */
|
2003-09-28 21:18:51 +00:00
|
|
|
|
2008-04-30 19:21:04 +00:00
|
|
|
ast_channel_lock(chan);
|
2008-08-10 14:45:25 +00:00
|
|
|
if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
|
|
|
|
agifile = ast_strdupa(tmpvar);
|
2008-04-30 19:21:04 +00:00
|
|
|
} else {
|
|
|
|
agifile = ast_strdupa(agifiledefault);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2008-06-12 17:27:55 +00:00
|
|
|
if (user->dahdichannel) {
|
|
|
|
/* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
|
2003-09-28 21:18:51 +00:00
|
|
|
x = 1;
|
2005-11-08 21:32:51 +00:00
|
|
|
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
|
2003-09-28 21:18:51 +00:00
|
|
|
}
|
|
|
|
/* Find a pointer to the agi app and execute the script */
|
2008-08-10 14:45:25 +00:00
|
|
|
agi_app = pbx_findapp("agi");
|
|
|
|
if (agi_app) {
|
|
|
|
ret = pbx_exec(chan, agi_app, agifile);
|
2003-09-28 21:18:51 +00:00
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Could not find application (agi)\n");
|
|
|
|
ret = -2;
|
|
|
|
}
|
2008-06-12 17:27:55 +00:00
|
|
|
if (user->dahdichannel) {
|
|
|
|
/* Remove CONFMUTE mode on DAHDI channel */
|
2003-09-28 21:18:51 +00:00
|
|
|
x = 0;
|
2005-11-08 21:32:51 +00:00
|
|
|
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
|
2004-05-30 20:38:05 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-08-13 20:36:51 +00:00
|
|
|
int lastusers = conf->users;
|
2009-12-10 17:31:23 +00:00
|
|
|
if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
/* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
|
2004-05-30 20:38:05 +00:00
|
|
|
x = 1;
|
2005-11-08 21:32:51 +00:00
|
|
|
ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
|
2013-01-22 19:29:50 +00:00
|
|
|
}
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
for (;;) {
|
2005-09-07 01:30:01 +00:00
|
|
|
int menu_was_active = 0;
|
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
outfd = -1;
|
|
|
|
ms = -1;
|
2007-12-13 23:10:42 +00:00
|
|
|
now = ast_tvnow();
|
2007-11-06 22:15:32 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
if (rt_schedule && conf->endtime) {
|
|
|
|
char currenttime[32];
|
2008-10-02 16:42:30 +00:00
|
|
|
long localendtime = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
int extended = 0;
|
|
|
|
struct ast_tm tm;
|
|
|
|
struct ast_variable *var, *origvar;
|
|
|
|
struct timeval tmp;
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
if (now.tv_sec % 60 == 0) {
|
|
|
|
if (!checked) {
|
2008-10-01 23:02:25 +00:00
|
|
|
ast_localtime(&now, &tm, NULL);
|
|
|
|
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
|
|
|
var = origvar = ast_load_realtime("meetme", "confno",
|
|
|
|
conf->confno, "starttime <=", currenttime,
|
|
|
|
"endtime >=", currenttime, NULL);
|
|
|
|
|
|
|
|
for ( ; var; var = var->next) {
|
|
|
|
if (!strcasecmp(var->name, "endtime")) {
|
2008-10-08 12:15:06 +00:00
|
|
|
struct ast_tm endtime_tm;
|
|
|
|
ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
|
|
|
|
tmp = ast_mktime(&endtime_tm, NULL);
|
2008-10-01 23:02:25 +00:00
|
|
|
localendtime = tmp.tv_sec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_variables_destroy(origvar);
|
|
|
|
|
|
|
|
/* A conference can be extended from the
|
|
|
|
Admin/User menu or by an external source */
|
|
|
|
if (localendtime > conf->endtime){
|
|
|
|
conf->endtime = localendtime;
|
|
|
|
extended = 1;
|
|
|
|
}
|
|
|
|
|
2008-10-08 22:32:37 +00:00
|
|
|
if (conf->endtime && (now.tv_sec >= conf->endtime)) {
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_verbose("Quitting time...\n");
|
|
|
|
goto outrun;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!announcement_played && conf->endalert) {
|
2008-10-08 22:32:37 +00:00
|
|
|
if (now.tv_sec + conf->endalert >= conf->endtime) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
|
|
|
|
if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2010-09-08 21:00:32 +00:00
|
|
|
if (musiconhold) {
|
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
announcement_played = 1;
|
|
|
|
}
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
|
|
|
|
if (extended) {
|
|
|
|
announcement_played = 0;
|
|
|
|
}
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
checked = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
checked = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
if (user->kicktime && (user->kicktime <= now.tv_sec)) {
|
2011-01-29 17:57:01 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
ret = -1;
|
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
break;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
to = -1;
|
|
|
|
if (user->timelimit) {
|
|
|
|
int minutes = 0, seconds = 0, remain = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
to = ast_tvdiff_ms(nexteventts, now);
|
2008-10-01 23:02:25 +00:00
|
|
|
if (to < 0) {
|
2007-11-06 22:15:32 +00:00
|
|
|
to = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
|
2008-10-01 23:02:25 +00:00
|
|
|
if (time_left_ms < to) {
|
2007-11-06 22:15:32 +00:00
|
|
|
to = time_left_ms;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
if (time_left_ms <= 0) {
|
2017-12-22 14:23:22 +00:00
|
|
|
if (user->end_sound) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
|
2007-11-06 22:15:32 +00:00
|
|
|
res = ast_waitstream(chan, "");
|
|
|
|
}
|
2011-05-04 02:39:11 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
ret = -1;
|
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
if (!to) {
|
2017-12-22 14:23:22 +00:00
|
|
|
if (time_left_ms >= 5000) {
|
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
remain = (time_left_ms + 500) / 1000;
|
|
|
|
if (remain / 60 >= 1) {
|
|
|
|
minutes = remain / 60;
|
|
|
|
seconds = remain % 60;
|
|
|
|
} else {
|
|
|
|
seconds = remain;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-11-06 22:15:32 +00:00
|
|
|
/* force the time left to round up if appropriate */
|
2007-12-13 23:10:42 +00:00
|
|
|
if (user->warning_sound && user->play_warning) {
|
|
|
|
if (!strcmp(user->warning_sound, "timeleft")) {
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
|
2007-11-06 22:15:32 +00:00
|
|
|
res = ast_waitstream(chan, "");
|
|
|
|
if (minutes) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
|
|
|
|
res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
|
2007-11-06 22:15:32 +00:00
|
|
|
res = ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
if (seconds) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
|
|
|
|
res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
|
2007-11-06 22:15:32 +00:00
|
|
|
res = ast_waitstream(chan, "");
|
|
|
|
}
|
|
|
|
} else {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
|
2007-11-06 22:15:32 +00:00
|
|
|
res = ast_waitstream(chan, "");
|
|
|
|
}
|
2010-09-08 21:00:32 +00:00
|
|
|
if (musiconhold) {
|
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
if (user->warning_freq) {
|
2007-11-06 22:15:32 +00:00
|
|
|
nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2007-11-06 22:15:32 +00:00
|
|
|
nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-11-06 22:15:32 +00:00
|
|
|
}
|
|
|
|
}
|
2006-09-11 22:17:46 +00:00
|
|
|
|
2007-12-13 23:10:42 +00:00
|
|
|
now = ast_tvnow();
|
2008-10-01 23:02:25 +00:00
|
|
|
if (timeout && now.tv_sec >= timeout) {
|
2011-01-29 17:57:01 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
ret = -1;
|
|
|
|
}
|
2006-09-11 22:17:46 +00:00
|
|
|
break;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2006-09-11 22:17:46 +00:00
|
|
|
|
2005-09-07 01:30:01 +00:00
|
|
|
/* if we have just exited from the menu, and the user had a channel-driver
|
|
|
|
volume adjustment, restore it
|
|
|
|
*/
|
2013-01-22 19:29:50 +00:00
|
|
|
if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
|
2005-09-07 02:27:58 +00:00
|
|
|
set_talk_volume(user, user->listen.desired);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-09-07 01:30:01 +00:00
|
|
|
|
2013-01-22 19:29:50 +00:00
|
|
|
menu_was_active = menu_mode;
|
2005-09-07 01:30:01 +00:00
|
|
|
|
2005-03-17 20:29:51 +00:00
|
|
|
currentmarked = conf->markedusers;
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
|
|
|
ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
|
|
|
|
ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
|
2005-11-08 21:32:51 +00:00
|
|
|
lastmarked == 0) {
|
2005-03-17 20:29:51 +00:00
|
|
|
if (currentmarked == 1 && conf->users > 1) {
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
|
2005-03-17 20:29:51 +00:00
|
|
|
if (conf->users - 1 == 1) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
} else {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
}
|
|
|
|
|
2004-05-30 20:38:05 +00:00
|
|
|
/* Update the struct with the actual confflags */
|
2009-12-10 17:31:23 +00:00
|
|
|
user->userflags = *confflags;
|
2007-12-13 23:10:42 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
|
2007-12-13 23:10:42 +00:00
|
|
|
if (currentmarked == 0) {
|
2005-03-17 20:29:51 +00:00
|
|
|
if (lastmarked != 0) {
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
2006-10-18 22:19:57 +00:00
|
|
|
ret = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
break;
|
2006-10-18 22:19:57 +00:00
|
|
|
} else {
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF;
|
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
|
2007-11-21 00:21:38 +00:00
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
2005-03-17 20:29:51 +00:00
|
|
|
musiconhold = 1;
|
|
|
|
}
|
2007-12-13 23:10:42 +00:00
|
|
|
} else if (currentmarked >= 1 && lastmarked == 0) {
|
2006-09-16 05:43:54 +00:00
|
|
|
/* Marked user entered, so cancel timeout */
|
|
|
|
timeout = 0;
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
|
2009-12-10 17:31:23 +00:00
|
|
|
} else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
close(fd);
|
|
|
|
goto outrun;
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_moh_stop(chan);
|
|
|
|
musiconhold = 0;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
2009-12-10 17:31:23 +00:00
|
|
|
!ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
|
2005-03-17 20:29:51 +00:00
|
|
|
ast_waitstream(chan, "");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
conf_play(chan, conf, ENTER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-23 14:19:45 +00:00
|
|
|
/* trying to add moh for single person conf */
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
|
2004-05-23 14:19:45 +00:00
|
|
|
if (conf->users == 1) {
|
2007-11-21 00:21:38 +00:00
|
|
|
if (!musiconhold) {
|
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
2004-05-23 14:19:45 +00:00
|
|
|
musiconhold = 1;
|
2017-12-22 14:23:22 +00:00
|
|
|
}
|
2004-05-23 14:19:45 +00:00
|
|
|
} else {
|
|
|
|
if (musiconhold) {
|
|
|
|
ast_moh_stop(chan);
|
|
|
|
musiconhold = 0;
|
|
|
|
}
|
2003-11-04 21:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2004-05-30 20:38:05 +00:00
|
|
|
/* Leave if the last marked user left */
|
2009-12-10 17:31:23 +00:00
|
|
|
if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
2006-10-18 22:19:57 +00:00
|
|
|
ret = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2006-10-18 22:19:57 +00:00
|
|
|
ret = -1;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2004-05-30 20:38:05 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-08-13 20:36:51 +00:00
|
|
|
|
|
|
|
/* Throw a TestEvent if a user exit did not cause this user to leave the conference */
|
|
|
|
if (conf->users != lastusers) {
|
|
|
|
if (conf->users < lastusers) {
|
|
|
|
ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
|
|
|
|
}
|
|
|
|
lastusers = conf->users;
|
|
|
|
}
|
|
|
|
|
2006-05-23 16:35:46 +00:00
|
|
|
/* Check if my modes have changed */
|
|
|
|
|
|
|
|
/* If I should be muted but am still talker, mute me */
|
2008-06-12 17:27:55 +00:00
|
|
|
if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
|
2013-06-07 15:54:26 +00:00
|
|
|
RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode ^= DAHDI_CONF_TALKER;
|
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2006-05-23 16:35:46 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
|
|
|
|
ret = -1;
|
2004-05-30 20:38:05 +00:00
|
|
|
break;
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2006-05-23 16:35:46 +00:00
|
|
|
|
2009-12-11 23:17:09 +00:00
|
|
|
/* Indicate user is not talking anymore - change him to unmonitored state */
|
|
|
|
if (ast_test_flag64(confflags, (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
|
|
|
|
set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
|
|
|
|
}
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
|
2006-05-23 16:35:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If I should be un-muted but am not talker, un-mute me */
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
|
2013-06-07 15:54:26 +00:00
|
|
|
RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confmode |= DAHDI_CONF_TALKER;
|
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2004-05-30 20:38:05 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
|
2004-05-22 04:11:22 +00:00
|
|
|
ret = -1;
|
|
|
|
break;
|
2004-05-30 20:38:05 +00:00
|
|
|
}
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
|
2006-05-23 16:35:46 +00:00
|
|
|
}
|
2013-06-07 15:54:26 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
|
2007-10-25 18:59:22 +00:00
|
|
|
(user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
|
|
|
|
|
2013-06-07 15:54:26 +00:00
|
|
|
RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
|
|
|
|
talkreq_manager = 1;
|
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
|
2007-10-25 18:59:22 +00:00
|
|
|
}
|
2006-05-23 16:35:46 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
|
2007-10-25 18:59:22 +00:00
|
|
|
!(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
|
2013-06-07 15:54:26 +00:00
|
|
|
RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
|
2007-10-25 18:59:22 +00:00
|
|
|
talkreq_manager = 0;
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
|
2007-10-25 18:59:22 +00:00
|
|
|
}
|
2011-09-15 12:50:40 +00:00
|
|
|
|
|
|
|
/* If user have been hung up, exit the conference */
|
|
|
|
if (user->adminflags & ADMINFLAG_HANGUP) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-05-23 16:35:46 +00:00
|
|
|
/* If I have been kicked, exit the conference */
|
|
|
|
if (user->adminflags & ADMINFLAG_KICKME) {
|
2007-12-13 23:10:42 +00:00
|
|
|
/* You have been kicked. */
|
2017-12-22 14:23:22 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
2012-01-24 20:12:09 +00:00
|
|
|
!ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
|
2006-05-23 16:35:46 +00:00
|
|
|
ast_waitstream(chan, "");
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2006-05-23 16:35:46 +00:00
|
|
|
ret = 0;
|
|
|
|
break;
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2003-11-04 21:47:35 +00:00
|
|
|
|
2012-11-15 23:10:13 +00:00
|
|
|
/* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
|
|
|
|
if (ast_check_hangup(chan)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Merged revisions 179532 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r179532 | russell | 2009-03-02 17:34:13 -0600 (Mon, 02 Mar 2009) | 40 lines
Move ast_waitfor() down to avoid the results of the API call becoming stale.
This call to ast_waitfor() was being done way too soon in this section of code.
Specifically, there was code in between the call to waitfor and the code that
uses the result that puts the channel in autoservice. By putting the channel
in autoservice, the previous results of ast_waitfor() become meaningless,
as the autoservice thread will do it's own ast_waitfor() and ast_read()
on the channel.
So, when we came back out of autoservice and eventually hit the block of code
that calls ast_read() on the channel, there may not actually be any input on
the channel available. Even though the previous call to ast_waitfor() in
app_meetme said there was input, the autoservice thread has since serviced
the channel for some period of time.
This bug manifested itself while dvossel was doing some testing of MeetMe in
Asterisk trunk. He was using the timerfd timing module. When the code hit
ast_read() erroneously, it determined that it must have been called because of
input on the timer fd, as chan->fdno was set to AST_TIMING_FD, since that was
the cause of the last legitimate call to ast_read() done by autoservice.
In this test, an IAX2 channel was calling into the MeetMe conference. It was
_much_ more likely to be seen with an IAX2 channel because of the way audio
is handled. Every audio frame that comes in results in a call to
ast_queue_frame(), which then uses ast_timer_enable_continuous() to notify
the channel thread that a frame is waiting to be handled. So, the chances
of ast_waitfor() indicating that a channel needs servicing due to a timer
event on an IAX2 event is very high.
Finally, it is interesting to note that if a different timing interface was
being used, this bug would probably not be noticed. When ast_read() is called
and erroneously thinks that there is a timer event to handle, it calls the
ast_timer_ack() function. The pthread and dahdi timing modules handle the
ack() function being called when there is no event by simply ignoring it.
In the case of the timerfd module, it results in a read() on the timer fd
that will block forever, as there is no data to read. This caused Asterisk
to lock up very quickly.
Thanks to dvossel and mmichelson for the fun debugging session. :-)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@179533 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-03-02 23:36:38 +00:00
|
|
|
c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
|
|
|
|
|
2004-06-28 22:10:50 +00:00
|
|
|
if (c) {
|
2008-06-12 15:26:07 +00:00
|
|
|
char dtmfstr[2] = "";
|
|
|
|
|
2012-03-01 22:09:18 +00:00
|
|
|
if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && (ast_channel_audiohooks(c) || ast_channel_monitor(c)))) {
|
2004-06-28 22:10:50 +00:00
|
|
|
if (using_pseudo) {
|
|
|
|
/* Kill old pseudo */
|
|
|
|
close(fd);
|
2005-09-25 03:57:53 +00:00
|
|
|
using_pseudo = 0;
|
2004-06-28 22:10:50 +00:00
|
|
|
}
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "Ooh, something swapped out under us, starting over\n");
|
2012-02-20 23:43:27 +00:00
|
|
|
retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || (ast_channel_audiohooks(c) || ast_channel_monitor(c)) ? 1 : 0);
|
2008-06-12 17:27:55 +00:00
|
|
|
user->dahdichannel = !retrydahdi;
|
|
|
|
goto dahdiretry;
|
2003-02-04 15:48:42 +00:00
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
|
2005-12-20 13:07:02 +00:00
|
|
|
f = ast_read_noaudio(c);
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2005-12-20 14:14:01 +00:00
|
|
|
f = ast_read(c);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
|
|
|
if (!f) {
|
2004-06-28 22:10:50 +00:00
|
|
|
break;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-06-12 15:26:07 +00:00
|
|
|
if (f->frametype == AST_FRAME_DTMF) {
|
2009-11-04 14:05:12 +00:00
|
|
|
dtmfstr[0] = f->subclass.integer;
|
2008-06-12 15:26:07 +00:00
|
|
|
dtmfstr[1] = '\0';
|
|
|
|
}
|
|
|
|
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
|
2008-10-01 23:02:25 +00:00
|
|
|
if (user->talk.actual) {
|
2005-10-28 16:36:10 +00:00
|
|
|
ast_frame_adjust_volume(f, user->talk.actual);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-10-28 16:36:10 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER))) {
|
2008-10-01 23:02:25 +00:00
|
|
|
if (user->talking == -1) {
|
2005-01-30 03:07:21 +00:00
|
|
|
user->talking = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-01-30 03:07:21 +00:00
|
|
|
|
|
|
|
res = ast_dsp_silence(dsp, f, &totalsilence);
|
|
|
|
if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
|
2009-12-11 23:17:09 +00:00
|
|
|
set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
|
2005-01-30 03:07:21 +00:00
|
|
|
}
|
2009-12-11 23:17:09 +00:00
|
|
|
|
2005-01-30 03:07:21 +00:00
|
|
|
if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
|
2009-12-11 23:17:09 +00:00
|
|
|
set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
|
2005-01-30 03:07:21 +00:00
|
|
|
}
|
|
|
|
}
|
2005-03-20 18:02:45 +00:00
|
|
|
if (using_pseudo) {
|
2005-11-08 23:19:30 +00:00
|
|
|
/* Absolutely do _not_ use careful_write here...
|
|
|
|
it is important that we read data from the channel
|
|
|
|
as fast as it arrives, and feed it into the conference.
|
|
|
|
The buffering in the pseudo channel will take care of any
|
|
|
|
timing differences, unless they are so drastic as to lose
|
|
|
|
audio frames (in which case carefully writing would only
|
|
|
|
have delayed the audio even further).
|
|
|
|
*/
|
2005-12-20 10:26:53 +00:00
|
|
|
/* As it turns out, we do want to use careful write. We just
|
|
|
|
don't want to block, but we do want to at least *try*
|
|
|
|
to write out all the samples.
|
|
|
|
*/
|
2010-01-06 20:37:18 +00:00
|
|
|
if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
|
2008-05-22 16:29:54 +00:00
|
|
|
careful_write(fd, f->data.ptr, f->datalen, 0);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-03-20 18:02:45 +00:00
|
|
|
}
|
2013-01-22 19:29:50 +00:00
|
|
|
} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
|
2007-08-09 16:13:26 +00:00
|
|
|
conf_queue_dtmf(conf, user, f);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2014-05-15 22:02:32 +00:00
|
|
|
/* Take out of conference */
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
|
2005-03-03 23:33:11 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
close(fd);
|
2006-06-11 21:12:56 +00:00
|
|
|
ast_frfree(f);
|
2005-03-03 23:33:11 +00:00
|
|
|
goto outrun;
|
|
|
|
}
|
2005-09-07 01:30:01 +00:00
|
|
|
|
|
|
|
/* if we are entering the menu, and the user has a channel-driver
|
|
|
|
volume adjustment, clear it
|
|
|
|
*/
|
2013-01-22 19:29:50 +00:00
|
|
|
if (!menu_mode && user->talk.desired && !user->talk.actual) {
|
2005-09-07 01:39:11 +00:00
|
|
|
set_talk_volume(user, 0);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-09-07 01:30:01 +00:00
|
|
|
|
2004-06-28 22:10:50 +00:00
|
|
|
if (musiconhold) {
|
2012-11-15 23:10:13 +00:00
|
|
|
ast_moh_stop(chan);
|
2013-01-22 19:29:50 +00:00
|
|
|
} else if (!menu_mode) {
|
|
|
|
char *menu_to_play;
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
|
|
|
|
menu_mode = MENU_ADMIN;
|
|
|
|
menu_to_play = "conf-adminmenu-18";
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2013-01-22 19:29:50 +00:00
|
|
|
menu_mode = MENU_NORMAL;
|
|
|
|
menu_to_play = "conf-usermenu-162";
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2006-05-31 22:54:58 +00:00
|
|
|
|
2013-01-22 19:29:50 +00:00
|
|
|
if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
|
|
|
|
dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
ast_stopstream(chan);
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2013-01-22 19:29:50 +00:00
|
|
|
dtmf = 0;
|
2004-05-30 20:38:05 +00:00
|
|
|
}
|
2013-01-22 19:29:50 +00:00
|
|
|
} else {
|
|
|
|
dtmf = f->subclass.integer;
|
2004-06-28 22:10:50 +00:00
|
|
|
}
|
2013-01-22 19:29:50 +00:00
|
|
|
|
|
|
|
if (dtmf > 0) {
|
2014-05-15 22:02:32 +00:00
|
|
|
meetme_menu(&menu_mode, &dtmf, conf, confflags,
|
|
|
|
chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
|
2013-01-22 19:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (musiconhold && !menu_mode) {
|
2007-11-21 00:21:38 +00:00
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-04-02 23:26:27 +00:00
|
|
|
|
2014-05-15 22:02:32 +00:00
|
|
|
/* Put back into conference */
|
2008-06-12 17:27:55 +00:00
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2005-03-03 23:33:11 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
close(fd);
|
2006-06-11 21:12:56 +00:00
|
|
|
ast_frfree(f);
|
2005-03-03 23:33:11 +00:00
|
|
|
goto outrun;
|
|
|
|
}
|
2005-11-08 23:19:30 +00:00
|
|
|
|
|
|
|
conf_flush(fd, chan);
|
2011-10-12 17:52:55 +00:00
|
|
|
/*
|
|
|
|
* Since options using DTMF could absorb DTMF meant for the
|
|
|
|
* conference menu, we have to check them after the menu.
|
|
|
|
*/
|
2009-12-10 17:31:23 +00:00
|
|
|
} else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
|
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
|
2008-06-12 15:26:07 +00:00
|
|
|
conf_queue_dtmf(conf, user, f);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-06-12 15:26:07 +00:00
|
|
|
|
|
|
|
if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
|
|
|
|
ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
|
|
|
|
ret = 0;
|
|
|
|
ast_frfree(f);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
} else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
|
|
|
|
(strchr(exitkeys, f->subclass.integer))) {
|
2008-06-12 15:26:07 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
|
2011-02-04 16:55:39 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
|
2008-06-12 15:26:07 +00:00
|
|
|
conf_queue_dtmf(conf, user, f);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-06-12 15:26:07 +00:00
|
|
|
ret = 0;
|
|
|
|
ast_frfree(f);
|
|
|
|
break;
|
2007-02-10 00:40:57 +00:00
|
|
|
} else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
|
2009-12-10 17:31:23 +00:00
|
|
|
&& ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
conf_queue_dtmf(conf, user, f);
|
2009-12-10 17:31:23 +00:00
|
|
|
} else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
|
2009-11-04 14:05:12 +00:00
|
|
|
switch (f->subclass.integer) {
|
2007-02-10 00:40:57 +00:00
|
|
|
case AST_CONTROL_HOLD:
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2007-06-13 19:10:16 +00:00
|
|
|
} else if (f->frametype == AST_FRAME_NULL) {
|
|
|
|
/* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
|
2010-07-01 15:12:31 +00:00
|
|
|
} else if (f->frametype == AST_FRAME_CONTROL) {
|
|
|
|
switch (f->subclass.integer) {
|
|
|
|
case AST_CONTROL_BUSY:
|
|
|
|
case AST_CONTROL_CONGESTION:
|
|
|
|
ast_frfree(f);
|
|
|
|
goto outrun;
|
|
|
|
break;
|
|
|
|
default:
|
2011-02-04 16:55:39 +00:00
|
|
|
ast_debug(1,
|
2014-07-22 14:22:00 +00:00
|
|
|
"Got ignored control frame on channel %s, f->frametype=%u,f->subclass=%d\n",
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(chan), f->frametype, f->subclass.integer);
|
2010-07-01 15:12:31 +00:00
|
|
|
}
|
2007-06-24 18:51:41 +00:00
|
|
|
} else {
|
2011-02-04 16:55:39 +00:00
|
|
|
ast_debug(1,
|
2014-07-22 14:22:00 +00:00
|
|
|
"Got unrecognized frame on channel %s, f->frametype=%u,f->subclass=%d\n",
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(chan), f->frametype, f->subclass.integer);
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2004-06-28 22:10:50 +00:00
|
|
|
ast_frfree(f);
|
|
|
|
} else if (outfd > -1) {
|
|
|
|
res = read(outfd, buf, CONF_SIZE);
|
|
|
|
if (res > 0) {
|
|
|
|
memset(&fr, 0, sizeof(fr));
|
|
|
|
fr.frametype = AST_FRAME_VOICE;
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
fr.subclass.format = ast_format_slin;
|
2004-06-28 22:10:50 +00:00
|
|
|
fr.datalen = res;
|
2007-12-13 23:10:42 +00:00
|
|
|
fr.samples = res / 2;
|
2008-05-22 16:29:54 +00:00
|
|
|
fr.data.ptr = buf;
|
2004-06-28 22:10:50 +00:00
|
|
|
fr.offset = AST_FRIENDLY_OFFSET;
|
2009-02-18 19:12:49 +00:00
|
|
|
if (!user->listen.actual &&
|
2009-12-10 17:31:23 +00:00
|
|
|
(ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
|
2006-05-31 22:54:58 +00:00
|
|
|
(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
|
2009-12-10 17:31:23 +00:00
|
|
|
(!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
|
2009-02-18 19:12:49 +00:00
|
|
|
)) {
|
2008-08-10 14:45:25 +00:00
|
|
|
int idx;
|
2008-10-01 23:02:25 +00:00
|
|
|
for (idx = 0; idx < AST_FRAME_BITS; idx++) {
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
if (ast_format_compatibility_format2bitfield(ast_channel_rawwriteformat(chan)) & (1 << idx)) {
|
2005-12-20 13:07:02 +00:00
|
|
|
break;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (idx >= AST_FRAME_BITS) {
|
2005-12-20 13:07:02 +00:00
|
|
|
goto bailoutandtrynormal;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_mutex_lock(&conf->listenlock);
|
2008-08-10 14:45:25 +00:00
|
|
|
if (!conf->transframe[idx]) {
|
2005-12-20 13:07:02 +00:00
|
|
|
if (conf->origframe) {
|
2014-05-22 16:19:13 +00:00
|
|
|
if (musiconhold
|
|
|
|
&& !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
|
|
|
|
&& !ast_dsp_silence(dsp, conf->origframe, &confsilence)
|
|
|
|
&& confsilence < MEETME_DELAYDETECTTALK) {
|
2010-05-12 18:01:20 +00:00
|
|
|
ast_moh_stop(chan);
|
|
|
|
mohtempstopped = 1;
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
if (!conf->transpath[idx]) {
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
conf->transpath[idx] = ast_translator_build_path(ast_channel_rawwriteformat(chan), ast_format_slin);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-08-10 14:45:25 +00:00
|
|
|
if (conf->transpath[idx]) {
|
|
|
|
conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
|
2008-10-01 23:02:25 +00:00
|
|
|
if (!conf->transframe[idx]) {
|
2008-08-10 14:45:25 +00:00
|
|
|
conf->transframe[idx] = &ast_null_frame;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-10 14:45:25 +00:00
|
|
|
if (conf->transframe[idx]) {
|
2009-06-16 18:54:30 +00:00
|
|
|
if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
|
|
|
|
can_write(chan, confflags)) {
|
|
|
|
struct ast_frame *cur;
|
|
|
|
/* the translator may have returned a list of frames, so
|
|
|
|
write each one onto the channel
|
|
|
|
*/
|
|
|
|
for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
|
|
|
|
if (ast_write(chan, cur)) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
|
2009-06-16 18:54:30 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2009-09-08 20:28:41 +00:00
|
|
|
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
|
|
|
|
mohtempstopped = 0;
|
2012-04-05 17:22:30 +00:00
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
2009-09-08 20:28:41 +00:00
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ast_mutex_unlock(&conf->listenlock);
|
|
|
|
goto bailoutandtrynormal;
|
|
|
|
}
|
|
|
|
ast_mutex_unlock(&conf->listenlock);
|
|
|
|
} else {
|
2009-09-08 20:28:41 +00:00
|
|
|
bailoutandtrynormal:
|
2014-05-22 16:19:13 +00:00
|
|
|
if (musiconhold
|
|
|
|
&& !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
|
|
|
|
&& !ast_dsp_silence(dsp, &fr, &confsilence)
|
|
|
|
&& confsilence < MEETME_DELAYDETECTTALK) {
|
2009-09-08 20:28:41 +00:00
|
|
|
ast_moh_stop(chan);
|
|
|
|
mohtempstopped = 1;
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
if (user->listen.actual) {
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_frame_adjust_volume(&fr, user->listen.actual);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2008-12-09 20:59:54 +00:00
|
|
|
if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
2009-09-08 20:28:41 +00:00
|
|
|
if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
|
|
|
|
mohtempstopped = 0;
|
2012-04-05 17:22:30 +00:00
|
|
|
conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
|
2009-09-08 20:28:41 +00:00
|
|
|
}
|
2004-06-28 22:10:50 +00:00
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2004-06-28 22:10:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2005-03-17 20:29:51 +00:00
|
|
|
lastmarked = currentmarked;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
2006-02-14 17:08:06 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
if (musiconhold) {
|
2006-02-14 17:08:06 +00:00
|
|
|
ast_moh_stop(chan);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
if (using_pseudo) {
|
2002-05-13 22:29:39 +00:00
|
|
|
close(fd);
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2002-08-11 02:12:40 +00:00
|
|
|
/* Take out of conference */
|
2017-12-22 14:23:22 +00:00
|
|
|
dahdic.chan = 0;
|
2008-06-12 17:27:55 +00:00
|
|
|
dahdic.confno = 0;
|
|
|
|
dahdic.confmode = 0;
|
|
|
|
if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
|
2002-08-11 02:12:40 +00:00
|
|
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
|
|
|
}
|
|
|
|
}
|
2005-01-07 07:23:31 +00:00
|
|
|
|
2005-09-07 14:15:37 +00:00
|
|
|
reset_volumes(user);
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
|
|
|
|
!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
|
2005-02-16 03:50:41 +00:00
|
|
|
conf_play(chan, conf, LEAVE);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
|
2010-11-24 23:46:14 +00:00
|
|
|
if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER |CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC) && conf->users > 1) {
|
2008-11-12 18:32:46 +00:00
|
|
|
struct announce_listitem *item;
|
|
|
|
if (!(item = ao2_alloc(sizeof(*item), NULL)))
|
2011-01-29 18:10:34 +00:00
|
|
|
goto outrun;
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
|
2008-11-12 18:32:46 +00:00
|
|
|
item->confchan = conf->chan;
|
|
|
|
item->confusers = conf->users;
|
|
|
|
item->announcetype = CONF_HASLEFT;
|
2010-11-24 23:46:14 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
|
|
|
|
item->vmrec = 1;
|
|
|
|
}
|
2008-11-12 18:32:46 +00:00
|
|
|
ast_mutex_lock(&conf->announcelistlock);
|
|
|
|
AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
|
|
|
|
ast_cond_signal(&conf->announcelist_addition);
|
|
|
|
ast_mutex_unlock(&conf->announcelistlock);
|
2010-11-24 23:46:14 +00:00
|
|
|
} else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
|
2008-11-12 18:32:46 +00:00
|
|
|
/* Last person is leaving, so no reason to try and announce, but should delete the name recording */
|
|
|
|
ast_filedelete(user->namerecloc, NULL);
|
2005-01-07 07:23:31 +00:00
|
|
|
}
|
|
|
|
|
2005-11-08 21:32:51 +00:00
|
|
|
outrun:
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
if (dsp) {
|
2005-01-30 03:07:21 +00:00
|
|
|
ast_dsp_free(dsp);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2011-01-29 16:31:17 +00:00
|
|
|
if (user->user_no) {
|
|
|
|
/* Only cleanup users who really joined! */
|
2007-10-17 15:13:51 +00:00
|
|
|
now = ast_tvnow();
|
2006-01-11 06:56:28 +00:00
|
|
|
|
2006-05-25 21:06:08 +00:00
|
|
|
if (sent_event) {
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
|
2006-05-25 21:06:08 +00:00
|
|
|
}
|
2006-01-11 06:56:28 +00:00
|
|
|
|
2007-12-12 21:22:58 +00:00
|
|
|
if (setusercount) {
|
|
|
|
conf->users--;
|
2007-12-13 23:10:42 +00:00
|
|
|
if (rt_log_members) {
|
2007-12-12 21:22:58 +00:00
|
|
|
/* Update table */
|
|
|
|
snprintf(members, sizeof(members), "%d", conf->users);
|
2008-06-09 22:51:59 +00:00
|
|
|
ast_realtime_require_field("meetme",
|
|
|
|
"confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
|
|
|
|
"members", RQ_UINTEGER1, strlen(members),
|
|
|
|
NULL);
|
2007-12-12 21:22:58 +00:00
|
|
|
ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
|
|
|
|
}
|
2009-12-10 17:31:23 +00:00
|
|
|
if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
|
2007-12-12 21:22:58 +00:00
|
|
|
conf->markedusers--;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
/* Remove ourselves from the container */
|
2017-12-22 14:23:22 +00:00
|
|
|
ao2_unlink(conf->usercontainer, user);
|
2006-12-11 05:01:37 +00:00
|
|
|
|
|
|
|
/* Change any states */
|
2008-10-01 23:02:25 +00:00
|
|
|
if (!conf->users) {
|
2013-01-02 18:11:59 +00:00
|
|
|
ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
|
|
|
|
2011-09-15 12:50:40 +00:00
|
|
|
/* This flag is meant to kill a conference with only one participant remaining. */
|
|
|
|
if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
|
|
|
|
ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
|
|
|
|
}
|
|
|
|
|
2004-11-25 03:23:07 +00:00
|
|
|
/* Return the number of seconds the user was in the conf */
|
2005-04-29 17:00:33 +00:00
|
|
|
snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
|
2004-11-25 03:23:07 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
|
2010-04-02 23:55:57 +00:00
|
|
|
|
|
|
|
/* Return the RealTime bookid for CDR linking */
|
|
|
|
if (rt_schedule) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
|
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2011-01-29 16:31:17 +00:00
|
|
|
ao2_ref(user, -1);
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
conf_run_cleanup:
|
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was
fast but had a few limitations.
1. Asterisk was limited in how many formats it could handle.
2. Formats, being a bit field, could not include any attribute information.
A format was strictly its type, e.g., "this is ulaw".
This was changed in Asterisk 10 (see
https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for
notes on that work) which led to the creation of the ast_format structure.
This structure allowed Asterisk to handle attributes and bundle information
with a format.
Additionally, ast_format_cap was created to act as a container for multiple
formats that, together, formed the capability of some entity. Another
mechanism was added to allow logic to be registered which performed format
attribute negotiation. Everywhere throughout the codebase Asterisk was
changed to use this strategy.
Unfortunately, in software, there is no free lunch. These new capabilities
came at a cost.
Performance analysis and profiling showed that we spend an inordinate
amount of time comparing, copying, and generally manipulating formats and
their related structures. Basic prototyping has shown that a reasonably
large performance improvement could be made in this area. This patch is the
result of that project, which overhauled the media format architecture
and its usage in Asterisk to improve performance.
Generally, the new philosophy for handling formats is as follows:
* The ast_format structure is reference counted. This removed a large amount
of the memory allocations and copying that was done in prior versions.
* In order to prevent race conditions while keeping things performant, the
ast_format structure is immutable by convention and lock-free. Violate this
tenet at your peril!
* Because formats are reference counted, codecs are also reference counted.
The Asterisk core generally provides built-in codecs and caches the
ast_format structures created to represent them. Generally, to prevent
inordinate amounts of module reference bumping, codecs and formats can be
added at run-time but cannot be removed.
* All compatibility with the bit field representation of codecs/formats has
been moved to a compatibility API. The primary user of this representation
is chan_iax2, which must continue to maintain its bit-field usage of formats
for interoperability concerns.
* When a format is negotiated with attributes, or when a format cannot be
represented by one of the cached formats, a new format object is created or
cloned from an existing format. That format may have the same codec
underlying it, but is a different format than a version of the format with
different attributes or without attributes.
* While formats are reference counted objects, the reference count maintained
on the format should be manipulated with care. Formats are generally cached
and will persist for the lifetime of Asterisk and do not explicitly need
to have their lifetime modified. An exception to this is when the user of a
format does not know where the format came from *and* the user may outlive
the provider of the format. This occurs, for example, when a format is read
from a channel: the channel may have a format with attributes (hence,
non-cached) and the user of the format may last longer than the channel (if
the reference to the channel is released prior to the format's reference).
For more information on this work, see the API design notes:
https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite
Finally, this work was the culmination of a large number of developer's
efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the
work in the Asterisk core, chan_sip, and was an invaluable resource in peer
reviews throughout this project.
There were a substantial number of patches contributed during this work; the
following issues/patch names simply reflect some of the work (and will cause
the release scripts to give attribution to the individuals who work on them).
Reviews:
https://reviewboard.asterisk.org/r/3814
https://reviewboard.asterisk.org/r/3808
https://reviewboard.asterisk.org/r/3805
https://reviewboard.asterisk.org/r/3803
https://reviewboard.asterisk.org/r/3801
https://reviewboard.asterisk.org/r/3798
https://reviewboard.asterisk.org/r/3800
https://reviewboard.asterisk.org/r/3794
https://reviewboard.asterisk.org/r/3793
https://reviewboard.asterisk.org/r/3792
https://reviewboard.asterisk.org/r/3791
https://reviewboard.asterisk.org/r/3790
https://reviewboard.asterisk.org/r/3789
https://reviewboard.asterisk.org/r/3788
https://reviewboard.asterisk.org/r/3787
https://reviewboard.asterisk.org/r/3786
https://reviewboard.asterisk.org/r/3784
https://reviewboard.asterisk.org/r/3783
https://reviewboard.asterisk.org/r/3778
https://reviewboard.asterisk.org/r/3774
https://reviewboard.asterisk.org/r/3775
https://reviewboard.asterisk.org/r/3772
https://reviewboard.asterisk.org/r/3761
https://reviewboard.asterisk.org/r/3754
https://reviewboard.asterisk.org/r/3753
https://reviewboard.asterisk.org/r/3751
https://reviewboard.asterisk.org/r/3750
https://reviewboard.asterisk.org/r/3748
https://reviewboard.asterisk.org/r/3747
https://reviewboard.asterisk.org/r/3746
https://reviewboard.asterisk.org/r/3742
https://reviewboard.asterisk.org/r/3740
https://reviewboard.asterisk.org/r/3739
https://reviewboard.asterisk.org/r/3738
https://reviewboard.asterisk.org/r/3737
https://reviewboard.asterisk.org/r/3736
https://reviewboard.asterisk.org/r/3734
https://reviewboard.asterisk.org/r/3722
https://reviewboard.asterisk.org/r/3713
https://reviewboard.asterisk.org/r/3703
https://reviewboard.asterisk.org/r/3689
https://reviewboard.asterisk.org/r/3687
https://reviewboard.asterisk.org/r/3674
https://reviewboard.asterisk.org/r/3671
https://reviewboard.asterisk.org/r/3667
https://reviewboard.asterisk.org/r/3665
https://reviewboard.asterisk.org/r/3625
https://reviewboard.asterisk.org/r/3602
https://reviewboard.asterisk.org/r/3519
https://reviewboard.asterisk.org/r/3518
https://reviewboard.asterisk.org/r/3516
https://reviewboard.asterisk.org/r/3515
https://reviewboard.asterisk.org/r/3512
https://reviewboard.asterisk.org/r/3506
https://reviewboard.asterisk.org/r/3413
https://reviewboard.asterisk.org/r/3410
https://reviewboard.asterisk.org/r/3387
https://reviewboard.asterisk.org/r/3388
https://reviewboard.asterisk.org/r/3389
https://reviewboard.asterisk.org/r/3390
https://reviewboard.asterisk.org/r/3321
https://reviewboard.asterisk.org/r/3320
https://reviewboard.asterisk.org/r/3319
https://reviewboard.asterisk.org/r/3318
https://reviewboard.asterisk.org/r/3266
https://reviewboard.asterisk.org/r/3265
https://reviewboard.asterisk.org/r/3234
https://reviewboard.asterisk.org/r/3178
ASTERISK-23114 #close
Reported by: mjordan
media_formats_translation_core.diff uploaded by kharwell (License 6464)
rb3506.diff uploaded by mjordan (License 6283)
media_format_app_file.diff uploaded by kharwell (License 6464)
misc-2.diff uploaded by file (License 5000)
chan_mild-3.diff uploaded by file (License 5000)
chan_obscure.diff uploaded by file (License 5000)
jingle.diff uploaded by file (License 5000)
funcs.diff uploaded by file (License 5000)
formats.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
bridges.diff uploaded by file (License 5000)
mf-codecs-2.diff uploaded by file (License 5000)
mf-app_fax.diff uploaded by file (License 5000)
mf-apps-3.diff uploaded by file (License 5000)
media-formats-3.diff uploaded by file (License 5000)
ASTERISK-23715
rb3713.patch uploaded by coreyfarrell (License 5909)
rb3689.patch uploaded by mjordan (License 6283)
ASTERISK-23957
rb3722.patch uploaded by mjordan (License 6283)
mf-attributes-3.diff uploaded by file (License 5000)
ASTERISK-23958
Tested by: jrose
rb3822.patch uploaded by coreyfarrell (License 5909)
rb3800.patch uploaded by jrose (License 6182)
chan_sip.diff uploaded by mjordan (License 6283)
rb3747.patch uploaded by jrose (License 6182)
ASTERISK-23959 #close
Tested by: sgriepentrog, mjordan, coreyfarrell
sip_cleanup.diff uploaded by opticron (License 6273)
chan_sip_caps.diff uploaded by mjordan (License 6283)
rb3751.patch uploaded by coreyfarrell (License 5909)
chan_sip-3.diff uploaded by file (License 5000)
ASTERISK-23960 #close
Tested by: opticron
direct_media.diff uploaded by opticron (License 6273)
pjsip-direct-media.diff uploaded by file (License 5000)
format_cap_remove.diff uploaded by opticron (License 6273)
media_format_fixes.diff uploaded by opticron (License 6273)
chan_pjsip-2.diff uploaded by file (License 5000)
ASTERISK-23966 #close
Tested by: rmudgett
rb3803.patch uploaded by rmudgetti (License 5621)
chan_dahdi.diff uploaded by file (License 5000)
ASTERISK-24064 #close
Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose
rb3814.patch uploaded by rmudgett (License 5621)
moh_cleanup.diff uploaded by opticron (License 6273)
bridge_leak.diff uploaded by opticron (License 6273)
translate.diff uploaded by file (License 5000)
rb3795.patch uploaded by rmudgett (License 5621)
tls_fix.diff uploaded by mjordan (License 6283)
fax-mf-fix-2.diff uploaded by file (License 5000)
rtp_transfer_stuff uploaded by mjordan (License 6283)
rb3787.patch uploaded by rmudgett (License 5621)
media-formats-explicit-translate-format-3.diff uploaded by file (License 5000)
format_cache_case_fix.diff uploaded by opticron (License 6273)
rb3774.patch uploaded by rmudgett (License 5621)
rb3775.patch uploaded by rmudgett (License 5621)
rtp_engine_fix.diff uploaded by opticron (License 6273)
rtp_crash_fix.diff uploaded by opticron (License 6273)
rb3753.patch uploaded by mjordan (License 6283)
rb3750.patch uploaded by mjordan (License 6283)
rb3748.patch uploaded by rmudgett (License 5621)
media_format_fixes.diff uploaded by opticron (License 6273)
rb3740.patch uploaded by mjordan (License 6283)
rb3739.patch uploaded by mjordan (License 6283)
rb3734.patch uploaded by mjordan (License 6283)
rb3689.patch uploaded by mjordan (License 6283)
rb3674.patch uploaded by coreyfarrell (License 5909)
rb3671.patch uploaded by coreyfarrell (License 5909)
rb3667.patch uploaded by coreyfarrell (License 5909)
rb3665.patch uploaded by mjordan (License 6283)
rb3625.patch uploaded by coreyfarrell (License 5909)
rb3602.patch uploaded by coreyfarrell (License 5909)
format_compatibility-2.diff uploaded by file (License 5000)
core.diff uploaded by file (License 5000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-07-20 22:06:33 +00:00
|
|
|
ao2_cleanup(cap_slin);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
2003-02-04 15:48:42 +00:00
|
|
|
return ret;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
|
2010-07-21 15:56:05 +00:00
|
|
|
char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
|
2006-03-07 01:12:09 +00:00
|
|
|
{
|
2008-10-01 23:02:25 +00:00
|
|
|
struct ast_variable *var, *origvar;
|
2006-03-07 01:12:09 +00:00
|
|
|
struct ast_conference *cnf;
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
*too_early = 0;
|
|
|
|
|
2006-03-07 01:12:09 +00:00
|
|
|
/* Check first in the conference list */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
2010-07-21 15:56:05 +00:00
|
|
|
if (!strcmp(confno, cnf->confno)) {
|
2006-03-07 01:12:09 +00:00
|
|
|
break;
|
2010-07-21 15:56:05 +00:00
|
|
|
}
|
2006-03-07 01:12:09 +00:00
|
|
|
}
|
2006-12-26 05:23:25 +00:00
|
|
|
if (cnf) {
|
2006-03-13 13:56:34 +00:00
|
|
|
cnf->refcount += refcount;
|
|
|
|
}
|
2006-03-07 01:12:09 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
|
|
|
if (!cnf) {
|
|
|
|
char *pin = NULL, *pinadmin = NULL; /* For temp use */
|
2007-10-17 15:13:51 +00:00
|
|
|
int maxusers = 0;
|
|
|
|
struct timeval now;
|
2009-03-03 22:01:24 +00:00
|
|
|
char recordingfilename[256] = "";
|
2009-07-14 20:14:45 +00:00
|
|
|
char recordingformat[11] = "";
|
2010-11-27 10:41:20 +00:00
|
|
|
char currenttime[32] = "";
|
|
|
|
char eatime[32] = "";
|
2009-07-14 20:14:45 +00:00
|
|
|
char bookid[51] = "";
|
2017-09-25 12:25:06 +00:00
|
|
|
char recordingtmp[AST_MAX_EXTENSION * 2] = "";
|
2011-01-07 20:53:45 +00:00
|
|
|
char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
|
|
|
|
char adminopts[OPTIONS_LEN + 1] = "";
|
2007-10-17 15:13:51 +00:00
|
|
|
struct ast_tm tm, etm;
|
2008-04-24 19:24:31 +00:00
|
|
|
struct timeval endtime = { .tv_sec = 0 };
|
2009-03-03 22:01:24 +00:00
|
|
|
const char *var2;
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2007-12-13 23:10:42 +00:00
|
|
|
if (rt_schedule) {
|
2007-10-17 15:13:51 +00:00
|
|
|
now = ast_tvnow();
|
|
|
|
|
|
|
|
ast_localtime(&now, &tm, NULL);
|
|
|
|
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
|
|
|
|
2011-05-06 21:49:47 +00:00
|
|
|
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
|
2008-04-24 19:24:31 +00:00
|
|
|
|
|
|
|
var = ast_load_realtime("meetme", "confno",
|
|
|
|
confno, "starttime <= ", currenttime, "endtime >= ",
|
|
|
|
currenttime, NULL);
|
|
|
|
|
|
|
|
if (!var && fuzzystart) {
|
|
|
|
now = ast_tvnow();
|
|
|
|
now.tv_sec += fuzzystart;
|
|
|
|
|
|
|
|
ast_localtime(&now, &tm, NULL);
|
|
|
|
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
|
|
|
var = ast_load_realtime("meetme", "confno",
|
|
|
|
confno, "starttime <= ", currenttime, "endtime >= ",
|
|
|
|
currenttime, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!var && earlyalert) {
|
|
|
|
now = ast_tvnow();
|
2007-10-17 15:13:51 +00:00
|
|
|
now.tv_sec += earlyalert;
|
|
|
|
ast_localtime(&now, &etm, NULL);
|
|
|
|
ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
|
2008-04-24 19:24:31 +00:00
|
|
|
var = ast_load_realtime("meetme", "confno",
|
|
|
|
confno, "starttime <= ", eatime, "endtime >= ",
|
|
|
|
currenttime, NULL);
|
2008-10-01 23:02:25 +00:00
|
|
|
if (var) {
|
2008-04-24 19:24:31 +00:00
|
|
|
*too_early = 1;
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2007-10-17 15:13:51 +00:00
|
|
|
var = ast_load_realtime("meetme", "confno", confno, NULL);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2006-03-07 01:12:09 +00:00
|
|
|
|
2010-07-21 15:56:05 +00:00
|
|
|
if (!var) {
|
2006-03-07 01:12:09 +00:00
|
|
|
return NULL;
|
2010-07-21 15:56:05 +00:00
|
|
|
}
|
2006-03-07 01:12:09 +00:00
|
|
|
|
2008-04-24 19:24:31 +00:00
|
|
|
if (rt_schedule && *too_early) {
|
|
|
|
/* Announce that the caller is early and exit */
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
|
2008-04-24 19:24:31 +00:00
|
|
|
ast_waitstream(chan, "");
|
2010-07-21 15:56:05 +00:00
|
|
|
}
|
2008-04-24 19:24:31 +00:00
|
|
|
ast_variables_destroy(var);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
for (origvar = var; var; var = var->next) {
|
2006-12-26 05:23:25 +00:00
|
|
|
if (!strcasecmp(var->name, "pin")) {
|
2006-03-07 01:12:09 +00:00
|
|
|
pin = ast_strdupa(var->value);
|
|
|
|
} else if (!strcasecmp(var->name, "adminpin")) {
|
|
|
|
pinadmin = ast_strdupa(var->value);
|
2008-10-17 04:28:13 +00:00
|
|
|
} else if (!strcasecmp(var->name, "bookId")) {
|
|
|
|
ast_copy_string(bookid, var->value, sizeof(bookid));
|
2007-10-17 15:13:51 +00:00
|
|
|
} else if (!strcasecmp(var->name, "opts")) {
|
2009-07-14 20:14:45 +00:00
|
|
|
ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
|
2007-10-17 15:13:51 +00:00
|
|
|
} else if (!strcasecmp(var->name, "maxusers")) {
|
|
|
|
maxusers = atoi(var->value);
|
|
|
|
} else if (!strcasecmp(var->name, "adminopts")) {
|
2009-07-14 20:14:45 +00:00
|
|
|
ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
|
2009-03-03 22:01:24 +00:00
|
|
|
} else if (!strcasecmp(var->name, "recordingfilename")) {
|
|
|
|
ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
|
|
|
|
} else if (!strcasecmp(var->name, "recordingformat")) {
|
|
|
|
ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
|
2007-10-17 15:13:51 +00:00
|
|
|
} else if (!strcasecmp(var->name, "endtime")) {
|
2008-10-08 12:15:06 +00:00
|
|
|
struct ast_tm endtime_tm;
|
|
|
|
ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
|
|
|
|
endtime = ast_mktime(&endtime_tm, NULL);
|
2006-03-07 01:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-13 23:10:42 +00:00
|
|
|
|
2008-10-01 23:02:25 +00:00
|
|
|
ast_variables_destroy(origvar);
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2010-07-09 20:01:01 +00:00
|
|
|
cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
|
2007-10-17 15:13:51 +00:00
|
|
|
|
|
|
|
if (cnf) {
|
2010-07-21 15:56:05 +00:00
|
|
|
struct ast_flags64 tmp_flags;
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
cnf->maxusers = maxusers;
|
|
|
|
cnf->endalert = endalert;
|
2007-12-13 23:10:42 +00:00
|
|
|
cnf->endtime = endtime.tv_sec;
|
2008-10-17 04:28:13 +00:00
|
|
|
cnf->useropts = ast_strdup(useropts);
|
|
|
|
cnf->adminopts = ast_strdup(adminopts);
|
|
|
|
cnf->bookid = ast_strdup(bookid);
|
2011-12-07 20:34:23 +00:00
|
|
|
if (!ast_strlen_zero(recordingfilename)) {
|
|
|
|
cnf->recordingfilename = ast_strdup(recordingfilename);
|
|
|
|
}
|
|
|
|
if (!ast_strlen_zero(recordingformat)) {
|
|
|
|
cnf->recordingformat = ast_strdup(recordingformat);
|
|
|
|
}
|
2009-03-03 22:01:24 +00:00
|
|
|
|
2010-07-21 15:56:05 +00:00
|
|
|
/* Parse the other options into confflags -- need to do this in two
|
|
|
|
* steps, because the parse_options routine zeroes the buffer. */
|
|
|
|
ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
|
|
|
|
ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
|
|
|
|
|
2009-03-03 22:01:24 +00:00
|
|
|
if (strchr(cnf->useropts, 'r')) {
|
|
|
|
if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
|
|
|
|
ast_free(cnf->recordingfilename);
|
|
|
|
cnf->recordingfilename = ast_strdup(var2);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
if (ast_strlen_zero(cnf->recordingfilename)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
|
2009-03-03 22:01:24 +00:00
|
|
|
ast_free(cnf->recordingfilename);
|
|
|
|
cnf->recordingfilename = ast_strdup(recordingtmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
|
|
|
|
ast_free(cnf->recordingformat);
|
|
|
|
cnf->recordingformat = ast_strdup(var2);
|
|
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
if (ast_strlen_zero(cnf->recordingformat)) {
|
|
|
|
ast_free(cnf->recordingformat);
|
|
|
|
cnf->recordingformat = ast_strdup("wav");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
|
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
2006-03-07 01:12:09 +00:00
|
|
|
}
|
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
if (cnf) {
|
2009-12-10 17:31:23 +00:00
|
|
|
if (confflags->flags && !cnf->chan &&
|
|
|
|
!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
2017-05-31 09:25:02 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
|
2010-11-24 23:46:14 +00:00
|
|
|
ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
|
2006-04-06 22:16:23 +00:00
|
|
|
}
|
2010-07-21 15:56:05 +00:00
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
if (confflags && !cnf->chan &&
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
|
2006-04-06 22:16:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-07 01:12:09 +00:00
|
|
|
return cnf;
|
|
|
|
}
|
|
|
|
|
2007-02-16 22:50:22 +00:00
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
|
2009-12-10 17:31:23 +00:00
|
|
|
char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2007-02-16 22:50:22 +00:00
|
|
|
struct ast_config *cfg;
|
|
|
|
struct ast_variable *var;
|
2007-08-16 21:09:46 +00:00
|
|
|
struct ast_flags config_flags = { 0 };
|
2004-06-17 02:42:42 +00:00
|
|
|
struct ast_conference *cnf;
|
2009-12-28 12:44:58 +00:00
|
|
|
|
2007-02-16 22:50:22 +00:00
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(confno);
|
|
|
|
AST_APP_ARG(pin);
|
|
|
|
AST_APP_ARG(pinadmin);
|
|
|
|
);
|
2004-01-11 06:07:36 +00:00
|
|
|
|
|
|
|
/* Check first in the conference list */
|
2007-12-13 23:10:42 +00:00
|
|
|
ast_debug(1, "The requested confno is '%s'?\n", confno);
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
2007-12-13 23:10:42 +00:00
|
|
|
ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
|
2011-02-04 16:55:39 +00:00
|
|
|
if (!strcmp(confno, cnf->confno))
|
2002-05-13 22:29:39 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-12-13 23:10:42 +00:00
|
|
|
if (cnf) {
|
2006-03-13 13:56:34 +00:00
|
|
|
cnf->refcount += refcount;
|
|
|
|
}
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2004-01-11 06:07:36 +00:00
|
|
|
|
|
|
|
if (!cnf) {
|
2003-10-29 22:52:20 +00:00
|
|
|
if (dynamic) {
|
2004-01-11 06:07:36 +00:00
|
|
|
/* No need to parse meetme.conf */
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "Building dynamic conference '%s'\n", confno);
|
2004-04-08 19:38:26 +00:00
|
|
|
if (dynamic_pin) {
|
|
|
|
if (dynamic_pin[0] == 'q') {
|
|
|
|
/* Query the user to enter a PIN */
|
2007-02-10 00:40:57 +00:00
|
|
|
if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
|
2006-01-18 21:12:14 +00:00
|
|
|
return NULL;
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2010-07-09 20:01:01 +00:00
|
|
|
cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
|
2004-04-08 19:38:26 +00:00
|
|
|
} else {
|
2010-07-09 20:01:01 +00:00
|
|
|
cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2004-01-11 06:07:36 +00:00
|
|
|
} else {
|
2007-02-16 22:50:22 +00:00
|
|
|
/* Check the config */
|
2007-08-16 21:09:46 +00:00
|
|
|
cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
|
2007-02-16 22:50:22 +00:00
|
|
|
if (!cfg) {
|
|
|
|
ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
|
|
|
|
return NULL;
|
2008-09-12 23:30:03 +00:00
|
|
|
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
|
|
|
|
ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
|
|
|
|
return NULL;
|
2007-02-16 22:50:22 +00:00
|
|
|
}
|
2009-12-28 12:44:58 +00:00
|
|
|
|
2007-02-16 22:50:22 +00:00
|
|
|
for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
|
2009-12-28 12:44:58 +00:00
|
|
|
char parse[MAX_SETTINGS];
|
|
|
|
|
2007-02-16 22:50:22 +00:00
|
|
|
if (strcasecmp(var->name, "conf"))
|
|
|
|
continue;
|
2009-12-28 12:44:58 +00:00
|
|
|
|
|
|
|
ast_copy_string(parse, var->value, sizeof(parse));
|
|
|
|
|
2007-07-31 01:10:47 +00:00
|
|
|
AST_STANDARD_APP_ARGS(args, parse);
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
|
2007-02-16 22:50:22 +00:00
|
|
|
if (!strcasecmp(args.confno, confno)) {
|
|
|
|
/* Bingo it's a valid conference */
|
|
|
|
cnf = build_conf(args.confno,
|
|
|
|
S_OR(args.pin, ""),
|
|
|
|
S_OR(args.pinadmin, ""),
|
2010-07-09 20:01:01 +00:00
|
|
|
make, dynamic, refcount, chan, NULL);
|
2007-02-16 22:50:22 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!var) {
|
2022-03-05 15:40:16 +00:00
|
|
|
ast_log(LOG_WARNING, "%s isn't a valid conference\n", confno);
|
2007-02-16 22:50:22 +00:00
|
|
|
}
|
|
|
|
ast_config_destroy(cfg);
|
2004-01-11 06:07:36 +00:00
|
|
|
}
|
2004-08-02 13:10:15 +00:00
|
|
|
} else if (dynamic_pin) {
|
2004-08-02 02:58:15 +00:00
|
|
|
/* Correct for the user selecting 'D' instead of 'd' to have
|
|
|
|
someone join into a conference that has already been created
|
|
|
|
with a pin. */
|
2008-10-01 23:02:25 +00:00
|
|
|
if (dynamic_pin[0] == 'q') {
|
2004-08-02 02:58:15 +00:00
|
|
|
dynamic_pin[0] = '\0';
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
if (cnf) {
|
|
|
|
if (confflags && !cnf->chan &&
|
2009-12-10 17:31:23 +00:00
|
|
|
!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
|
2010-11-24 23:46:14 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
|
2010-11-24 23:46:14 +00:00
|
|
|
ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
|
2006-04-06 22:16:23 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2006-04-06 22:16:23 +00:00
|
|
|
if (confflags && !cnf->chan &&
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
|
2008-06-12 17:27:55 +00:00
|
|
|
ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
|
2006-04-06 22:16:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-13 22:29:39 +00:00
|
|
|
return cnf;
|
|
|
|
}
|
|
|
|
|
2006-01-20 00:18:42 +00:00
|
|
|
/*! \brief The MeetmeCount application */
|
2009-05-21 21:13:09 +00:00
|
|
|
static int count_exec(struct ast_channel *chan, const char *data)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
|
|
|
int res = 0;
|
2004-01-11 06:07:36 +00:00
|
|
|
struct ast_conference *conf;
|
|
|
|
int count;
|
2005-11-30 19:53:05 +00:00
|
|
|
char *localdata;
|
2017-12-22 14:23:22 +00:00
|
|
|
char val[80] = "0";
|
2005-11-30 19:53:05 +00:00
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(confno);
|
|
|
|
AST_APP_ARG(varname);
|
|
|
|
);
|
2004-01-11 06:07:36 +00:00
|
|
|
|
2005-10-26 19:48:14 +00:00
|
|
|
if (ast_strlen_zero(data)) {
|
2002-05-13 22:29:39 +00:00
|
|
|
ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2012-07-31 20:21:43 +00:00
|
|
|
localdata = ast_strdupa(data);
|
2005-11-30 19:53:05 +00:00
|
|
|
|
|
|
|
AST_STANDARD_APP_ARGS(args, localdata);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-21 01:05:00 +00:00
|
|
|
conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
|
2006-04-06 22:16:23 +00:00
|
|
|
|
2007-02-21 01:05:00 +00:00
|
|
|
if (conf) {
|
2004-01-11 06:07:36 +00:00
|
|
|
count = conf->users;
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(conf);
|
|
|
|
conf = NULL;
|
|
|
|
} else
|
2004-01-11 06:07:36 +00:00
|
|
|
count = 0;
|
|
|
|
|
2007-12-13 23:10:42 +00:00
|
|
|
if (!ast_strlen_zero(args.varname)) {
|
2004-01-11 06:07:36 +00:00
|
|
|
/* have var so load it and exit */
|
2007-12-13 23:10:42 +00:00
|
|
|
snprintf(val, sizeof(val), "%d", count);
|
2005-11-30 19:53:05 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, args.varname, val);
|
2004-01-11 06:07:36 +00:00
|
|
|
} else {
|
2012-02-20 23:43:27 +00:00
|
|
|
if (ast_channel_state(chan) != AST_STATE_UP) {
|
2004-01-11 06:07:36 +00:00
|
|
|
ast_answer(chan);
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
|
2003-08-20 23:32:23 +00:00
|
|
|
}
|
2005-11-08 21:32:51 +00:00
|
|
|
|
2002-05-13 22:29:39 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2006-01-20 00:18:42 +00:00
|
|
|
/*! \brief The meetme() application */
|
2009-05-21 21:13:09 +00:00
|
|
|
static int conf_exec(struct ast_channel *chan, const char *data)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2007-12-13 23:10:42 +00:00
|
|
|
int res = -1;
|
2007-02-10 00:40:57 +00:00
|
|
|
char confno[MAX_CONFNUM] = "";
|
2002-05-13 22:29:39 +00:00
|
|
|
int allowretry = 0;
|
|
|
|
int retrycnt = 0;
|
2007-02-21 01:05:00 +00:00
|
|
|
struct ast_conference *cnf = NULL;
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 confflags = {0};
|
|
|
|
struct ast_flags config_flags = { 0 };
|
2003-10-29 22:52:20 +00:00
|
|
|
int dynamic = 0;
|
2004-04-08 19:38:26 +00:00
|
|
|
int empty = 0, empty_no_pin = 0;
|
2005-02-02 02:57:45 +00:00
|
|
|
int always_prompt = 0;
|
2009-05-21 21:13:09 +00:00
|
|
|
const char *notdata;
|
|
|
|
char *info, the_pin[MAX_PIN] = "";
|
2005-11-30 19:53:05 +00:00
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(confno);
|
|
|
|
AST_APP_ARG(options);
|
|
|
|
AST_APP_ARG(pin);
|
|
|
|
);
|
2006-09-11 22:17:46 +00:00
|
|
|
char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
|
2003-09-28 21:18:51 +00:00
|
|
|
|
2005-10-26 19:48:14 +00:00
|
|
|
if (ast_strlen_zero(data)) {
|
2002-05-13 22:29:39 +00:00
|
|
|
allowretry = 1;
|
2004-01-11 06:31:42 +00:00
|
|
|
notdata = "";
|
|
|
|
} else {
|
|
|
|
notdata = data;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
if (ast_channel_state(chan) != AST_STATE_UP)
|
2002-05-13 22:29:39 +00:00
|
|
|
ast_answer(chan);
|
|
|
|
|
2005-10-19 18:19:02 +00:00
|
|
|
info = ast_strdupa(notdata);
|
2003-02-04 15:48:42 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
AST_STANDARD_APP_ARGS(args, info);
|
2005-11-30 19:53:05 +00:00
|
|
|
|
|
|
|
if (args.confno) {
|
|
|
|
ast_copy_string(confno, args.confno, sizeof(confno));
|
2004-05-27 14:35:26 +00:00
|
|
|
if (ast_strlen_zero(confno)) {
|
2004-01-11 06:31:42 +00:00
|
|
|
allowretry = 1;
|
|
|
|
}
|
2003-02-04 15:48:42 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2005-11-30 19:53:05 +00:00
|
|
|
if (args.pin)
|
|
|
|
ast_copy_string(the_pin, args.pin, sizeof(the_pin));
|
|
|
|
|
|
|
|
if (args.options) {
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
|
|
|
|
dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
|
|
|
|
if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
|
2005-07-07 23:17:04 +00:00
|
|
|
strcpy(the_pin, "q");
|
2005-03-12 05:37:32 +00:00
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
|
|
|
|
empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
|
|
|
|
always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
2004-01-11 06:07:36 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (retrycnt > 3)
|
|
|
|
allowretry = 0;
|
2004-04-08 19:38:26 +00:00
|
|
|
if (empty) {
|
2007-03-29 17:42:48 +00:00
|
|
|
int i;
|
2004-04-08 19:38:26 +00:00
|
|
|
struct ast_config *cfg;
|
|
|
|
struct ast_variable *var;
|
|
|
|
int confno_int;
|
|
|
|
|
2004-06-28 22:10:50 +00:00
|
|
|
/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
|
|
|
|
if ((empty_no_pin) || (!dynamic)) {
|
2007-08-16 21:09:46 +00:00
|
|
|
cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
|
2008-09-12 23:30:03 +00:00
|
|
|
if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
|
2004-06-28 22:10:50 +00:00
|
|
|
var = ast_variable_browse(cfg, "rooms");
|
2005-11-08 21:32:51 +00:00
|
|
|
while (var) {
|
2009-12-28 12:44:58 +00:00
|
|
|
char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
|
2004-06-28 22:10:50 +00:00
|
|
|
if (!strcasecmp(var->name, "conf")) {
|
2009-12-28 12:44:58 +00:00
|
|
|
int found = 0;
|
|
|
|
ast_copy_string(parse, var->value, sizeof(parse));
|
|
|
|
confno_tmp = strsep(&stringp, "|,");
|
|
|
|
if (!dynamic) {
|
|
|
|
/* For static: run through the list and see if this conference is empty */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
if (!strcmp(confno_tmp, cnf->confno)) {
|
|
|
|
/* The conference exists, therefore it's not empty */
|
|
|
|
found = 1;
|
|
|
|
break;
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2009-12-28 12:44:58 +00:00
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
2012-09-20 19:16:59 +00:00
|
|
|
cnf = NULL;
|
2009-12-28 12:44:58 +00:00
|
|
|
if (!found) {
|
|
|
|
/* At this point, we have a confno_tmp (static conference) that is empty */
|
|
|
|
if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
|
|
|
|
/* Case 1: empty_no_pin and pin is nonexistent (NULL)
|
|
|
|
* Case 2: empty_no_pin and pin is blank (but not NULL)
|
|
|
|
* Case 3: not empty_no_pin
|
|
|
|
*/
|
|
|
|
ast_copy_string(confno, confno_tmp, sizeof(confno));
|
|
|
|
break;
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-06-28 22:10:50 +00:00
|
|
|
var = var->next;
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2005-01-25 06:10:20 +00:00
|
|
|
ast_config_destroy(cfg);
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2010-07-21 15:56:05 +00:00
|
|
|
|
|
|
|
if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
|
|
|
|
const char *catg;
|
|
|
|
for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
|
|
|
|
const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
|
|
|
|
const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
|
|
|
|
if (ast_strlen_zero(confno_tmp)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!dynamic) {
|
|
|
|
int found = 0;
|
|
|
|
/* For static: run through the list and see if this conference is empty */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
if (!strcmp(confno_tmp, cnf->confno)) {
|
|
|
|
/* The conference exists, therefore it's not empty */
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
if (!found) {
|
|
|
|
/* At this point, we have a confno_tmp (realtime conference) that is empty */
|
|
|
|
if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
|
|
|
|
/* Case 1: empty_no_pin and pin is nonexistent (NULL)
|
|
|
|
* Case 2: empty_no_pin and pin is blank (but not NULL)
|
|
|
|
* Case 3: not empty_no_pin
|
|
|
|
*/
|
|
|
|
ast_copy_string(confno, confno_tmp, sizeof(confno));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_config_destroy(cfg);
|
|
|
|
}
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2004-04-08 19:38:26 +00:00
|
|
|
/* Select first conference number not in use */
|
2004-06-28 22:10:50 +00:00
|
|
|
if (ast_strlen_zero(confno) && dynamic) {
|
2007-03-29 17:42:48 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
2008-07-08 16:40:28 +00:00
|
|
|
for (i = 0; i < ARRAY_LEN(conf_map); i++) {
|
2007-03-29 17:42:48 +00:00
|
|
|
if (!conf_map[i]) {
|
2004-07-14 07:22:30 +00:00
|
|
|
snprintf(confno, sizeof(confno), "%d", i);
|
2007-03-29 17:42:48 +00:00
|
|
|
conf_map[i] = 1;
|
2004-04-08 19:38:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-03-29 17:42:48 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Not found? */
|
2004-05-27 14:35:26 +00:00
|
|
|
if (ast_strlen_zero(confno)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
|
2012-08-29 21:15:24 +00:00
|
|
|
ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
|
2004-04-08 19:38:26 +00:00
|
|
|
if (!res)
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
} else {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(confno, "%30d", &confno_int) == 1) {
|
2009-12-10 17:31:23 +00:00
|
|
|
if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
|
2006-11-13 17:55:24 +00:00
|
|
|
if (!res) {
|
|
|
|
ast_waitstream(chan, "");
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
|
2006-11-13 17:55:24 +00:00
|
|
|
}
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
2004-06-28 22:10:50 +00:00
|
|
|
} else {
|
|
|
|
ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
|
2004-04-08 19:38:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2004-05-27 14:35:26 +00:00
|
|
|
while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
|
2004-01-11 06:07:36 +00:00
|
|
|
/* Prompt user for conference number */
|
|
|
|
res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
|
|
|
|
if (res < 0) {
|
|
|
|
/* Don't try to validate when we catch an error */
|
2004-07-14 07:22:30 +00:00
|
|
|
confno[0] = '\0';
|
2004-01-11 06:07:36 +00:00
|
|
|
allowretry = 0;
|
|
|
|
break;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
2004-05-27 14:35:26 +00:00
|
|
|
if (!ast_strlen_zero(confno)) {
|
2004-01-11 06:07:36 +00:00
|
|
|
/* Check the validity of the conference */
|
2017-12-22 14:23:22 +00:00
|
|
|
cnf = find_conf(chan, confno, 1, dynamic, the_pin,
|
2007-02-10 00:40:57 +00:00
|
|
|
sizeof(the_pin), 1, &confflags);
|
|
|
|
if (!cnf) {
|
2007-10-17 15:13:51 +00:00
|
|
|
int too_early = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
cnf = find_conf_realtime(chan, confno, 1, dynamic,
|
2010-07-21 15:56:05 +00:00
|
|
|
the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
|
2007-10-17 15:13:51 +00:00
|
|
|
if (rt_schedule && too_early)
|
|
|
|
allowretry = 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2006-04-06 22:16:23 +00:00
|
|
|
|
2004-01-11 06:07:36 +00:00
|
|
|
if (!cnf) {
|
2007-10-17 15:13:51 +00:00
|
|
|
if (allowretry) {
|
2004-07-14 07:22:30 +00:00
|
|
|
confno[0] = '\0';
|
2012-01-24 20:12:09 +00:00
|
|
|
res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
|
2007-10-17 15:13:51 +00:00
|
|
|
if (!res)
|
|
|
|
ast_waitstream(chan, "");
|
|
|
|
res = -1;
|
|
|
|
}
|
2004-01-11 06:07:36 +00:00
|
|
|
} else {
|
2011-11-10 21:15:39 +00:00
|
|
|
/* Conference requires a pin for specified access level */
|
|
|
|
int req_pin = !ast_strlen_zero(cnf->pin) ||
|
2011-07-19 15:49:55 +00:00
|
|
|
(!ast_strlen_zero(cnf->pinadmin) &&
|
2011-11-10 21:15:39 +00:00
|
|
|
ast_test_flag64(&confflags, CONFFLAG_ADMIN));
|
|
|
|
/* The following logic was derived from a
|
|
|
|
* 4 variable truth table and defines which
|
|
|
|
* circumstances are not exempt from pin
|
|
|
|
* checking.
|
|
|
|
* If this needs to be modified, write the
|
|
|
|
* truth table back out from the boolean
|
|
|
|
* expression AB+A'D+C', change the erroneous
|
|
|
|
* result, and rederive the expression.
|
|
|
|
* Variables:
|
|
|
|
* A: pin provided?
|
|
|
|
* B: always prompt?
|
|
|
|
* C: dynamic?
|
|
|
|
* D: has users? */
|
|
|
|
int not_exempt = !cnf->isdynamic;
|
|
|
|
not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
|
|
|
|
not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
|
|
|
|
if (req_pin && not_exempt) {
|
2007-02-10 00:40:57 +00:00
|
|
|
char pin[MAX_PIN] = "";
|
2004-07-27 03:08:00 +00:00
|
|
|
int j;
|
|
|
|
|
|
|
|
/* Allow the pin to be retried up to 3 times */
|
2005-11-08 21:32:51 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
if (*the_pin && (always_prompt == 0)) {
|
2005-07-07 23:17:04 +00:00
|
|
|
ast_copy_string(pin, the_pin, sizeof(pin));
|
2004-07-27 03:08:00 +00:00
|
|
|
res = 0;
|
|
|
|
} else {
|
|
|
|
/* Prompt user for pin if pin is required */
|
2012-08-29 21:15:24 +00:00
|
|
|
ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
|
|
|
|
"Channel: %s",
|
2012-08-29 22:40:18 +00:00
|
|
|
ast_channel_name(chan));
|
2004-07-27 03:10:26 +00:00
|
|
|
res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
|
2004-07-27 03:08:00 +00:00
|
|
|
}
|
|
|
|
if (res >= 0) {
|
2010-09-21 00:04:54 +00:00
|
|
|
if ((!strcasecmp(pin, cnf->pin) &&
|
|
|
|
(ast_strlen_zero(cnf->pinadmin) ||
|
|
|
|
!ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
|
|
|
|
(!ast_strlen_zero(cnf->pinadmin) &&
|
|
|
|
!strcasecmp(pin, cnf->pinadmin))) {
|
2004-07-27 03:08:00 +00:00
|
|
|
/* Pin correct */
|
|
|
|
allowretry = 0;
|
2008-10-01 23:02:25 +00:00
|
|
|
if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
|
2008-10-17 04:28:13 +00:00
|
|
|
if (!ast_strlen_zero(cnf->adminopts)) {
|
|
|
|
char *opts = ast_strdupa(cnf->adminopts);
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
|
2008-10-17 04:28:13 +00:00
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
} else {
|
2008-10-17 04:28:13 +00:00
|
|
|
if (!ast_strlen_zero(cnf->useropts)) {
|
|
|
|
char *opts = ast_strdupa(cnf->useropts);
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
|
2008-10-17 04:28:13 +00:00
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2004-07-27 03:08:00 +00:00
|
|
|
/* Run the conference */
|
2009-03-03 22:01:24 +00:00
|
|
|
ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
|
2009-12-10 17:31:23 +00:00
|
|
|
res = conf_run(chan, cnf, &confflags, optargs);
|
2004-07-27 03:08:00 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/* Pin invalid */
|
2012-01-24 20:12:09 +00:00
|
|
|
if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
|
2006-05-07 13:39:32 +00:00
|
|
|
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
2006-09-28 16:19:22 +00:00
|
|
|
ast_stopstream(chan);
|
2008-10-17 04:28:13 +00:00
|
|
|
} else {
|
2006-05-07 13:39:32 +00:00
|
|
|
ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
|
|
|
|
break;
|
|
|
|
}
|
2007-02-21 01:05:00 +00:00
|
|
|
if (res < 0)
|
2004-07-27 03:10:26 +00:00
|
|
|
break;
|
|
|
|
pin[0] = res;
|
|
|
|
pin[1] = '\0';
|
2004-07-27 03:08:00 +00:00
|
|
|
res = -1;
|
|
|
|
if (allowretry)
|
|
|
|
confno[0] = '\0';
|
|
|
|
}
|
2004-01-13 04:42:39 +00:00
|
|
|
} else {
|
2005-07-07 22:36:40 +00:00
|
|
|
/* failed when getting the pin */
|
2004-01-13 04:42:39 +00:00
|
|
|
res = -1;
|
2004-07-27 03:08:00 +00:00
|
|
|
allowretry = 0;
|
2005-07-07 22:36:40 +00:00
|
|
|
/* see if we need to get rid of the conference */
|
2004-07-27 03:08:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't retry pin with a static pin */
|
2007-12-13 23:10:42 +00:00
|
|
|
if (*the_pin && (always_prompt == 0)) {
|
2004-07-27 03:08:00 +00:00
|
|
|
break;
|
2004-01-12 23:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* No pin required */
|
|
|
|
allowretry = 0;
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/* For RealTime conferences without a pin
|
2010-04-02 23:55:57 +00:00
|
|
|
* should still support loading options
|
|
|
|
*/
|
|
|
|
if (!ast_strlen_zero(cnf->useropts)) {
|
|
|
|
char *opts = ast_strdupa(cnf->useropts);
|
|
|
|
ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
|
|
|
|
}
|
|
|
|
|
2004-01-12 23:21:29 +00:00
|
|
|
/* Run the conference */
|
2009-12-10 17:31:23 +00:00
|
|
|
res = conf_run(chan, cnf, &confflags, optargs);
|
2004-01-11 06:07:36 +00:00
|
|
|
}
|
2007-02-21 20:18:16 +00:00
|
|
|
dispose_conf(cnf);
|
|
|
|
cnf = NULL;
|
|
|
|
}
|
2004-01-11 06:07:36 +00:00
|
|
|
}
|
|
|
|
} while (allowretry);
|
2007-02-21 01:05:00 +00:00
|
|
|
|
|
|
|
if (cnf)
|
|
|
|
dispose_conf(cnf);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2002-05-13 22:29:39 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-06-29 23:50:46 +00:00
|
|
|
static struct ast_conf_user *find_user(struct ast_conference *conf, const char *callerident)
|
2005-12-20 13:07:02 +00:00
|
|
|
{
|
2004-05-22 04:11:22 +00:00
|
|
|
struct ast_conf_user *user = NULL;
|
2005-12-20 13:07:02 +00:00
|
|
|
int cid;
|
2012-05-29 22:37:19 +00:00
|
|
|
|
|
|
|
if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
|
2010-07-13 17:37:40 +00:00
|
|
|
user = ao2_find(conf->usercontainer, &cid, 0);
|
|
|
|
/* reference decremented later in admin_exec */
|
|
|
|
return user;
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
static int user_listen_volup_cb(void *obj, void *unused, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
tweak_listen_volume(user, VOL_UP);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
tweak_listen_volume(user, VOL_DOWN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_talk_volup_cb(void *obj, void *unused, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
tweak_talk_volume(user, VOL_UP);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
tweak_talk_volume(user, VOL_DOWN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_reset_vol_cb(void *obj, void *unused, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
reset_volumes(user);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_chan_cb(void *obj, void *args, int flags)
|
|
|
|
{
|
|
|
|
struct ast_conf_user *user = obj;
|
|
|
|
const char *channel = args;
|
|
|
|
|
2012-01-09 22:15:50 +00:00
|
|
|
if (!strcmp(ast_channel_name(user->chan), channel)) {
|
2010-07-13 17:37:40 +00:00
|
|
|
return (CMP_MATCH | CMP_STOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-31 01:04:41 +00:00
|
|
|
/*! \brief The MeetMeAdmin application
|
2009-08-18 18:57:28 +00:00
|
|
|
|
|
|
|
MeetMeAdmin(confno, command, caller) */
|
2009-05-21 21:13:09 +00:00
|
|
|
static int admin_exec(struct ast_channel *chan, const char *data) {
|
2005-11-30 19:53:05 +00:00
|
|
|
char *params;
|
2004-05-22 04:11:22 +00:00
|
|
|
struct ast_conference *cnf;
|
|
|
|
struct ast_conf_user *user = NULL;
|
2005-11-30 19:53:05 +00:00
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(confno);
|
|
|
|
AST_APP_ARG(command);
|
|
|
|
AST_APP_ARG(user);
|
|
|
|
);
|
2008-10-01 23:02:25 +00:00
|
|
|
int res = 0;
|
2006-07-03 05:32:08 +00:00
|
|
|
|
|
|
|
if (ast_strlen_zero(data)) {
|
|
|
|
ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
|
2022-03-31 15:44:23 +00:00
|
|
|
if (chan) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
|
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
params = ast_strdupa(data);
|
|
|
|
AST_STANDARD_APP_ARGS(args, params);
|
2005-11-30 19:53:05 +00:00
|
|
|
|
2006-07-03 05:32:08 +00:00
|
|
|
if (!args.command) {
|
|
|
|
ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
|
2022-03-31 15:44:23 +00:00
|
|
|
if (chan) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
|
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-05-07 22:17:40 +00:00
|
|
|
|
|
|
|
AST_LIST_LOCK(&confs);
|
2006-07-03 05:32:08 +00:00
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
if (!strcmp(cnf->confno, args.confno))
|
|
|
|
break;
|
|
|
|
}
|
2005-11-30 19:53:05 +00:00
|
|
|
|
2006-07-03 05:32:08 +00:00
|
|
|
if (!cnf) {
|
|
|
|
ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
2022-03-31 15:44:23 +00:00
|
|
|
if (chan) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
|
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-21 01:05:00 +00:00
|
|
|
ast_atomic_fetchadd_int(&cnf->refcount, 1);
|
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
if (args.user) {
|
2006-07-03 05:32:08 +00:00
|
|
|
user = find_user(cnf, args.user);
|
2010-07-13 17:37:40 +00:00
|
|
|
if (!user) {
|
|
|
|
ast_log(LOG_NOTICE, "Specified User not found!\n");
|
|
|
|
res = -2;
|
|
|
|
goto usernotfound;
|
|
|
|
}
|
2013-09-13 14:17:15 +00:00
|
|
|
} else {
|
|
|
|
/* fail for commands that require a user */
|
|
|
|
switch (*args.command) {
|
|
|
|
case 'm': /* Unmute */
|
|
|
|
case 'M': /* Mute */
|
|
|
|
case 't': /* Lower user's talk volume */
|
|
|
|
case 'T': /* Raise user's talk volume */
|
|
|
|
case 'u': /* Lower user's listen volume */
|
|
|
|
case 'U': /* Raise user's listen volume */
|
|
|
|
case 'r': /* Reset user's volume level */
|
|
|
|
case 'k': /* Kick user */
|
|
|
|
res = -2;
|
|
|
|
ast_log(LOG_NOTICE, "No user specified!\n");
|
|
|
|
goto usernotfound;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
|
|
|
|
switch (*args.command) {
|
2017-12-22 14:23:22 +00:00
|
|
|
case 76: /* L: Lock */
|
2006-07-03 05:32:08 +00:00
|
|
|
cnf->locked = 1;
|
|
|
|
break;
|
2017-12-22 14:23:22 +00:00
|
|
|
case 108: /* l: Unlock */
|
2006-07-03 05:32:08 +00:00
|
|
|
cnf->locked = 0;
|
|
|
|
break;
|
|
|
|
case 75: /* K: kick all users */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 101: /* e: Eject last user*/
|
2010-07-13 17:37:40 +00:00
|
|
|
{
|
|
|
|
int max_no = 0;
|
2013-09-13 14:17:15 +00:00
|
|
|
RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
|
2012-04-06 20:32:52 +00:00
|
|
|
|
2013-09-13 14:17:15 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
|
|
|
|
eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
|
|
|
|
if (!eject_user) {
|
|
|
|
res = -1;
|
|
|
|
ast_log(LOG_NOTICE, "No last user to kick!\n");
|
|
|
|
break;
|
2012-04-06 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
2013-09-13 14:17:15 +00:00
|
|
|
if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
|
|
|
|
eject_user->adminflags |= ADMINFLAG_KICKME;
|
|
|
|
} else {
|
2008-10-01 23:02:25 +00:00
|
|
|
res = -1;
|
2006-07-03 05:32:08 +00:00
|
|
|
ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
2010-07-13 17:37:40 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
case 77: /* M: Mute */
|
2010-07-13 17:37:40 +00:00
|
|
|
user->adminflags |= ADMINFLAG_MUTED;
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 78: /* N: Mute all (non-admin) users */
|
2012-04-04 13:51:45 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, &cnf);
|
2017-12-22 14:23:22 +00:00
|
|
|
break;
|
|
|
|
case 109: /* m: Unmute */
|
2010-07-13 17:37:40 +00:00
|
|
|
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 110: /* n: Unmute all users */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
2017-12-22 14:23:22 +00:00
|
|
|
case 107: /* k: Kick user */
|
2010-07-13 17:37:40 +00:00
|
|
|
user->adminflags |= ADMINFLAG_KICKME;
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 118: /* v: Lower all users listen volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 86: /* V: Raise all users listen volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 115: /* s: Lower all users speaking volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 83: /* S: Raise all users speaking volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 82: /* R: Reset all volume levels */
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 114: /* r: Reset user's volume level */
|
2010-07-13 17:37:40 +00:00
|
|
|
reset_volumes(user);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 85: /* U: Raise user's listen volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
tweak_listen_volume(user, VOL_UP);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 117: /* u: Lower user's listen volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
tweak_listen_volume(user, VOL_DOWN);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 84: /* T: Raise user's talk volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
tweak_talk_volume(user, VOL_UP);
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
|
|
|
case 116: /* t: Lower user's talk volume */
|
2010-07-13 17:37:40 +00:00
|
|
|
tweak_talk_volume(user, VOL_DOWN);
|
2008-10-01 23:02:25 +00:00
|
|
|
break;
|
|
|
|
case 'E': /* E: Extend conference */
|
|
|
|
if (rt_extend_conf(args.confno)) {
|
|
|
|
res = -1;
|
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
break;
|
2004-05-22 04:11:22 +00:00
|
|
|
}
|
2006-07-03 05:32:08 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
if (args.user) {
|
|
|
|
/* decrement reference from find_user */
|
|
|
|
ao2_ref(user, -1);
|
|
|
|
}
|
|
|
|
usernotfound:
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-10-19 18:19:02 +00:00
|
|
|
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(cnf);
|
2022-03-31 15:44:23 +00:00
|
|
|
if (chan) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
|
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
|
2004-05-22 04:11:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! \brief The MeetMeChannelAdmin application
|
2009-08-18 18:57:28 +00:00
|
|
|
MeetMeChannelAdmin(channel, command) */
|
2009-05-21 21:13:09 +00:00
|
|
|
static int channel_admin_exec(struct ast_channel *chan, const char *data) {
|
2007-05-07 22:14:09 +00:00
|
|
|
char *params;
|
|
|
|
struct ast_conference *conf = NULL;
|
|
|
|
struct ast_conf_user *user = NULL;
|
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(channel);
|
|
|
|
AST_APP_ARG(command);
|
|
|
|
);
|
|
|
|
|
|
|
|
if (ast_strlen_zero(data)) {
|
|
|
|
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-05-07 22:14:09 +00:00
|
|
|
params = ast_strdupa(data);
|
|
|
|
AST_STANDARD_APP_ARGS(args, params);
|
|
|
|
|
|
|
|
if (!args.channel) {
|
|
|
|
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!args.command) {
|
|
|
|
ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, conf, list) {
|
2010-07-13 17:37:40 +00:00
|
|
|
if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
|
|
|
|
break;
|
2007-05-07 22:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-05-07 22:14:09 +00:00
|
|
|
if (!user) {
|
|
|
|
ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-05-07 22:14:09 +00:00
|
|
|
/* perform the specified action */
|
2007-05-07 22:17:40 +00:00
|
|
|
switch (*args.command) {
|
2017-12-22 14:23:22 +00:00
|
|
|
case 77: /* M: Mute */
|
2007-05-07 22:14:09 +00:00
|
|
|
user->adminflags |= ADMINFLAG_MUTED;
|
|
|
|
break;
|
2017-12-22 14:23:22 +00:00
|
|
|
case 109: /* m: Unmute */
|
2007-05-07 22:14:09 +00:00
|
|
|
user->adminflags &= ~ADMINFLAG_MUTED;
|
|
|
|
break;
|
2017-12-22 14:23:22 +00:00
|
|
|
case 107: /* k: Kick user */
|
2007-05-07 22:14:09 +00:00
|
|
|
user->adminflags |= ADMINFLAG_KICKME;
|
|
|
|
break;
|
|
|
|
default: /* unknown command */
|
|
|
|
ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
|
|
|
|
break;
|
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_ref(user, -1);
|
2007-05-07 22:14:09 +00:00
|
|
|
AST_LIST_UNLOCK(&confs);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-05-07 22:14:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-05 22:43:18 +00:00
|
|
|
static int meetmemute(struct mansession *s, const struct message *m, int mute)
|
2006-05-23 16:35:46 +00:00
|
|
|
{
|
|
|
|
struct ast_conference *conf;
|
|
|
|
struct ast_conf_user *user;
|
2007-01-05 22:43:18 +00:00
|
|
|
const char *confid = astman_get_header(m, "Meetme");
|
|
|
|
char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
|
2006-05-23 16:35:46 +00:00
|
|
|
int userno;
|
|
|
|
|
2006-06-09 19:05:30 +00:00
|
|
|
if (ast_strlen_zero(confid)) {
|
2006-05-23 16:35:46 +00:00
|
|
|
astman_send_error(s, m, "Meetme conference not specified");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-09 19:05:30 +00:00
|
|
|
if (ast_strlen_zero(userid)) {
|
2006-05-23 16:35:46 +00:00
|
|
|
astman_send_error(s, m, "Meetme user number not specified");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
userno = strtoul(userid, &userid, 10);
|
|
|
|
|
|
|
|
if (*userid) {
|
|
|
|
astman_send_error(s, m, "Invalid user number");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look in the conference list */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, conf, list) {
|
|
|
|
if (!strcmp(confid, conf->confno))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!conf) {
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
astman_send_error(s, m, "Meetme conference does not exist");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
user = ao2_find(conf->usercontainer, &userno, 0);
|
2006-05-23 16:35:46 +00:00
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
astman_send_error(s, m, "User number not found");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mute)
|
|
|
|
user->adminflags |= ADMINFLAG_MUTED; /* request user muting */
|
|
|
|
else
|
2007-10-25 18:59:22 +00:00
|
|
|
user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
|
2006-05-23 16:35:46 +00:00
|
|
|
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, ast_channel_name(user->chan), ast_channel_uniqueid(user->chan));
|
2006-05-23 16:35:46 +00:00
|
|
|
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_ref(user, -1);
|
2006-05-23 16:35:46 +00:00
|
|
|
astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-05 22:43:18 +00:00
|
|
|
static int action_meetmemute(struct mansession *s, const struct message *m)
|
2006-05-23 16:35:46 +00:00
|
|
|
{
|
|
|
|
return meetmemute(s, m, 1);
|
|
|
|
}
|
|
|
|
|
2007-01-05 22:43:18 +00:00
|
|
|
static int action_meetmeunmute(struct mansession *s, const struct message *m)
|
2006-05-23 16:35:46 +00:00
|
|
|
{
|
|
|
|
return meetmemute(s, m, 0);
|
|
|
|
}
|
|
|
|
|
2007-09-22 14:03:48 +00:00
|
|
|
static int action_meetmelist(struct mansession *s, const struct message *m)
|
|
|
|
{
|
|
|
|
const char *actionid = astman_get_header(m, "ActionID");
|
|
|
|
const char *conference = astman_get_header(m, "Conference");
|
|
|
|
char idText[80] = "";
|
|
|
|
struct ast_conference *cnf;
|
|
|
|
struct ast_conf_user *user;
|
2010-07-13 17:37:40 +00:00
|
|
|
struct ao2_iterator user_iter;
|
2007-09-22 14:03:48 +00:00
|
|
|
int total = 0;
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(actionid))
|
|
|
|
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
|
|
|
|
|
|
|
|
if (AST_LIST_EMPTY(&confs)) {
|
|
|
|
astman_send_error(s, m, "No active conferences.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-12 18:09:27 +00:00
|
|
|
astman_send_listack(s, m, "Meetme user list will follow", "start");
|
2007-09-22 14:03:48 +00:00
|
|
|
|
|
|
|
/* Find the right conference */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
/* If we ask for one particular, and this isn't it, skip it */
|
|
|
|
if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Show all the users */
|
2011-03-22 15:26:51 +00:00
|
|
|
user_iter = ao2_iterator_init(cnf->usercontainer, 0);
|
2010-07-13 17:37:40 +00:00
|
|
|
while ((user = ao2_iterator_next(&user_iter))) {
|
2007-09-22 14:03:48 +00:00
|
|
|
total++;
|
|
|
|
astman_append(s,
|
2010-07-14 15:48:36 +00:00
|
|
|
"Event: MeetmeList\r\n"
|
|
|
|
"%s"
|
|
|
|
"Conference: %s\r\n"
|
|
|
|
"UserNumber: %d\r\n"
|
|
|
|
"CallerIDNum: %s\r\n"
|
|
|
|
"CallerIDName: %s\r\n"
|
2011-05-25 17:14:11 +00:00
|
|
|
"ConnectedLineNum: %s\r\n"
|
|
|
|
"ConnectedLineName: %s\r\n"
|
2010-07-14 15:48:36 +00:00
|
|
|
"Channel: %s\r\n"
|
|
|
|
"Admin: %s\r\n"
|
|
|
|
"Role: %s\r\n"
|
|
|
|
"MarkedUser: %s\r\n"
|
|
|
|
"Muted: %s\r\n"
|
|
|
|
"Talking: %s\r\n"
|
|
|
|
"\r\n",
|
|
|
|
idText,
|
|
|
|
cnf->confno,
|
|
|
|
user->user_no,
|
2012-02-29 16:52:47 +00:00
|
|
|
S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
|
|
|
|
S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
|
|
|
|
S_COR(ast_channel_connected(user->chan)->id.number.valid, ast_channel_connected(user->chan)->id.number.str, "<unknown>"),
|
|
|
|
S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(user->chan),
|
2010-07-14 15:48:36 +00:00
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
|
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
|
|
|
|
ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
|
|
|
|
user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
|
|
|
|
user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_ref(user, -1);
|
2007-09-22 14:03:48 +00:00
|
|
|
}
|
2010-07-13 17:37:40 +00:00
|
|
|
ao2_iterator_destroy(&user_iter);
|
2007-09-22 14:03:48 +00:00
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
2015-01-09 18:16:54 +00:00
|
|
|
|
2007-09-22 14:03:48 +00:00
|
|
|
/* Send final confirmation */
|
2015-01-09 18:16:54 +00:00
|
|
|
astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
|
|
|
|
astman_send_list_complete_end(s);
|
2007-09-22 14:03:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-09 22:48:02 +00:00
|
|
|
static int action_meetmelistrooms(struct mansession *s, const struct message *m)
|
|
|
|
{
|
|
|
|
const char *actionid = astman_get_header(m, "ActionID");
|
|
|
|
char idText[80] = "";
|
|
|
|
struct ast_conference *cnf;
|
|
|
|
int totalitems = 0;
|
|
|
|
int hr, min, sec;
|
|
|
|
time_t now;
|
|
|
|
char markedusers[5];
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(actionid)) {
|
|
|
|
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AST_LIST_EMPTY(&confs)) {
|
|
|
|
astman_send_error(s, m, "No active conferences.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-12 18:09:27 +00:00
|
|
|
astman_send_listack(s, m, "Meetme conferences will follow", "start");
|
2011-02-09 22:48:02 +00:00
|
|
|
|
|
|
|
now = time(NULL);
|
|
|
|
|
|
|
|
/* Traverse the conference list */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, cnf, list) {
|
|
|
|
totalitems++;
|
|
|
|
|
|
|
|
if (cnf->markedusers == 0) {
|
|
|
|
strcpy(markedusers, "N/A");
|
|
|
|
} else {
|
|
|
|
sprintf(markedusers, "%.4d", cnf->markedusers);
|
|
|
|
}
|
|
|
|
hr = (now - cnf->start) / 3600;
|
|
|
|
min = ((now - cnf->start) % 3600) / 60;
|
|
|
|
sec = (now - cnf->start) % 60;
|
|
|
|
|
|
|
|
astman_append(s,
|
|
|
|
"Event: MeetmeListRooms\r\n"
|
|
|
|
"%s"
|
|
|
|
"Conference: %s\r\n"
|
|
|
|
"Parties: %d\r\n"
|
|
|
|
"Marked: %s\r\n"
|
|
|
|
"Activity: %2.2d:%2.2d:%2.2d\r\n"
|
|
|
|
"Creation: %s\r\n"
|
|
|
|
"Locked: %s\r\n"
|
|
|
|
"\r\n",
|
|
|
|
idText,
|
|
|
|
cnf->confno,
|
|
|
|
cnf->users,
|
|
|
|
markedusers,
|
|
|
|
hr, min, sec,
|
|
|
|
cnf->isdynamic ? "Dynamic" : "Static",
|
2017-12-22 14:23:22 +00:00
|
|
|
cnf->locked ? "Yes" : "No");
|
2011-02-09 22:48:02 +00:00
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
|
|
|
/* Send final confirmation */
|
2015-01-09 18:16:54 +00:00
|
|
|
astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
|
|
|
|
astman_send_list_complete_end(s);
|
2011-02-09 22:48:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-13 15:38:08 +00:00
|
|
|
/*! \internal
|
|
|
|
* \brief creates directory structure and assigns absolute path from relative paths for filenames
|
|
|
|
*
|
|
|
|
* \param filename contains the absolute or relative path to the desired file
|
|
|
|
* \param buffer stores completed filename, absolutely must be a buffer of PATH_MAX length
|
|
|
|
*/
|
|
|
|
static void filename_parse(char *filename, char *buffer)
|
|
|
|
{
|
|
|
|
char *slash;
|
|
|
|
if (ast_strlen_zero(filename)) {
|
|
|
|
ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
|
|
|
|
} else if (filename[0] != '/') {
|
|
|
|
snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
|
|
|
|
} else {
|
|
|
|
ast_copy_string(buffer, filename, PATH_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
slash = buffer;
|
|
|
|
if ((slash = strrchr(slash, '/'))) {
|
|
|
|
*slash = '\0';
|
|
|
|
ast_mkdir(buffer, 0777);
|
|
|
|
*slash = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-22 04:51:30 +00:00
|
|
|
static void *recordthread(void *args)
|
|
|
|
{
|
2005-11-08 21:32:51 +00:00
|
|
|
struct ast_conference *cnf = args;
|
2007-12-13 23:10:42 +00:00
|
|
|
struct ast_frame *f = NULL;
|
2005-01-22 04:51:30 +00:00
|
|
|
int flags;
|
2007-12-13 23:10:42 +00:00
|
|
|
struct ast_filestream *s = NULL;
|
|
|
|
int res = 0;
|
2005-12-20 13:07:02 +00:00
|
|
|
int x;
|
|
|
|
const char *oldrecordingfilename = NULL;
|
2012-04-13 15:38:08 +00:00
|
|
|
char filename_buffer[PATH_MAX];
|
2005-01-22 04:51:30 +00:00
|
|
|
|
2005-12-26 00:47:28 +00:00
|
|
|
if (!cnf || !cnf->lchan) {
|
2005-02-01 06:48:50 +00:00
|
|
|
pthread_exit(0);
|
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
|
2012-04-13 15:38:08 +00:00
|
|
|
filename_buffer[0] = '\0';
|
|
|
|
filename_parse(cnf->recordingfilename, filename_buffer);
|
|
|
|
|
2005-12-26 00:47:28 +00:00
|
|
|
ast_stopstream(cnf->lchan);
|
2007-07-31 01:10:47 +00:00
|
|
|
flags = O_CREAT | O_TRUNC | O_WRONLY;
|
2005-01-22 04:51:30 +00:00
|
|
|
|
2005-12-20 13:07:02 +00:00
|
|
|
|
|
|
|
cnf->recording = MEETME_RECORD_ACTIVE;
|
2005-12-26 00:47:28 +00:00
|
|
|
while (ast_waitfor(cnf->lchan, -1) > -1) {
|
2005-12-20 13:07:02 +00:00
|
|
|
if (cnf->recording == MEETME_RECORD_TERMINATE) {
|
2006-01-26 19:33:27 +00:00
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
2005-12-20 13:07:02 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-04-13 15:38:08 +00:00
|
|
|
if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
|
|
|
|
s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
|
|
|
|
oldrecordingfilename = filename_buffer;
|
2005-12-20 13:07:02 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2005-12-26 00:47:28 +00:00
|
|
|
f = ast_read(cnf->lchan);
|
2005-12-20 13:07:02 +00:00
|
|
|
if (!f) {
|
|
|
|
res = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (f->frametype == AST_FRAME_VOICE) {
|
|
|
|
ast_mutex_lock(&cnf->listenlock);
|
2007-12-13 23:10:42 +00:00
|
|
|
for (x = 0; x < AST_FRAME_BITS; x++) {
|
2005-12-20 13:07:02 +00:00
|
|
|
/* Free any translations that have occured */
|
|
|
|
if (cnf->transframe[x]) {
|
|
|
|
ast_frfree(cnf->transframe[x]);
|
|
|
|
cnf->transframe[x] = NULL;
|
|
|
|
}
|
2005-01-22 04:51:30 +00:00
|
|
|
}
|
2005-12-25 01:27:47 +00:00
|
|
|
if (cnf->origframe)
|
|
|
|
ast_frfree(cnf->origframe);
|
2007-07-18 12:38:36 +00:00
|
|
|
cnf->origframe = ast_frdup(f);
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_mutex_unlock(&cnf->listenlock);
|
|
|
|
if (s)
|
2005-01-22 04:51:30 +00:00
|
|
|
res = ast_writestream(s, f);
|
2005-12-20 13:07:02 +00:00
|
|
|
if (res) {
|
|
|
|
ast_frfree(f);
|
2005-01-22 04:51:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
ast_frfree(f);
|
2005-01-22 04:51:30 +00:00
|
|
|
}
|
2005-12-20 13:07:02 +00:00
|
|
|
cnf->recording = MEETME_RECORD_OFF;
|
|
|
|
if (s)
|
|
|
|
ast_closestream(s);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2005-01-22 04:51:30 +00:00
|
|
|
pthread_exit(0);
|
|
|
|
}
|
|
|
|
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
/*! \brief Callback for devicestate providers */
|
2007-02-13 22:02:20 +00:00
|
|
|
static enum ast_device_state meetmestate(const char *data)
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
{
|
|
|
|
struct ast_conference *conf;
|
|
|
|
|
|
|
|
/* Find conference */
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, conf, list) {
|
|
|
|
if (!strcmp(data, conf->confno))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
if (!conf)
|
|
|
|
return AST_DEVICE_INVALID;
|
|
|
|
|
|
|
|
|
|
|
|
/* SKREP to fill */
|
|
|
|
if (!conf->users)
|
|
|
|
return AST_DEVICE_NOT_INUSE;
|
|
|
|
|
|
|
|
return AST_DEVICE_INUSE;
|
|
|
|
}
|
|
|
|
|
2014-12-06 17:36:21 +00:00
|
|
|
static void meetme_set_defaults(void)
|
|
|
|
{
|
|
|
|
/* Scheduling support is off by default */
|
|
|
|
rt_schedule = 0;
|
|
|
|
fuzzystart = 0;
|
|
|
|
earlyalert = 0;
|
|
|
|
endalert = 0;
|
|
|
|
extendby = 0;
|
|
|
|
|
|
|
|
/* Logging of participants defaults to ON for compatibility reasons */
|
|
|
|
rt_log_members = 1;
|
2015-12-07 19:07:32 +00:00
|
|
|
|
|
|
|
/* Set default number of buffers to be allocated. */
|
|
|
|
audio_buffers = DEFAULT_AUDIO_BUFFERS;
|
2014-12-06 17:36:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void load_config_meetme(int reload)
|
2005-11-08 23:19:30 +00:00
|
|
|
{
|
|
|
|
struct ast_config *cfg;
|
2007-08-16 21:09:46 +00:00
|
|
|
struct ast_flags config_flags = { 0 };
|
2006-09-20 20:40:39 +00:00
|
|
|
const char *val;
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2014-12-06 17:36:21 +00:00
|
|
|
if (!reload) {
|
|
|
|
meetme_set_defaults();
|
|
|
|
}
|
|
|
|
|
2008-09-12 23:30:03 +00:00
|
|
|
if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
|
|
|
|
return;
|
|
|
|
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
|
|
|
|
ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
|
2005-11-08 23:19:30 +00:00
|
|
|
return;
|
2008-09-12 23:30:03 +00:00
|
|
|
}
|
2005-11-08 23:19:30 +00:00
|
|
|
|
2014-12-06 17:36:21 +00:00
|
|
|
if (reload) {
|
|
|
|
meetme_set_defaults();
|
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2005-11-08 23:19:30 +00:00
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
|
2005-11-08 23:19:30 +00:00
|
|
|
ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
|
|
|
|
audio_buffers = DEFAULT_AUDIO_BUFFERS;
|
2008-06-12 17:27:55 +00:00
|
|
|
} else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
|
2005-11-08 23:19:30 +00:00
|
|
|
ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
|
2008-06-12 17:27:55 +00:00
|
|
|
DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
|
2005-11-08 23:19:30 +00:00
|
|
|
audio_buffers = DEFAULT_AUDIO_BUFFERS;
|
|
|
|
}
|
|
|
|
if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
|
|
|
|
ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
|
|
|
|
}
|
|
|
|
|
2007-10-17 15:13:51 +00:00
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
|
|
|
|
rt_schedule = ast_true(val);
|
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
|
|
|
|
rt_log_members = ast_true(val);
|
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
|
|
|
|
fuzzystart = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(val, "%30d", &earlyalert) != 1)) {
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
|
|
|
|
earlyalert = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(val, "%30d", &endalert) != 1)) {
|
2007-10-17 15:13:51 +00:00
|
|
|
ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
|
|
|
|
endalert = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if ((sscanf(val, "%30d", &extendby) != 1)) {
|
2008-10-01 23:02:25 +00:00
|
|
|
ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
|
|
|
|
extendby = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
}
|
2008-10-01 23:02:25 +00:00
|
|
|
}
|
2007-10-17 15:13:51 +00:00
|
|
|
|
2005-11-08 23:19:30 +00:00
|
|
|
ast_config_destroy(cfg);
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \brief Find an SLA trunk by name
|
2007-02-10 00:40:57 +00:00
|
|
|
*/
|
2007-02-22 23:12:26 +00:00
|
|
|
static struct sla_trunk *sla_find_trunk(const char *name)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct sla_trunk tmp_trunk = {
|
|
|
|
.name = name,
|
|
|
|
};
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \brief Find an SLA station by name
|
2007-02-10 00:40:57 +00:00
|
|
|
*/
|
2007-02-22 23:12:26 +00:00
|
|
|
static struct sla_station *sla_find_station(const char *name)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct sla_station tmp_station = {
|
|
|
|
.name = name,
|
|
|
|
};
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2007-03-08 20:56:57 +00:00
|
|
|
static int sla_check_station_hold_access(const struct sla_trunk *trunk,
|
|
|
|
const struct sla_station *station)
|
2007-02-28 22:09:33 +00:00
|
|
|
{
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
|
|
|
/* For each station that has this call on hold, check for private hold. */
|
|
|
|
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
|
|
|
|
AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
|
2007-03-08 20:56:57 +00:00
|
|
|
if (trunk_ref->trunk != trunk || station_ref->station == station)
|
2007-02-28 22:09:33 +00:00
|
|
|
continue;
|
2007-03-08 20:56:57 +00:00
|
|
|
if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
|
2007-02-28 22:09:33 +00:00
|
|
|
station_ref->station->hold_access == SLA_HOLD_PRIVATE)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \brief Find a trunk reference on a station by name
|
2007-02-28 19:57:41 +00:00
|
|
|
* \param station the station
|
|
|
|
* \param name the trunk's name
|
2013-07-10 01:56:15 +00:00
|
|
|
* \pre sla_station is locked
|
2007-02-28 19:57:41 +00:00
|
|
|
* \return a pointer to the station's trunk reference. If the trunk
|
2007-02-28 22:09:33 +00:00
|
|
|
* is not found, it is not idle and barge is disabled, or if
|
|
|
|
* it is on hold and private hold is set, then NULL will be returned.
|
2007-02-28 19:57:41 +00:00
|
|
|
*/
|
2007-02-28 18:21:47 +00:00
|
|
|
static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
|
2007-02-10 00:40:57 +00:00
|
|
|
const char *name)
|
2006-07-01 23:54:43 +00:00
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref = NULL;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
2007-02-28 19:57:41 +00:00
|
|
|
if (strcasecmp(trunk_ref->trunk->name, name))
|
|
|
|
continue;
|
2007-02-28 22:09:33 +00:00
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
if ( (trunk_ref->trunk->barge_disabled
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
&& trunk_ref->state == SLA_TRUNK_STATE_UP) ||
|
2017-12-22 14:23:22 +00:00
|
|
|
(trunk_ref->trunk->hold_stations
|
2007-03-08 20:56:57 +00:00
|
|
|
&& trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
|
|
|
|
&& trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
|
2017-12-22 14:23:22 +00:00
|
|
|
sla_check_station_hold_access(trunk_ref->trunk, station) )
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
{
|
2007-02-28 19:57:41 +00:00
|
|
|
trunk_ref = NULL;
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
}
|
2007-02-28 22:09:33 +00:00
|
|
|
|
2007-02-28 19:57:41 +00:00
|
|
|
break;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (trunk_ref) {
|
|
|
|
ao2_ref(trunk_ref, 1);
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
return trunk_ref;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_station_ref_destructor(void *obj)
|
|
|
|
{
|
|
|
|
struct sla_station_ref *station_ref = obj;
|
|
|
|
|
|
|
|
if (station_ref->station) {
|
|
|
|
ao2_ref(station_ref->station, -1);
|
|
|
|
station_ref->station = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
|
2007-02-10 00:40:57 +00:00
|
|
|
return NULL;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(station, 1);
|
2007-02-10 00:40:57 +00:00
|
|
|
station_ref->station = station;
|
|
|
|
|
|
|
|
return station_ref;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
|
|
|
|
if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
|
|
|
|
return NULL;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(station, 1);
|
2007-02-22 23:12:26 +00:00
|
|
|
ringing_station->station = station;
|
|
|
|
ringing_station->ring_begin = ast_tvnow();
|
|
|
|
|
|
|
|
return ringing_station;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
|
|
|
|
{
|
|
|
|
if (ringing_station->station) {
|
|
|
|
ao2_ref(ringing_station->station, -1);
|
|
|
|
ringing_station->station = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_free(ringing_station);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sla_failed_station *sla_create_failed_station(struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_failed_station *failed_station;
|
|
|
|
|
|
|
|
if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ao2_ref(station, 1);
|
|
|
|
failed_station->station = station;
|
|
|
|
failed_station->last_try = ast_tvnow();
|
|
|
|
|
|
|
|
return failed_station;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
|
|
|
|
{
|
|
|
|
if (failed_station->station) {
|
|
|
|
ao2_ref(failed_station->station, -1);
|
|
|
|
failed_station->station = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_free(failed_station);
|
|
|
|
}
|
|
|
|
|
2007-08-10 16:24:11 +00:00
|
|
|
static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case SLA_TRUNK_STATE_IDLE:
|
|
|
|
return AST_DEVICE_NOT_INUSE;
|
|
|
|
case SLA_TRUNK_STATE_RINGING:
|
|
|
|
return AST_DEVICE_RINGING;
|
|
|
|
case SLA_TRUNK_STATE_UP:
|
|
|
|
return AST_DEVICE_INUSE;
|
|
|
|
case SLA_TRUNK_STATE_ONHOLD:
|
|
|
|
case SLA_TRUNK_STATE_ONHOLD_BYME:
|
|
|
|
return AST_DEVICE_ONHOLD;
|
|
|
|
}
|
|
|
|
|
|
|
|
return AST_DEVICE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
|
2007-03-08 20:56:57 +00:00
|
|
|
enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
struct sla_station *station;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2013-07-10 01:56:15 +00:00
|
|
|
struct ao2_iterator i;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
i = ao2_iterator_init(sla_stations, 0);
|
|
|
|
while ((station = ao2_iterator_next(&i))) {
|
|
|
|
ao2_lock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
2007-03-08 20:56:57 +00:00
|
|
|
if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
|
2013-07-10 01:56:15 +00:00
|
|
|
|| trunk_ref == exclude) {
|
2007-02-10 00:40:57 +00:00
|
|
|
continue;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk_ref->state = state;
|
2013-01-02 18:11:59 +00:00
|
|
|
ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
|
|
|
|
"SLA:%s_%s", station->name, trunk->name);
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_unlock(station);
|
|
|
|
ao2_ref(station, -1);
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_iterator_destroy(&i);
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
struct run_station_args {
|
|
|
|
struct sla_station *station;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
ast_mutex_t *cond_lock;
|
|
|
|
ast_cond_t *cond;
|
|
|
|
};
|
|
|
|
|
2008-12-09 20:59:54 +00:00
|
|
|
static void answer_trunk_chan(struct ast_channel *chan)
|
|
|
|
{
|
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.
Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.
This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.
The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.
ASTERISK-29998 #close
Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-09-24 10:15:09 +00:00
|
|
|
ast_raw_answer(chan);
|
2008-12-09 20:59:54 +00:00
|
|
|
ast_indicate(chan, -1);
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
static void *run_station(void *data)
|
2006-07-01 23:54:43 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
|
|
|
|
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
|
2008-08-06 17:33:48 +00:00
|
|
|
struct ast_str *conf_name = ast_str_create(16);
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 conf_flags = { 0 };
|
2007-02-10 00:40:57 +00:00
|
|
|
struct ast_conference *conf;
|
|
|
|
|
|
|
|
{
|
|
|
|
struct run_station_args *args = data;
|
|
|
|
station = args->station;
|
|
|
|
trunk_ref = args->trunk_ref;
|
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
/* args is no longer valid here. */
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_set_flag64(&conf_flags,
|
2007-02-10 00:40:57 +00:00
|
|
|
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
|
2008-12-09 20:59:54 +00:00
|
|
|
answer_trunk_chan(trunk_ref->chan);
|
2010-07-09 20:01:01 +00:00
|
|
|
conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
|
2007-02-21 01:05:00 +00:00
|
|
|
if (conf) {
|
2009-12-10 17:31:23 +00:00
|
|
|
conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(conf);
|
|
|
|
conf = NULL;
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk_ref->chan = NULL;
|
2007-03-08 20:56:57 +00:00
|
|
|
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_str_append(&conf_name, 0, ",K");
|
2008-12-13 08:36:35 +00:00
|
|
|
admin_exec(NULL, ast_str_buffer(conf_name));
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk_ref->trunk->hold_stations = 0;
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ast_dial_join(station->dial);
|
|
|
|
ast_dial_destroy(station->dial);
|
|
|
|
station->dial = NULL;
|
2008-08-06 17:33:48 +00:00
|
|
|
ast_free(conf_name);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk);
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2007-02-22 23:12:26 +00:00
|
|
|
char buf[80];
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
2007-07-31 01:10:47 +00:00
|
|
|
snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
|
2007-02-22 23:12:26 +00:00
|
|
|
admin_exec(NULL, buf);
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
|
|
|
|
ao2_ref(station_ref, -1);
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_trunk_destroy(ringing_trunk);
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
|
|
|
|
enum sla_station_hangup hangup)
|
|
|
|
{
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
|
|
|
ast_dial_join(ringing_station->station->dial);
|
|
|
|
ast_dial_destroy(ringing_station->station->dial);
|
|
|
|
ringing_station->station->dial = NULL;
|
|
|
|
|
|
|
|
if (hangup == SLA_STATION_HANGUP_NORMAL)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* If the station is being hung up because of a timeout, then add it to the
|
|
|
|
* list of timed out stations on each of the ringing trunks. This is so
|
|
|
|
* that when doing further processing to figure out which stations should be
|
|
|
|
* ringing, which trunk to answer, determining timeouts, etc., we know which
|
|
|
|
* ringing trunks we should ignore. */
|
|
|
|
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
|
|
|
|
if (ringing_trunk->trunk == trunk_ref->trunk)
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!trunk_ref)
|
|
|
|
continue;
|
|
|
|
if (!(station_ref = sla_create_station_ref(ringing_station->station)))
|
|
|
|
continue;
|
|
|
|
AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_station_destroy(ringing_station);
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_dial_state_callback(struct ast_dial *dial)
|
|
|
|
{
|
|
|
|
sla_queue_event(SLA_EVENT_DIAL_STATE);
|
|
|
|
}
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
/*! \brief Check to see if dialing this station already timed out for this ringing trunk
|
|
|
|
* \note Assumes sla.lock is locked
|
|
|
|
*/
|
|
|
|
static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
|
|
|
|
const struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_station_ref *timed_out_station;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
|
|
|
|
if (station == timed_out_station->station)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Choose the highest priority ringing trunk for a station
|
|
|
|
* \param station the station
|
2010-06-08 14:38:18 +00:00
|
|
|
* \param rm remove the ringing trunk once selected
|
2007-02-28 18:21:47 +00:00
|
|
|
* \param trunk_ref a place to store the pointer to this stations reference to
|
|
|
|
* the selected trunk
|
|
|
|
* \return a pointer to the selected ringing trunk, or NULL if none found
|
|
|
|
* \note Assumes that sla.lock is locked
|
|
|
|
*/
|
2017-12-22 14:23:22 +00:00
|
|
|
static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
|
2008-08-10 14:45:25 +00:00
|
|
|
struct sla_trunk_ref **trunk_ref, int rm)
|
2007-02-28 18:21:47 +00:00
|
|
|
{
|
|
|
|
struct sla_trunk_ref *s_trunk_ref;
|
|
|
|
struct sla_ringing_trunk *ringing_trunk = NULL;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
/* Make sure this is the trunk we're looking for */
|
|
|
|
if (s_trunk_ref->trunk != ringing_trunk->trunk)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* This trunk on the station is ringing. But, make sure this station
|
|
|
|
* didn't already time out while this trunk was ringing. */
|
|
|
|
if (sla_check_timed_out_station(ringing_trunk, station))
|
|
|
|
continue;
|
|
|
|
|
2008-08-10 14:45:25 +00:00
|
|
|
if (rm)
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (trunk_ref) {
|
|
|
|
ao2_ref(s_trunk_ref, 1);
|
2007-02-28 18:21:47 +00:00
|
|
|
*trunk_ref = s_trunk_ref;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
if (ringing_trunk)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ringing_trunk;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static void sla_handle_dial_state_event(void)
|
|
|
|
{
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
|
2007-02-24 01:56:41 +00:00
|
|
|
struct sla_ringing_trunk *ringing_trunk = NULL;
|
2007-02-22 23:12:26 +00:00
|
|
|
struct run_station_args args;
|
|
|
|
enum ast_dial_result dial_res;
|
|
|
|
pthread_t dont_care;
|
|
|
|
ast_mutex_t cond_lock;
|
|
|
|
ast_cond_t cond;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
|
|
|
|
case AST_DIAL_RESULT_HANGUP:
|
|
|
|
case AST_DIAL_RESULT_INVALID:
|
|
|
|
case AST_DIAL_RESULT_FAILED:
|
|
|
|
case AST_DIAL_RESULT_TIMEOUT:
|
|
|
|
case AST_DIAL_RESULT_UNANSWERED:
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
|
|
|
|
break;
|
|
|
|
case AST_DIAL_RESULT_ANSWERED:
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-22 23:12:26 +00:00
|
|
|
/* Find the appropriate trunk to answer. */
|
2007-02-28 18:21:47 +00:00
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!ringing_trunk) {
|
2013-03-26 01:38:56 +00:00
|
|
|
/* This case happens in a bit of a race condition. If two stations answer
|
|
|
|
* the outbound call at the same time, the first one will get connected to
|
|
|
|
* the trunk. When the second one gets here, it will not see any trunks
|
|
|
|
* ringing so we have no idea what to conect it to. So, we just hang up
|
|
|
|
* on it. */
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
|
2013-03-26 01:38:56 +00:00
|
|
|
ast_dial_join(ringing_station->station->dial);
|
|
|
|
ast_dial_destroy(ringing_station->station->dial);
|
|
|
|
ringing_station->station->dial = NULL;
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_station_destroy(ringing_station);
|
2007-02-22 23:12:26 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
/* Track the channel that answered this trunk */
|
2007-02-22 23:12:26 +00:00
|
|
|
s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
|
2007-02-28 18:21:47 +00:00
|
|
|
/* Actually answer the trunk */
|
2008-12-09 20:59:54 +00:00
|
|
|
answer_trunk_chan(ringing_trunk->trunk->chan);
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
2007-02-28 18:21:47 +00:00
|
|
|
/* Now, start a thread that will connect this station to the trunk. The rest of
|
|
|
|
* the code here sets up the thread and ensures that it is able to save the arguments
|
|
|
|
* before they are no longer valid since they are allocated on the stack. */
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(s_trunk_ref, 1);
|
2007-02-22 23:12:26 +00:00
|
|
|
args.trunk_ref = s_trunk_ref;
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(ringing_station->station, 1);
|
2007-02-22 23:12:26 +00:00
|
|
|
args.station = ringing_station->station;
|
|
|
|
args.cond = &cond;
|
|
|
|
args.cond_lock = &cond_lock;
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_trunk_destroy(ringing_trunk);
|
|
|
|
sla_ringing_station_destroy(ringing_station);
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_mutex_init(&cond_lock);
|
|
|
|
ast_cond_init(&cond, NULL);
|
|
|
|
ast_mutex_lock(&cond_lock);
|
2007-05-24 18:30:19 +00:00
|
|
|
ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_cond_wait(&cond, &cond_lock);
|
|
|
|
ast_mutex_unlock(&cond_lock);
|
|
|
|
ast_mutex_destroy(&cond_lock);
|
|
|
|
ast_cond_destroy(&cond);
|
|
|
|
break;
|
|
|
|
case AST_DIAL_RESULT_TRYING:
|
|
|
|
case AST_DIAL_RESULT_RINGING:
|
|
|
|
case AST_DIAL_RESULT_PROGRESS:
|
|
|
|
case AST_DIAL_RESULT_PROCEEDING:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dial_res == AST_DIAL_RESULT_ANSWERED) {
|
|
|
|
/* Queue up reprocessing ringing trunks, and then ringing stations again */
|
|
|
|
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
|
|
|
|
sla_queue_event(SLA_EVENT_DIAL_STATE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
2017-12-22 14:23:22 +00:00
|
|
|
/*! \brief Check to see if this station is already ringing
|
|
|
|
* \note Assumes sla.lock is locked
|
2007-02-28 18:21:47 +00:00
|
|
|
*/
|
|
|
|
static int sla_check_ringing_station(const struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
|
|
|
|
if (station == ringing_station->station)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Check to see if this station has failed to be dialed in the past minute
|
|
|
|
* \note assumes sla.lock is locked
|
|
|
|
*/
|
|
|
|
static int sla_check_failed_station(const struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_failed_station *failed_station;
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
|
|
|
|
if (station != failed_station->station)
|
|
|
|
continue;
|
|
|
|
if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_failed_station_destroy(failed_station);
|
2007-02-28 18:21:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
res = 1;
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Ring a station
|
|
|
|
* \note Assumes sla.lock is locked
|
|
|
|
*/
|
|
|
|
static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
|
|
|
|
{
|
|
|
|
char *tech, *tech_data;
|
|
|
|
struct ast_dial *dial;
|
|
|
|
struct sla_ringing_station *ringing_station;
|
2007-03-26 18:29:10 +00:00
|
|
|
enum ast_dial_result res;
|
2010-07-14 15:48:36 +00:00
|
|
|
int caller_is_saved;
|
|
|
|
struct ast_party_caller caller;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
if (!(dial = ast_dial_create()))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ast_dial_set_state_callback(dial, sla_dial_state_callback);
|
|
|
|
tech_data = ast_strdupa(station->device);
|
|
|
|
tech = strsep(&tech_data, "/");
|
|
|
|
|
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it. Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation. This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first. In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-07 15:47:55 +00:00
|
|
|
if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
|
2007-02-28 18:21:47 +00:00
|
|
|
ast_dial_destroy(dial);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-07-14 15:48:36 +00:00
|
|
|
/* Do we need to save off the caller ID data? */
|
|
|
|
caller_is_saved = 0;
|
|
|
|
if (!sla.attempt_callerid) {
|
|
|
|
caller_is_saved = 1;
|
2012-02-29 16:52:47 +00:00
|
|
|
caller = *ast_channel_caller(ringing_trunk->trunk->chan);
|
|
|
|
ast_party_caller_init(ast_channel_caller(ringing_trunk->trunk->chan));
|
2007-03-26 18:29:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2010-07-14 15:48:36 +00:00
|
|
|
/* Restore saved caller ID */
|
|
|
|
if (caller_is_saved) {
|
2012-02-29 16:52:47 +00:00
|
|
|
ast_party_caller_free(ast_channel_caller(ringing_trunk->trunk->chan));
|
|
|
|
ast_channel_caller_set(ringing_trunk->trunk->chan, &caller);
|
2010-07-14 15:48:36 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-03-26 18:29:10 +00:00
|
|
|
if (res != AST_DIAL_RESULT_TRYING) {
|
2007-02-28 18:21:47 +00:00
|
|
|
struct sla_failed_station *failed_station;
|
|
|
|
ast_dial_destroy(dial);
|
2013-07-10 01:56:15 +00:00
|
|
|
if ((failed_station = sla_create_failed_station(station))) {
|
|
|
|
AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!(ringing_station = sla_create_ringing_station(station))) {
|
|
|
|
ast_dial_join(dial);
|
|
|
|
ast_dial_destroy(dial);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
station->dial = dial;
|
|
|
|
|
|
|
|
AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Check to see if a station is in use
|
|
|
|
*/
|
|
|
|
static int sla_check_inuse_station(const struct sla_station *station)
|
2007-02-22 23:12:26 +00:00
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
if (trunk_ref->chan)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
|
|
|
|
const struct sla_trunk *trunk)
|
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref = NULL;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
if (trunk_ref->trunk == trunk)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(trunk_ref, 1);
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
return trunk_ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Calculate the ring delay for a given ringing trunk on a station
|
|
|
|
* \param station the station
|
2007-05-31 10:26:55 +00:00
|
|
|
* \param ringing_trunk the trunk. If NULL, the highest priority ringing trunk will be used
|
2007-02-28 18:21:47 +00:00
|
|
|
* \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
|
|
|
|
*/
|
2017-12-22 14:23:22 +00:00
|
|
|
static int sla_check_station_delay(struct sla_station *station,
|
2007-02-28 18:21:47 +00:00
|
|
|
struct sla_ringing_trunk *ringing_trunk)
|
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
|
2007-02-28 18:21:47 +00:00
|
|
|
unsigned int delay = UINT_MAX;
|
|
|
|
int time_left, time_elapsed;
|
|
|
|
|
|
|
|
if (!ringing_trunk)
|
|
|
|
ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
|
|
|
|
else
|
|
|
|
trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
|
|
|
|
|
|
|
|
if (!ringing_trunk || !trunk_ref)
|
|
|
|
return delay;
|
|
|
|
|
|
|
|
/* If this station has a ring delay specific to the highest priority
|
|
|
|
* ringing trunk, use that. Otherwise, use the ring delay specified
|
|
|
|
* globally for the station. */
|
|
|
|
delay = trunk_ref->ring_delay;
|
|
|
|
if (!delay)
|
|
|
|
delay = station->ring_delay;
|
|
|
|
if (!delay)
|
|
|
|
return INT_MAX;
|
|
|
|
|
|
|
|
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
|
|
|
|
time_left = (delay * 1000) - time_elapsed;
|
|
|
|
|
|
|
|
return time_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Ring stations based on current set of ringing trunks
|
|
|
|
* \note Assumes that sla.lock is locked
|
|
|
|
*/
|
|
|
|
static void sla_ring_stations(void)
|
|
|
|
{
|
2007-02-22 23:12:26 +00:00
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
|
|
|
|
/* Make sure that every station that uses at least one of the ringing
|
|
|
|
* trunks, is ringing. */
|
|
|
|
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
|
2007-02-28 18:21:47 +00:00
|
|
|
int time_left;
|
|
|
|
|
|
|
|
/* Is this station already ringing? */
|
|
|
|
if (sla_check_ringing_station(station_ref->station))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is this station already in a call? */
|
|
|
|
if (sla_check_inuse_station(station_ref->station))
|
|
|
|
continue;
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* Did we fail to dial this station earlier? If so, has it been
|
|
|
|
* a minute since we tried? */
|
2007-02-28 18:21:47 +00:00
|
|
|
if (sla_check_failed_station(station_ref->station))
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* If this station already timed out while this trunk was ringing,
|
|
|
|
* do not dial it again for this ringing trunk. */
|
2007-02-28 18:21:47 +00:00
|
|
|
if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
/* Check for a ring delay in progress */
|
|
|
|
time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
|
|
|
|
if (time_left != INT_MAX && time_left > 0)
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
/* It is time to make this station begin to ring. Do it! */
|
|
|
|
sla_ring_station(ringing_trunk, station_ref->station);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
/* Now, all of the stations that should be ringing, are ringing. */
|
2007-02-28 18:21:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_hangup_stations(void)
|
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
|
|
|
|
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
if (trunk_ref->trunk == ringing_trunk->trunk)
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
if (ringing_trunk)
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!trunk_ref) {
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_dial_join(ringing_station->station->dial);
|
|
|
|
ast_dial_destroy(ringing_station->station->dial);
|
|
|
|
ringing_station->station->dial = NULL;
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_station_destroy(ringing_station);
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END
|
|
|
|
}
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
static void sla_handle_ringing_trunk_event(void)
|
|
|
|
{
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
sla_ring_stations();
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
|
|
|
|
/* Find stations that shouldn't be ringing anymore. */
|
|
|
|
sla_hangup_stations();
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static void sla_handle_hold_event(struct sla_event *event)
|
|
|
|
{
|
|
|
|
ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
|
2007-03-08 20:56:57 +00:00
|
|
|
event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
|
2013-01-02 18:11:59 +00:00
|
|
|
ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
|
|
|
|
event->station->name, event->trunk_ref->trunk->name);
|
2017-12-22 14:23:22 +00:00
|
|
|
sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
|
2007-03-08 20:56:57 +00:00
|
|
|
INACTIVE_TRUNK_REFS, event->trunk_ref);
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
|
|
|
|
if (event->trunk_ref->trunk->active_stations == 1) {
|
|
|
|
/* The station putting it on hold is the only one on the call, so start
|
|
|
|
* Music on hold to the trunk. */
|
|
|
|
event->trunk_ref->trunk->on_hold = 1;
|
|
|
|
ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
|
|
|
|
}
|
|
|
|
|
2009-10-22 17:11:23 +00:00
|
|
|
ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
|
2007-03-08 23:21:44 +00:00
|
|
|
event->trunk_ref->chan = NULL;
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
/*! \brief Process trunk ring timeouts
|
|
|
|
* \note Called with sla.lock locked
|
|
|
|
* \return non-zero if a change to the ringing trunks was made
|
|
|
|
*/
|
|
|
|
static int sla_calc_trunk_timeouts(unsigned int *timeout)
|
2007-02-22 23:12:26 +00:00
|
|
|
{
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
2007-02-28 18:21:47 +00:00
|
|
|
int res = 0;
|
2007-02-22 23:12:26 +00:00
|
|
|
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
int time_left, time_elapsed;
|
|
|
|
if (!ringing_trunk->trunk->ring_timeout)
|
|
|
|
continue;
|
|
|
|
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
|
|
|
|
time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
|
|
|
|
if (time_left <= 0) {
|
2007-06-15 15:36:45 +00:00
|
|
|
pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_stop_ringing_trunk(ringing_trunk);
|
2007-02-28 18:21:47 +00:00
|
|
|
res = 1;
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
if (time_left < *timeout)
|
|
|
|
*timeout = time_left;
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
2007-02-22 23:12:26 +00:00
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Process station ring timeouts
|
|
|
|
* \note Called with sla.lock locked
|
|
|
|
* \return non-zero if a change to the ringing stations was made
|
|
|
|
*/
|
|
|
|
static int sla_calc_station_timeouts(unsigned int *timeout)
|
|
|
|
{
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
int res = 0;
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
|
|
|
|
unsigned int ring_timeout = 0;
|
2007-02-28 18:21:47 +00:00
|
|
|
int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
|
2007-02-22 23:12:26 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* If there are any ring timeouts specified for a specific trunk
|
|
|
|
* on the station, then use the highest per-trunk ring timeout.
|
|
|
|
* Otherwise, use the ring timeout set for the entire station. */
|
|
|
|
AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
int trunk_time_elapsed, trunk_time_left;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
if (ringing_trunk->trunk == trunk_ref->trunk)
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!ringing_trunk)
|
|
|
|
continue;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* If there is a trunk that is ringing without a timeout, then the
|
|
|
|
* only timeout that could matter is a global station ring timeout. */
|
2007-02-28 18:21:47 +00:00
|
|
|
if (!trunk_ref->ring_timeout)
|
2007-02-22 23:12:26 +00:00
|
|
|
break;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* This trunk on this station is ringing and has a timeout.
|
|
|
|
* However, make sure this trunk isn't still ringing from a
|
|
|
|
* previous timeout. If so, don't consider it. */
|
|
|
|
AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
|
|
|
|
if (station_ref->station == ringing_station->station)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (station_ref)
|
|
|
|
continue;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
|
|
|
|
trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
|
|
|
|
if (trunk_time_left > final_trunk_time_left)
|
|
|
|
final_trunk_time_left = trunk_time_left;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
/* No timeout was found for ringing trunks, and no timeout for the entire station */
|
|
|
|
if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
/* Compute how much time is left for a global station timeout */
|
|
|
|
if (ringing_station->station->ring_timeout) {
|
|
|
|
ring_timeout = ringing_station->station->ring_timeout;
|
|
|
|
time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
|
|
|
|
time_left = (ring_timeout * 1000) - time_elapsed;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* If the time left based on the per-trunk timeouts is smaller than the
|
|
|
|
* global station ring timeout, use that. */
|
|
|
|
if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
|
|
|
|
time_left = final_trunk_time_left;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
/* If there is no time left, the station needs to stop ringing */
|
2007-02-22 23:12:26 +00:00
|
|
|
if (time_left <= 0) {
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
|
2007-02-28 18:21:47 +00:00
|
|
|
res = 1;
|
2007-02-22 23:12:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
/* There is still some time left for this station to ring, so save that
|
|
|
|
* timeout if it is the first event scheduled to occur */
|
|
|
|
if (time_left < *timeout)
|
|
|
|
*timeout = time_left;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Calculate the ring delay for a station
|
|
|
|
* \note Assumes sla.lock is locked
|
|
|
|
*/
|
|
|
|
static int sla_calc_station_delays(unsigned int *timeout)
|
|
|
|
{
|
|
|
|
struct sla_station *station;
|
|
|
|
int res = 0;
|
2013-07-10 01:56:15 +00:00
|
|
|
struct ao2_iterator i;
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
i = ao2_iterator_init(sla_stations, 0);
|
|
|
|
for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
|
2007-02-28 18:21:47 +00:00
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
int time_left;
|
|
|
|
|
|
|
|
/* Ignore stations already ringing */
|
|
|
|
if (sla_check_ringing_station(station))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Ignore stations already on a call */
|
|
|
|
if (sla_check_inuse_station(station))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Ignore stations that don't have one of their trunks ringing */
|
|
|
|
if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If there is no time left, then the station needs to start ringing.
|
2017-12-22 14:23:22 +00:00
|
|
|
* Return non-zero so that an event will be queued up an event to
|
2007-02-28 18:21:47 +00:00
|
|
|
* make that happen. */
|
|
|
|
if (time_left <= 0) {
|
|
|
|
res = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time_left < *timeout)
|
|
|
|
*timeout = time_left;
|
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_iterator_destroy(&i);
|
2007-02-28 18:21:47 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Calculate the time until the next known event
|
|
|
|
* \note Called with sla.lock locked */
|
|
|
|
static int sla_process_timers(struct timespec *ts)
|
|
|
|
{
|
|
|
|
unsigned int timeout = UINT_MAX;
|
2008-08-10 14:45:25 +00:00
|
|
|
struct timeval wait;
|
2007-02-28 18:21:47 +00:00
|
|
|
unsigned int change_made = 0;
|
|
|
|
|
|
|
|
/* Check for ring timeouts on ringing trunks */
|
|
|
|
if (sla_calc_trunk_timeouts(&timeout))
|
|
|
|
change_made = 1;
|
|
|
|
|
|
|
|
/* Check for ring timeouts on ringing stations */
|
|
|
|
if (sla_calc_station_timeouts(&timeout))
|
|
|
|
change_made = 1;
|
|
|
|
|
|
|
|
/* Check for station ring delays */
|
|
|
|
if (sla_calc_station_delays(&timeout))
|
|
|
|
change_made = 1;
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
/* queue reprocessing of ringing trunks */
|
|
|
|
if (change_made)
|
|
|
|
sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
|
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
/* No timeout */
|
2007-02-22 23:12:26 +00:00
|
|
|
if (timeout == UINT_MAX)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ts) {
|
2008-08-10 14:45:25 +00:00
|
|
|
wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
|
|
|
|
ts->tv_sec = wait.tv_sec;
|
|
|
|
ts->tv_nsec = wait.tv_usec * 1000;
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_event_destroy(struct sla_event *event)
|
2007-06-21 18:40:20 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
if (event->trunk_ref) {
|
|
|
|
ao2_ref(event->trunk_ref, -1);
|
|
|
|
event->trunk_ref = NULL;
|
2007-06-21 18:40:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (event->station) {
|
|
|
|
ao2_ref(event->station, -1);
|
|
|
|
event->station = NULL;
|
2007-06-21 18:40:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ast_free(event);
|
2007-06-21 18:40:20 +00:00
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static void *sla_thread(void *data)
|
|
|
|
{
|
|
|
|
struct sla_failed_station *failed_station;
|
|
|
|
struct sla_ringing_station *ringing_station;
|
|
|
|
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
|
|
|
|
while (!sla.stop) {
|
|
|
|
struct sla_event *event;
|
|
|
|
struct timespec ts = { 0, };
|
|
|
|
unsigned int have_timeout = 0;
|
|
|
|
|
|
|
|
if (AST_LIST_EMPTY(&sla.event_q)) {
|
|
|
|
if ((have_timeout = sla_process_timers(&ts)))
|
|
|
|
ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
|
|
|
|
else
|
|
|
|
ast_cond_wait(&sla.cond, &sla.lock);
|
|
|
|
if (sla.stop)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (have_timeout)
|
|
|
|
sla_process_timers(NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
switch (event->type) {
|
|
|
|
case SLA_EVENT_HOLD:
|
|
|
|
sla_handle_hold_event(event);
|
|
|
|
break;
|
|
|
|
case SLA_EVENT_DIAL_STATE:
|
|
|
|
sla_handle_dial_state_event();
|
|
|
|
break;
|
|
|
|
case SLA_EVENT_RINGING_TRUNK:
|
|
|
|
sla_handle_ringing_trunk_event();
|
|
|
|
break;
|
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_event_destroy(event);
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
|
|
|
|
sla_ringing_station_destroy(ringing_station);
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
|
|
|
|
sla_failed_station_destroy(failed_station);
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct dial_trunk_args {
|
2007-03-01 23:44:09 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station *station;
|
|
|
|
ast_mutex_t *cond_lock;
|
|
|
|
ast_cond_t *cond;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *dial_trunk(void *data)
|
|
|
|
{
|
|
|
|
struct dial_trunk_args *args = data;
|
|
|
|
struct ast_dial *dial;
|
|
|
|
char *tech, *tech_data;
|
|
|
|
enum ast_dial_result dial_res;
|
|
|
|
char conf_name[MAX_CONFNUM];
|
|
|
|
struct ast_conference *conf;
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 conf_flags = { 0 };
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
|
|
|
|
RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
|
2010-07-14 15:48:36 +00:00
|
|
|
int caller_is_saved;
|
|
|
|
struct ast_party_caller caller;
|
2013-01-22 15:15:04 +00:00
|
|
|
int last_state = 0;
|
|
|
|
int current_state = 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
if (!(dial = ast_dial_create())) {
|
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-03-01 23:44:09 +00:00
|
|
|
tech_data = ast_strdupa(trunk_ref->trunk->device);
|
2007-02-10 00:40:57 +00:00
|
|
|
tech = strsep(&tech_data, "/");
|
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and
much change was necessary to accomplish it. Channel uniqueids
and linkedids are split into separate string and creation time
components without breaking linkedid propgation. This allowed
the uniqueid to be specified by the user interface - and those
values are now carried through to channel creation, adding the
assignedids value to every function in the chain including the
channel drivers. For local channels, the second channel can be
specified or left to default to a ;2 suffix of first. In ARI,
bridge, playback, and snoop objects can also be created with a
specified uniqueid.
Along the way, the args order to allocating channels was fixed
in chan_mgcp and chan_gtalk, and linkedid is no longer lost as
masquerade occurs.
(closes issue ASTERISK-23120)
Review: https://reviewboard.asterisk.org/r/3191/
........
Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-07 15:47:55 +00:00
|
|
|
if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
ast_dial_destroy(dial);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-14 15:48:36 +00:00
|
|
|
/* Do we need to save of the caller ID data? */
|
|
|
|
caller_is_saved = 0;
|
|
|
|
if (!sla.attempt_callerid) {
|
|
|
|
caller_is_saved = 1;
|
2012-02-29 16:52:47 +00:00
|
|
|
caller = *ast_channel_caller(trunk_ref->chan);
|
|
|
|
ast_party_caller_init(ast_channel_caller(trunk_ref->chan));
|
2007-03-26 18:29:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
|
|
|
|
|
2010-07-14 15:48:36 +00:00
|
|
|
/* Restore saved caller ID */
|
|
|
|
if (caller_is_saved) {
|
2012-02-29 16:52:47 +00:00
|
|
|
ast_party_caller_free(ast_channel_caller(trunk_ref->chan));
|
|
|
|
ast_channel_caller_set(trunk_ref->chan, &caller);
|
2010-07-14 15:48:36 +00:00
|
|
|
}
|
2007-03-26 18:29:10 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (dial_res != AST_DIAL_RESULT_TRYING) {
|
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
ast_dial_destroy(dial);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.
Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.
This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.
The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.
ASTERISK-29998 #close
Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-09-24 10:15:09 +00:00
|
|
|
/* Wait for dial to end, while servicing the channel */
|
|
|
|
while (ast_waitfor(trunk_ref->chan, 100)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
unsigned int done = 0;
|
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.
Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.
This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.
The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.
ASTERISK-29998 #close
Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-09-24 10:15:09 +00:00
|
|
|
struct ast_frame *fr = ast_read(trunk_ref->chan);
|
|
|
|
|
|
|
|
if (!fr) {
|
|
|
|
ast_debug(1, "Channel %s did not return a frame, must have hung up\n", ast_channel_name(trunk_ref->chan));
|
|
|
|
done = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ast_frfree(fr); /* Ignore while dialing */
|
|
|
|
|
2007-02-12 18:01:15 +00:00
|
|
|
switch ((dial_res = ast_dial_state(dial))) {
|
2007-02-10 00:40:57 +00:00
|
|
|
case AST_DIAL_RESULT_ANSWERED:
|
2007-03-01 23:44:09 +00:00
|
|
|
trunk_ref->trunk->chan = ast_dial_answered(dial);
|
2007-02-10 00:40:57 +00:00
|
|
|
case AST_DIAL_RESULT_HANGUP:
|
|
|
|
case AST_DIAL_RESULT_INVALID:
|
|
|
|
case AST_DIAL_RESULT_FAILED:
|
|
|
|
case AST_DIAL_RESULT_TIMEOUT:
|
|
|
|
case AST_DIAL_RESULT_UNANSWERED:
|
|
|
|
done = 1;
|
2013-01-22 15:15:04 +00:00
|
|
|
break;
|
2007-02-10 00:40:57 +00:00
|
|
|
case AST_DIAL_RESULT_TRYING:
|
2013-01-22 15:15:04 +00:00
|
|
|
current_state = AST_CONTROL_PROGRESS;
|
|
|
|
break;
|
2007-02-10 00:40:57 +00:00
|
|
|
case AST_DIAL_RESULT_RINGING:
|
|
|
|
case AST_DIAL_RESULT_PROGRESS:
|
|
|
|
case AST_DIAL_RESULT_PROCEEDING:
|
2013-01-22 15:15:04 +00:00
|
|
|
current_state = AST_CONTROL_RINGING;
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (done)
|
|
|
|
break;
|
2013-01-22 15:15:04 +00:00
|
|
|
|
|
|
|
/* check that SLA station that originated trunk call is still alive */
|
2013-07-10 01:56:15 +00:00
|
|
|
if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
|
|
|
|
ast_debug(3, "Originating station device %s no longer active\n", station->device);
|
2013-01-22 15:15:04 +00:00
|
|
|
trunk_ref->trunk->chan = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If trunk line state changed, send indication back to originating SLA Station channel */
|
|
|
|
if (current_state != last_state) {
|
|
|
|
ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, ast_channel_name(trunk_ref->chan));
|
|
|
|
ast_indicate(trunk_ref->chan, current_state);
|
|
|
|
last_state = current_state;
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2007-03-01 23:44:09 +00:00
|
|
|
if (!trunk_ref->trunk->chan) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
ast_dial_join(dial);
|
|
|
|
ast_dial_destroy(dial);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-03-01 23:44:09 +00:00
|
|
|
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_set_flag64(&conf_flags,
|
|
|
|
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
|
2007-02-10 00:40:57 +00:00
|
|
|
CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
|
2010-07-09 20:01:01 +00:00
|
|
|
conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
ast_mutex_lock(args->cond_lock);
|
|
|
|
ast_cond_signal(args->cond);
|
|
|
|
ast_mutex_unlock(args->cond_lock);
|
|
|
|
|
2007-02-21 01:05:00 +00:00
|
|
|
if (conf) {
|
2009-12-10 17:31:23 +00:00
|
|
|
conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(conf);
|
|
|
|
conf = NULL;
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-04-04 16:27:12 +00:00
|
|
|
/* If the trunk is going away, it is definitely now IDLE. */
|
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
|
|
|
|
2007-03-01 23:44:09 +00:00
|
|
|
trunk_ref->trunk->chan = NULL;
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk_ref->trunk->on_hold = 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
ast_dial_join(dial);
|
|
|
|
ast_dial_destroy(dial);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \brief For a given station, choose the highest priority idle trunk
|
|
|
|
* \pre sla_station is locked
|
2007-02-28 18:21:47 +00:00
|
|
|
*/
|
|
|
|
static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
|
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref = NULL;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
2013-07-10 01:56:15 +00:00
|
|
|
if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
|
|
|
|
ao2_ref(trunk_ref, 1);
|
2007-02-28 18:21:47 +00:00
|
|
|
break;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return trunk_ref;
|
|
|
|
}
|
|
|
|
|
2009-05-21 21:13:09 +00:00
|
|
|
static int sla_station_exec(struct ast_channel *chan, const char *data)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
char *station_name, *trunk_name;
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
|
|
|
|
RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
|
2007-02-10 00:40:57 +00:00
|
|
|
char conf_name[MAX_CONFNUM];
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 conf_flags = { 0 };
|
2007-02-10 00:40:57 +00:00
|
|
|
struct ast_conference *conf;
|
|
|
|
|
|
|
|
if (ast_strlen_zero(data)) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
|
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
trunk_name = ast_strdupa(data);
|
|
|
|
station_name = strsep(&trunk_name, "_");
|
|
|
|
|
|
|
|
if (ast_strlen_zero(station_name)) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
|
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
station = sla_find_station(station_name);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
if (!station) {
|
|
|
|
ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
|
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_lock(station);
|
2007-03-08 20:56:57 +00:00
|
|
|
if (!ast_strlen_zero(trunk_name)) {
|
2007-02-28 18:21:47 +00:00
|
|
|
trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
|
2013-07-10 01:56:15 +00:00
|
|
|
} else {
|
2007-02-28 18:21:47 +00:00
|
|
|
trunk_ref = sla_choose_idle_trunk(station);
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
ao2_unlock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-02-28 19:57:41 +00:00
|
|
|
if (!trunk_ref) {
|
2007-02-28 22:09:33 +00:00
|
|
|
if (ast_strlen_zero(trunk_name))
|
|
|
|
ast_log(LOG_NOTICE, "No trunks available for call.\n");
|
|
|
|
else {
|
|
|
|
ast_log(LOG_NOTICE, "Can't join existing call on trunk "
|
|
|
|
"'%s' due to access controls.\n", trunk_name);
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-08 20:56:57 +00:00
|
|
|
if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
|
|
|
|
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
|
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
|
|
|
else {
|
|
|
|
trunk_ref->state = SLA_TRUNK_STATE_UP;
|
2013-01-02 18:11:59 +00:00
|
|
|
ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
|
|
|
|
"SLA:%s_%s", station->name, trunk_ref->trunk->name);
|
2007-03-08 20:56:57 +00:00
|
|
|
}
|
2007-11-15 17:27:27 +00:00
|
|
|
} else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
if (ringing_trunk->trunk == trunk_ref->trunk) {
|
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
|
|
|
|
if (ringing_trunk) {
|
2008-12-09 20:59:54 +00:00
|
|
|
answer_trunk_chan(ringing_trunk->trunk->chan);
|
2007-11-15 17:27:27 +00:00
|
|
|
sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_trunk_destroy(ringing_trunk);
|
2007-11-15 17:27:27 +00:00
|
|
|
|
|
|
|
/* Queue up reprocessing ringing trunks, and then ringing stations again */
|
|
|
|
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
|
|
|
|
sla_queue_event(SLA_EVENT_DIAL_STATE);
|
|
|
|
}
|
2007-03-08 20:56:57 +00:00
|
|
|
}
|
|
|
|
|
2007-03-01 23:44:09 +00:00
|
|
|
trunk_ref->chan = chan;
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!trunk_ref->trunk->chan) {
|
|
|
|
ast_mutex_t cond_lock;
|
|
|
|
ast_cond_t cond;
|
|
|
|
pthread_t dont_care;
|
|
|
|
struct dial_trunk_args args = {
|
2007-03-01 23:44:09 +00:00
|
|
|
.trunk_ref = trunk_ref,
|
2007-02-10 00:40:57 +00:00
|
|
|
.station = station,
|
|
|
|
.cond_lock = &cond_lock,
|
|
|
|
.cond = &cond,
|
|
|
|
};
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(trunk_ref, 1);
|
|
|
|
ao2_ref(station, 1);
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
/* Create a thread to dial the trunk and dump it into the conference.
|
|
|
|
* However, we want to wait until the trunk has been dialed and the
|
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.
Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.
This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.
The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.
ASTERISK-29998 #close
Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-09-24 10:15:09 +00:00
|
|
|
* conference is created before continuing on here.
|
|
|
|
* Don't autoservice the channel or we'll have multiple threads
|
|
|
|
* handling it. dial_trunk services the channel.
|
|
|
|
*/
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_mutex_init(&cond_lock);
|
|
|
|
ast_cond_init(&cond, NULL);
|
|
|
|
ast_mutex_lock(&cond_lock);
|
2007-05-24 18:30:19 +00:00
|
|
|
ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_cond_wait(&cond, &cond_lock);
|
|
|
|
ast_mutex_unlock(&cond_lock);
|
|
|
|
ast_mutex_destroy(&cond_lock);
|
|
|
|
ast_cond_destroy(&cond);
|
sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.
Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.
This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.
The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.
ASTERISK-29998 #close
Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-09-24 10:15:09 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!trunk_ref->trunk->chan) {
|
2014-07-22 14:22:00 +00:00
|
|
|
ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
2007-03-01 23:44:09 +00:00
|
|
|
trunk_ref->chan = NULL;
|
2007-02-10 00:40:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
|
|
|
|
trunk_ref->trunk->on_hold) {
|
|
|
|
trunk_ref->trunk->on_hold = 0;
|
|
|
|
ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
|
2007-04-06 19:52:12 +00:00
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
|
2011-02-04 16:55:39 +00:00
|
|
|
ast_set_flag64(&conf_flags,
|
2007-02-10 00:40:57 +00:00
|
|
|
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
|
|
|
|
ast_answer(chan);
|
2010-07-09 20:01:01 +00:00
|
|
|
conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
|
2007-02-21 01:05:00 +00:00
|
|
|
if (conf) {
|
2009-12-10 17:31:23 +00:00
|
|
|
conf_run(chan, conf, &conf_flags, NULL);
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(conf);
|
|
|
|
conf = NULL;
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk_ref->chan = NULL;
|
2007-03-08 23:21:44 +00:00
|
|
|
if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
|
2007-07-31 01:10:47 +00:00
|
|
|
strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
|
2007-02-10 00:40:57 +00:00
|
|
|
admin_exec(NULL, conf_name);
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk_ref->trunk->hold_stations = 0;
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_trunk_ref_destructor(void *obj)
|
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref = obj;
|
|
|
|
|
|
|
|
if (trunk_ref->trunk) {
|
|
|
|
ao2_ref(trunk_ref->trunk, -1);
|
|
|
|
trunk_ref->trunk = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
|
|
|
|
{
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
|
2007-02-10 00:40:57 +00:00
|
|
|
return NULL;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_ref(trunk, 1);
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk_ref->trunk = trunk;
|
|
|
|
|
|
|
|
return trunk_ref;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
|
|
|
|
{
|
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
|
2007-02-22 23:12:26 +00:00
|
|
|
return NULL;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ao2_ref(trunk, 1);
|
2007-02-22 23:12:26 +00:00
|
|
|
ringing_trunk->trunk = trunk;
|
|
|
|
ringing_trunk->ring_begin = ast_tvnow();
|
|
|
|
|
2007-03-08 20:56:57 +00:00
|
|
|
sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
|
2007-02-22 23:12:26 +00:00
|
|
|
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
|
|
|
|
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
|
|
|
|
|
|
|
|
return ringing_trunk;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
|
|
|
|
{
|
|
|
|
if (ringing_trunk->trunk) {
|
|
|
|
ao2_ref(ringing_trunk->trunk, -1);
|
|
|
|
ringing_trunk->trunk = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_free(ringing_trunk);
|
|
|
|
}
|
|
|
|
|
2007-11-21 00:21:38 +00:00
|
|
|
enum {
|
|
|
|
SLA_TRUNK_OPT_MOH = (1 << 0),
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
|
|
|
|
SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
|
|
|
|
AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
|
|
|
|
END_OPTIONS );
|
|
|
|
|
2009-05-21 21:13:09 +00:00
|
|
|
static int sla_trunk_exec(struct ast_channel *chan, const char *data)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
char conf_name[MAX_CONFNUM];
|
|
|
|
struct ast_conference *conf;
|
2009-12-10 17:31:23 +00:00
|
|
|
struct ast_flags64 conf_flags = { 0 };
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
|
2007-02-22 23:12:26 +00:00
|
|
|
struct sla_ringing_trunk *ringing_trunk;
|
2007-11-21 00:21:38 +00:00
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(trunk_name);
|
|
|
|
AST_APP_ARG(options);
|
|
|
|
);
|
|
|
|
char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
|
|
|
|
struct ast_flags opt_flags = { 0 };
|
|
|
|
char *parse;
|
|
|
|
|
|
|
|
if (ast_strlen_zero(data)) {
|
|
|
|
ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse = ast_strdupa(data);
|
|
|
|
AST_STANDARD_APP_ARGS(args, parse);
|
|
|
|
if (args.argc == 2) {
|
|
|
|
if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
|
|
|
|
ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-11-21 00:21:38 +00:00
|
|
|
trunk = sla_find_trunk(args.trunk_name);
|
2007-06-21 18:40:20 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!trunk) {
|
2007-11-21 00:21:38 +00:00
|
|
|
ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
2007-06-21 18:40:20 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (trunk->chan) {
|
|
|
|
ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
|
2007-11-21 00:21:38 +00:00
|
|
|
args.trunk_name);
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
2007-06-21 18:40:20 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk->chan = chan;
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-21 00:21:38 +00:00
|
|
|
snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
|
2010-07-09 20:01:01 +00:00
|
|
|
conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!conf) {
|
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_set_flag64(&conf_flags,
|
2008-12-09 20:59:54 +00:00
|
|
|
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
|
2007-11-21 00:21:38 +00:00
|
|
|
|
|
|
|
if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
|
|
|
|
ast_indicate(chan, -1);
|
2009-12-10 17:31:23 +00:00
|
|
|
ast_set_flag64(&conf_flags, CONFFLAG_MOH);
|
2007-11-21 00:21:38 +00:00
|
|
|
} else
|
|
|
|
ast_indicate(chan, AST_CONTROL_RINGING);
|
|
|
|
|
2009-12-10 17:31:23 +00:00
|
|
|
conf_run(chan, conf, &conf_flags, opts);
|
2007-02-21 01:05:00 +00:00
|
|
|
dispose_conf(conf);
|
|
|
|
conf = NULL;
|
2007-02-10 00:40:57 +00:00
|
|
|
trunk->chan = NULL;
|
Merged revisions 60521 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r60521 | russell | 2007-04-06 13:58:46 -0500 (Fri, 06 Apr 2007) | 16 lines
Fix a few problems with SLA. (issue #9459, reported by francesco_r, fixed by me)
* The original behavior was that if one station put a call on hold, another one
picked it up, and then hung up, the code would still consider the call on
hold by the first station, so the trunk would not be hung up. However, to
better comply with what most people seem to expect it to behave, it will now
hang up the trunk.
* Fix a problem with "barge=no". This was only intended to prevent people from
joining calls that are in progress. However, it also prevented other people
from picking up a call that was on hold. This has been fixed.
* When there are no active stations on a trunk and it is on hold, the code now
indicates the HOLD and UNHOLD conditions to the trunk channel. This allows
music on hold to be played to the trunk when it is on hold.
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@60522 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-04-06 18:59:42 +00:00
|
|
|
trunk->on_hold = 0;
|
2008-03-19 22:58:33 +00:00
|
|
|
|
|
|
|
sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
|
|
|
|
|
2007-06-15 15:36:45 +00:00
|
|
|
if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
|
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
/* Remove the entry from the list of ringing trunks if it is still there. */
|
|
|
|
ast_mutex_lock(&sla.lock);
|
2007-02-22 23:12:26 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
|
|
|
|
if (ringing_trunk->trunk == trunk) {
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-08 05:28:47 +00:00
|
|
|
AST_LIST_TRAVERSE_SAFE_END;
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_mutex_unlock(&sla.lock);
|
2007-02-22 23:12:26 +00:00
|
|
|
if (ringing_trunk) {
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_ringing_trunk_destroy(ringing_trunk);
|
2007-02-10 00:40:57 +00:00
|
|
|
pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
|
2007-03-13 23:20:41 +00:00
|
|
|
/* Queue reprocessing of ringing trunks to make stations stop ringing
|
|
|
|
* that shouldn't be ringing after this trunk stopped. */
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_queue_event(SLA_EVENT_RINGING_TRUNK);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-13 22:02:20 +00:00
|
|
|
static enum ast_device_state sla_state(const char *data)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
char *buf, *station_name, *trunk_name;
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2007-02-13 22:02:20 +00:00
|
|
|
enum ast_device_state res = AST_DEVICE_INVALID;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
trunk_name = buf = ast_strdupa(data);
|
|
|
|
station_name = strsep(&trunk_name, "_");
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
station = sla_find_station(station_name);
|
|
|
|
if (station) {
|
|
|
|
ao2_lock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
|
|
|
|
res = sla_state_to_devstate(trunk_ref->state);
|
2007-02-10 00:40:57 +00:00
|
|
|
break;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_unlock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (res == AST_DEVICE_INVALID) {
|
|
|
|
ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
|
|
|
|
trunk_name, station_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static int sla_trunk_release_refs(void *obj, void *arg, int flags)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct sla_trunk *trunk = obj;
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
|
|
|
|
ao2_ref(station_ref, -1);
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
return 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static int sla_station_release_refs(void *obj, void *arg, int flags)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
struct sla_station *station = obj;
|
2007-02-10 00:40:57 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
|
|
|
|
ao2_ref(trunk_ref, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_station_destructor(void *obj)
|
|
|
|
{
|
|
|
|
struct sla_station *station = obj;
|
|
|
|
|
|
|
|
ast_debug(1, "sla_station destructor for '%s'\n", station->name);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!ast_strlen_zero(station->autocontext)) {
|
2013-07-10 01:56:15 +00:00
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
char exten[AST_MAX_EXTENSION];
|
|
|
|
char hint[AST_MAX_APP];
|
|
|
|
snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
|
|
|
|
snprintf(hint, sizeof(hint), "SLA:%s", exten);
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_context_remove_extension(station->autocontext, exten,
|
2007-02-10 00:40:57 +00:00
|
|
|
1, sla_registrar);
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_context_remove_extension(station->autocontext, hint,
|
2007-02-10 00:40:57 +00:00
|
|
|
PRIORITY_HINT, sla_registrar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
sla_station_release_refs(station, NULL, 0);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2007-11-04 19:44:31 +00:00
|
|
|
ast_string_field_free_memory(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static int sla_trunk_cmp(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_trunk *trunk = obj, *trunk2 = arg;
|
|
|
|
|
|
|
|
return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static int sla_station_cmp(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_station *station = obj, *station2 = arg;
|
|
|
|
|
|
|
|
return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sla_destroy(void)
|
|
|
|
{
|
2007-02-10 00:40:57 +00:00
|
|
|
if (sla.thread != AST_PTHREADT_NULL) {
|
|
|
|
ast_mutex_lock(&sla.lock);
|
|
|
|
sla.stop = 1;
|
|
|
|
ast_cond_signal(&sla.cond);
|
|
|
|
ast_mutex_unlock(&sla.lock);
|
|
|
|
pthread_join(sla.thread, NULL);
|
|
|
|
}
|
|
|
|
|
2007-12-06 14:40:44 +00:00
|
|
|
/* Drop any created contexts from the dialplan */
|
|
|
|
ast_context_destroy(NULL, sla_registrar);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_mutex_destroy(&sla.lock);
|
|
|
|
ast_cond_destroy(&sla.cond);
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
|
|
|
|
ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
|
|
|
|
|
|
|
|
ao2_ref(sla_trunks, -1);
|
|
|
|
sla_trunks = NULL;
|
|
|
|
|
|
|
|
ao2_ref(sla_stations, -1);
|
|
|
|
sla_stations = NULL;
|
2007-02-10 00:40:57 +00:00
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static int sla_check_device(const char *device)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
|
|
|
char *tech, *tech_data;
|
|
|
|
|
|
|
|
tech_data = ast_strdupa(device);
|
|
|
|
tech = strsep(&tech_data, "/");
|
|
|
|
|
|
|
|
if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static void sla_trunk_destructor(void *obj)
|
|
|
|
{
|
|
|
|
struct sla_trunk *trunk = obj;
|
|
|
|
|
|
|
|
ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(trunk->autocontext)) {
|
|
|
|
ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
|
|
|
|
}
|
|
|
|
|
|
|
|
sla_trunk_release_refs(trunk, NULL, 0);
|
|
|
|
|
|
|
|
ast_string_field_free_memory(trunk);
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
static int sla_build_trunk(struct ast_config *cfg, const char *cat)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
|
2007-02-10 00:40:57 +00:00
|
|
|
struct ast_variable *var;
|
|
|
|
const char *dev;
|
2013-07-10 01:56:15 +00:00
|
|
|
int existing_trunk = 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
|
|
|
|
ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
if (sla_check_device(dev)) {
|
2013-07-10 01:56:15 +00:00
|
|
|
ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n",
|
2007-02-10 00:40:57 +00:00
|
|
|
cat, dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if ((trunk = sla_find_trunk(cat))) {
|
|
|
|
trunk->mark = 0;
|
|
|
|
existing_trunk = 1;
|
|
|
|
} else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
|
|
|
|
if (ast_string_field_init(trunk, 32)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ast_string_field_set(trunk, name, cat);
|
|
|
|
} else {
|
2007-02-10 00:40:57 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_lock(trunk);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_string_field_set(trunk, device, dev);
|
|
|
|
|
|
|
|
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
|
|
|
|
if (!strcasecmp(var->name, "autocontext"))
|
|
|
|
ast_string_field_set(trunk, autocontext, var->value);
|
2007-02-22 23:12:26 +00:00
|
|
|
else if (!strcasecmp(var->name, "ringtimeout")) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
|
|
|
|
var->value, trunk->name);
|
|
|
|
trunk->ring_timeout = 0;
|
|
|
|
}
|
2007-02-28 19:57:41 +00:00
|
|
|
} else if (!strcasecmp(var->name, "barge"))
|
|
|
|
trunk->barge_disabled = ast_false(var->value);
|
2007-02-28 22:09:33 +00:00
|
|
|
else if (!strcasecmp(var->name, "hold")) {
|
|
|
|
if (!strcasecmp(var->value, "private"))
|
|
|
|
trunk->hold_access = SLA_HOLD_PRIVATE;
|
|
|
|
else if (!strcasecmp(var->value, "open"))
|
|
|
|
trunk->hold_access = SLA_HOLD_OPEN;
|
|
|
|
else {
|
|
|
|
ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
|
|
|
|
var->value, trunk->name);
|
|
|
|
}
|
|
|
|
} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
|
|
|
|
var->name, var->lineno, SLA_CONFIG_FILE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_unlock(trunk);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!ast_strlen_zero(trunk->autocontext)) {
|
2015-06-08 15:09:57 +00:00
|
|
|
if (!ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Failed to automatically find or create "
|
|
|
|
"context '%s' for SLA!\n", trunk->autocontext);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-06-08 15:09:57 +00:00
|
|
|
|
|
|
|
if (ast_add_extension(trunk->autocontext, 0 /* don't replace */, "s", 1,
|
2007-09-17 18:57:56 +00:00
|
|
|
NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Failed to automatically create extension "
|
|
|
|
"for trunk '%s'!\n", trunk->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!existing_trunk) {
|
|
|
|
ao2_link(sla_trunks, trunk);
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \pre station is not locked
|
|
|
|
*/
|
2007-02-22 23:12:26 +00:00
|
|
|
static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
|
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
|
|
|
|
struct sla_trunk_ref *trunk_ref = NULL;
|
2007-02-22 23:12:26 +00:00
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
char *trunk_name, *options, *cur;
|
2013-07-10 01:56:15 +00:00
|
|
|
int existing_trunk_ref = 0;
|
|
|
|
int existing_station_ref = 0;
|
2007-02-22 23:12:26 +00:00
|
|
|
|
|
|
|
options = ast_strdupa(var->value);
|
|
|
|
trunk_name = strsep(&options, ",");
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
trunk = sla_find_trunk(trunk_name);
|
2007-02-22 23:12:26 +00:00
|
|
|
if (!trunk) {
|
|
|
|
ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
|
|
|
|
return;
|
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
if (trunk_ref->trunk == trunk) {
|
|
|
|
trunk_ref->mark = 0;
|
|
|
|
existing_trunk_ref = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
|
2007-02-22 23:12:26 +00:00
|
|
|
return;
|
2013-07-10 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
trunk_ref->state = SLA_TRUNK_STATE_IDLE;
|
|
|
|
|
|
|
|
while ((cur = strsep(&options, ","))) {
|
|
|
|
char *name, *value = cur;
|
|
|
|
name = strsep(&value, "=");
|
|
|
|
if (!strcasecmp(name, "ringtimeout")) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
|
|
|
|
"trunk '%s' on station '%s'\n", value, trunk->name, station->name);
|
|
|
|
trunk_ref->ring_timeout = 0;
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
} else if (!strcasecmp(name, "ringdelay")) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
|
2007-02-28 18:21:47 +00:00
|
|
|
ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
|
|
|
|
"trunk '%s' on station '%s'\n", value, trunk->name, station->name);
|
|
|
|
trunk_ref->ring_delay = 0;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Invalid option '%s' for "
|
|
|
|
"trunk '%s' on station '%s'\n", name, trunk->name, station->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
|
|
|
|
if (station_ref->station == station) {
|
|
|
|
station_ref->mark = 0;
|
|
|
|
existing_station_ref = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
|
|
|
|
if (!existing_trunk_ref) {
|
|
|
|
ao2_ref(trunk_ref, -1);
|
|
|
|
} else {
|
|
|
|
trunk_ref->mark = 1;
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-10 01:56:15 +00:00
|
|
|
|
|
|
|
if (!existing_station_ref) {
|
|
|
|
ao2_lock(trunk);
|
|
|
|
AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
|
|
|
|
ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
|
|
|
|
ao2_unlock(trunk);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!existing_trunk_ref) {
|
|
|
|
ao2_lock(station);
|
|
|
|
AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
|
|
|
|
ao2_unlock(station);
|
|
|
|
}
|
2007-02-22 23:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sla_build_station(struct ast_config *cfg, const char *cat)
|
2007-02-10 00:40:57 +00:00
|
|
|
{
|
2013-07-10 01:56:15 +00:00
|
|
|
RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
|
2007-02-10 00:40:57 +00:00
|
|
|
struct ast_variable *var;
|
|
|
|
const char *dev;
|
2013-07-10 01:56:15 +00:00
|
|
|
int existing_station = 0;
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
|
|
|
|
ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if ((station = sla_find_station(cat))) {
|
|
|
|
station->mark = 0;
|
|
|
|
existing_station = 1;
|
|
|
|
} else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
|
|
|
|
if (ast_string_field_init(station, 32)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ast_string_field_set(station, name, cat);
|
|
|
|
} else {
|
2007-02-10 00:40:57 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_lock(station);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_string_field_set(station, device, dev);
|
|
|
|
|
|
|
|
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!strcasecmp(var->name, "trunk")) {
|
|
|
|
ao2_unlock(station);
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_add_trunk_to_station(station, var);
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_lock(station);
|
|
|
|
} else if (!strcasecmp(var->name, "autocontext")) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_string_field_set(station, autocontext, var->value);
|
2013-07-10 01:56:15 +00:00
|
|
|
} else if (!strcasecmp(var->name, "ringtimeout")) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
|
2007-02-22 23:12:26 +00:00
|
|
|
ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
|
|
|
|
var->value, station->name);
|
|
|
|
station->ring_timeout = 0;
|
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
} else if (!strcasecmp(var->name, "ringdelay")) {
|
2009-08-10 19:20:57 +00:00
|
|
|
if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
|
2007-02-28 18:21:47 +00:00
|
|
|
ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
|
|
|
|
var->value, station->name);
|
|
|
|
station->ring_delay = 0;
|
|
|
|
}
|
2007-02-28 22:09:33 +00:00
|
|
|
} else if (!strcasecmp(var->name, "hold")) {
|
|
|
|
if (!strcasecmp(var->value, "private"))
|
|
|
|
station->hold_access = SLA_HOLD_PRIVATE;
|
|
|
|
else if (!strcasecmp(var->value, "open"))
|
|
|
|
station->hold_access = SLA_HOLD_OPEN;
|
|
|
|
else {
|
|
|
|
ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
|
|
|
|
var->value, station->name);
|
|
|
|
}
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
} else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
|
|
|
|
ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
|
|
|
|
var->name, var->lineno, SLA_CONFIG_FILE);
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_unlock(station);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
if (!ast_strlen_zero(station->autocontext)) {
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
2015-06-08 15:09:57 +00:00
|
|
|
|
|
|
|
if (!ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Failed to automatically find or create "
|
|
|
|
"context '%s' for SLA!\n", station->autocontext);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* The extension for when the handset goes off-hook.
|
|
|
|
* exten => station1,1,SLAStation(station1) */
|
2015-06-08 15:09:57 +00:00
|
|
|
if (ast_add_extension(station->autocontext, 0 /* don't replace */, station->name, 1,
|
2007-09-17 18:57:56 +00:00
|
|
|
NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Failed to automatically create extension "
|
|
|
|
"for trunk '%s'!\n", station->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
char exten[AST_MAX_EXTENSION];
|
|
|
|
char hint[AST_MAX_APP];
|
|
|
|
snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
|
|
|
|
snprintf(hint, sizeof(hint), "SLA:%s", exten);
|
2017-12-22 14:23:22 +00:00
|
|
|
/* Extension for this line button
|
2007-02-10 00:40:57 +00:00
|
|
|
* exten => station1_line1,1,SLAStation(station1_line1) */
|
2015-06-08 15:09:57 +00:00
|
|
|
if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, 1,
|
2007-09-17 18:57:56 +00:00
|
|
|
NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Failed to automatically create extension "
|
|
|
|
"for trunk '%s'!\n", station->name);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-12-22 14:23:22 +00:00
|
|
|
/* Hint for this line button
|
2007-02-10 00:40:57 +00:00
|
|
|
* exten => station1_line1,hint,SLA:station1_line1 */
|
2015-06-08 15:09:57 +00:00
|
|
|
if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, PRIORITY_HINT,
|
2007-02-10 00:40:57 +00:00
|
|
|
NULL, NULL, hint, NULL, NULL, sla_registrar)) {
|
|
|
|
ast_log(LOG_ERROR, "Failed to automatically create hint "
|
|
|
|
"for trunk '%s'!\n", station->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (!existing_station) {
|
|
|
|
ao2_link(sla_stations, station);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sla_trunk_mark(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_trunk *trunk = obj;
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
|
|
|
ao2_lock(trunk);
|
|
|
|
|
|
|
|
trunk->mark = 1;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
|
|
|
|
station_ref->mark = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ao2_unlock(trunk);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sla_station_mark(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_station *station = obj;
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
|
|
|
ao2_lock(station);
|
|
|
|
|
|
|
|
station->mark = 1;
|
|
|
|
|
|
|
|
AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
|
|
|
|
trunk_ref->mark = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ao2_unlock(station);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
return 0;
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
static int sla_trunk_is_marked(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_trunk *trunk = obj;
|
|
|
|
|
|
|
|
ao2_lock(trunk);
|
|
|
|
|
|
|
|
if (trunk->mark) {
|
|
|
|
/* Only remove all of the station references if the trunk itself is going away */
|
|
|
|
sla_trunk_release_refs(trunk, NULL, 0);
|
|
|
|
} else {
|
|
|
|
struct sla_station_ref *station_ref;
|
|
|
|
|
|
|
|
/* Otherwise only remove references to stations no longer in the config */
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&trunk->stations, station_ref, entry) {
|
|
|
|
if (!station_ref->mark) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
|
|
|
ao2_ref(station_ref, -1);
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END
|
|
|
|
}
|
|
|
|
|
|
|
|
ao2_unlock(trunk);
|
|
|
|
|
|
|
|
return trunk->mark ? CMP_MATCH : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sla_station_is_marked(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct sla_station *station = obj;
|
|
|
|
|
|
|
|
ao2_lock(station);
|
|
|
|
|
|
|
|
if (station->mark) {
|
|
|
|
/* Only remove all of the trunk references if the station itself is going away */
|
|
|
|
sla_station_release_refs(station, NULL, 0);
|
|
|
|
} else {
|
|
|
|
struct sla_trunk_ref *trunk_ref;
|
|
|
|
|
|
|
|
/* Otherwise only remove references to trunks no longer in the config */
|
|
|
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&station->trunks, trunk_ref, entry) {
|
|
|
|
if (!trunk_ref->mark) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
AST_LIST_REMOVE_CURRENT(entry);
|
|
|
|
ao2_ref(trunk_ref, -1);
|
|
|
|
}
|
|
|
|
AST_LIST_TRAVERSE_SAFE_END
|
|
|
|
}
|
|
|
|
|
|
|
|
ao2_unlock(station);
|
|
|
|
|
|
|
|
return station->mark ? CMP_MATCH : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sla_in_use(void)
|
|
|
|
{
|
|
|
|
return ao2_container_count(sla_trunks) || ao2_container_count(sla_stations);
|
|
|
|
}
|
|
|
|
|
2007-06-21 18:40:20 +00:00
|
|
|
static int sla_load_config(int reload)
|
2006-07-01 23:54:43 +00:00
|
|
|
{
|
|
|
|
struct ast_config *cfg;
|
2007-08-16 21:09:46 +00:00
|
|
|
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
2007-02-10 00:40:57 +00:00
|
|
|
const char *cat = NULL;
|
|
|
|
int res = 0;
|
2007-03-14 16:34:03 +00:00
|
|
|
const char *val;
|
2006-07-01 23:54:43 +00:00
|
|
|
|
2007-06-21 18:40:20 +00:00
|
|
|
if (!reload) {
|
|
|
|
ast_mutex_init(&sla.lock);
|
|
|
|
ast_cond_init(&sla.cond, NULL);
|
2018-11-19 20:10:02 +00:00
|
|
|
sla_trunks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
|
|
|
NULL, sla_trunk_cmp);
|
|
|
|
sla_stations = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
|
|
|
NULL, sla_station_cmp);
|
2007-06-21 18:40:20 +00:00
|
|
|
}
|
2007-02-28 18:21:47 +00:00
|
|
|
|
2008-09-12 23:30:03 +00:00
|
|
|
if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
|
2007-02-10 00:40:57 +00:00
|
|
|
return 0; /* Treat no config as normal */
|
2008-09-12 23:30:03 +00:00
|
|
|
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
|
2007-08-16 21:09:46 +00:00
|
|
|
return 0;
|
2008-09-12 23:30:03 +00:00
|
|
|
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
|
|
|
|
ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2012-01-09 15:40:16 +00:00
|
|
|
if (reload) {
|
2013-07-10 01:56:15 +00:00
|
|
|
ao2_callback(sla_trunks, 0, sla_trunk_mark, NULL);
|
|
|
|
ao2_callback(sla_stations, 0, sla_station_mark, NULL);
|
2012-01-09 15:40:16 +00:00
|
|
|
}
|
|
|
|
|
2007-03-14 16:34:03 +00:00
|
|
|
if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
|
|
|
|
sla.attempt_callerid = ast_true(val);
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
while ((cat = ast_category_browse(cfg, cat)) && !res) {
|
|
|
|
const char *type;
|
|
|
|
if (!strcasecmp(cat, "general"))
|
|
|
|
continue;
|
|
|
|
if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
|
|
|
|
SLA_CONFIG_FILE);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcasecmp(type, "trunk"))
|
2007-02-22 23:12:26 +00:00
|
|
|
res = sla_build_trunk(cfg, cat);
|
2007-02-10 00:40:57 +00:00
|
|
|
else if (!strcasecmp(type, "station"))
|
2007-02-22 23:12:26 +00:00
|
|
|
res = sla_build_station(cfg, cat);
|
2007-02-10 00:40:57 +00:00
|
|
|
else {
|
|
|
|
ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
|
|
|
|
SLA_CONFIG_FILE, type);
|
|
|
|
}
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2006-07-01 23:54:43 +00:00
|
|
|
ast_config_destroy(cfg);
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-07-10 01:56:15 +00:00
|
|
|
if (reload) {
|
|
|
|
ao2_callback(sla_trunks, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_trunk_is_marked, NULL);
|
|
|
|
ao2_callback(sla_stations, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_station_is_marked, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start SLA event processing thread once SLA has been configured. */
|
|
|
|
if (sla.thread == AST_PTHREADT_NULL && sla_in_use()) {
|
2007-06-21 18:40:20 +00:00
|
|
|
ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
|
2010-06-23 17:21:40 +00:00
|
|
|
}
|
2007-02-10 00:40:57 +00:00
|
|
|
|
|
|
|
return res;
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
2009-06-29 23:50:46 +00:00
|
|
|
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
|
2008-04-18 18:15:11 +00:00
|
|
|
{
|
|
|
|
if (!strcasecmp("lock", keyword)) {
|
|
|
|
return conf->locked;
|
|
|
|
} else if (!strcasecmp("parties", keyword)) {
|
|
|
|
return conf->users;
|
|
|
|
} else if (!strcasecmp("activity", keyword)) {
|
|
|
|
time_t now;
|
|
|
|
now = time(NULL);
|
|
|
|
return (now - conf->start);
|
|
|
|
} else if (!strcasecmp("dynamic", keyword)) {
|
|
|
|
return conf->isdynamic;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
struct ast_conference *conf;
|
|
|
|
char *parse;
|
|
|
|
int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
|
|
|
|
AST_DECLARE_APP_ARGS(args,
|
|
|
|
AST_APP_ARG(keyword);
|
|
|
|
AST_APP_ARG(confno);
|
|
|
|
);
|
|
|
|
|
|
|
|
if (ast_strlen_zero(data)) {
|
|
|
|
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse = ast_strdupa(data);
|
|
|
|
AST_STANDARD_APP_ARGS(args, parse);
|
|
|
|
|
|
|
|
if (ast_strlen_zero(args.keyword)) {
|
|
|
|
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_strlen_zero(args.confno)) {
|
|
|
|
ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
AST_LIST_LOCK(&confs);
|
|
|
|
AST_LIST_TRAVERSE(&confs, conf, list) {
|
|
|
|
if (!strcmp(args.confno, conf->confno)) {
|
|
|
|
result = acf_meetme_info_eval(args.keyword, conf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_LIST_UNLOCK(&confs);
|
|
|
|
|
|
|
|
if (result > -1) {
|
|
|
|
snprintf(buf, len, "%d", result);
|
|
|
|
} else if (result == -1) {
|
2009-11-05 22:12:45 +00:00
|
|
|
ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
|
|
|
|
snprintf(buf, len, "0");
|
2008-04-18 18:15:11 +00:00
|
|
|
} else if (result == -2) {
|
2017-12-22 14:23:22 +00:00
|
|
|
ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
|
2009-11-05 21:24:21 +00:00
|
|
|
snprintf(buf, len, "0");
|
2008-04-18 18:15:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct ast_custom_function meetme_info_acf = {
|
|
|
|
.name = "MEETME_INFO",
|
|
|
|
.read = acf_meetme_info,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
static int load_config(int reload)
|
2006-07-01 23:54:43 +00:00
|
|
|
{
|
2014-12-06 17:36:21 +00:00
|
|
|
load_config_meetme(reload);
|
2013-07-10 01:56:15 +00:00
|
|
|
return sla_load_config(reload);
|
2006-07-01 23:54:43 +00:00
|
|
|
}
|
|
|
|
|
2006-08-21 02:11:39 +00:00
|
|
|
static int unload_module(void)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2006-08-21 02:11:39 +00:00
|
|
|
int res = 0;
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
|
2006-09-18 19:54:18 +00:00
|
|
|
res = ast_manager_unregister("MeetmeMute");
|
2006-05-23 16:35:46 +00:00
|
|
|
res |= ast_manager_unregister("MeetmeUnmute");
|
2007-09-22 14:03:48 +00:00
|
|
|
res |= ast_manager_unregister("MeetmeList");
|
2011-02-09 22:48:02 +00:00
|
|
|
res |= ast_manager_unregister("MeetmeListRooms");
|
2007-05-07 22:14:09 +00:00
|
|
|
res |= ast_unregister_application(app4);
|
2005-10-18 22:52:21 +00:00
|
|
|
res |= ast_unregister_application(app3);
|
|
|
|
res |= ast_unregister_application(app2);
|
|
|
|
res |= ast_unregister_application(app);
|
2007-02-10 00:40:57 +00:00
|
|
|
res |= ast_unregister_application(slastation_app);
|
|
|
|
res |= ast_unregister_application(slatrunk_app);
|
2005-10-18 22:52:21 +00:00
|
|
|
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
ast_devstate_prov_del("Meetme");
|
2006-07-08 02:24:07 +00:00
|
|
|
ast_devstate_prov_del("SLA");
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2007-02-22 23:12:26 +00:00
|
|
|
sla_destroy();
|
2017-12-22 14:23:22 +00:00
|
|
|
|
2008-04-18 18:15:11 +00:00
|
|
|
res |= ast_custom_function_unregister(&meetme_info_acf);
|
2008-06-05 19:07:27 +00:00
|
|
|
ast_unload_realtime("meetme");
|
2007-02-10 00:40:57 +00:00
|
|
|
|
2013-06-07 15:54:26 +00:00
|
|
|
meetme_stasis_cleanup();
|
|
|
|
|
2005-10-18 22:52:21 +00:00
|
|
|
return res;
|
2002-05-13 22:29:39 +00:00
|
|
|
}
|
|
|
|
|
2012-10-01 23:22:50 +00:00
|
|
|
/*!
|
|
|
|
* \brief Load the module
|
|
|
|
*
|
|
|
|
* Module loading including tests for configuration or dependencies.
|
|
|
|
* This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
|
|
|
|
* or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
|
2017-12-22 14:23:22 +00:00
|
|
|
* tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
|
|
|
|
* configuration file or other non-critical problem return
|
2012-10-01 23:22:50 +00:00
|
|
|
* AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
|
|
|
|
*/
|
2006-08-21 02:11:39 +00:00
|
|
|
static int load_module(void)
|
2002-05-13 22:29:39 +00:00
|
|
|
{
|
2007-03-05 18:45:28 +00:00
|
|
|
int res = 0;
|
2005-10-18 22:52:21 +00:00
|
|
|
|
2007-02-28 18:21:47 +00:00
|
|
|
res |= load_config(0);
|
|
|
|
|
2013-06-07 15:54:26 +00:00
|
|
|
res |= meetme_stasis_init();
|
|
|
|
|
2007-02-10 00:40:57 +00:00
|
|
|
ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
|
2009-05-22 17:52:35 +00:00
|
|
|
res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
|
|
|
|
res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
|
|
|
|
res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
|
2011-02-09 22:48:02 +00:00
|
|
|
res |= ast_manager_register_xml("MeetmeListRooms", EVENT_FLAG_REPORTING, action_meetmelistrooms);
|
2008-11-13 15:46:06 +00:00
|
|
|
res |= ast_register_application_xml(app4, channel_admin_exec);
|
|
|
|
res |= ast_register_application_xml(app3, admin_exec);
|
|
|
|
res |= ast_register_application_xml(app2, count_exec);
|
|
|
|
res |= ast_register_application_xml(app, conf_exec);
|
|
|
|
res |= ast_register_application_xml(slastation_app, sla_station_exec);
|
|
|
|
res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
|
2002-05-13 22:29:39 +00:00
|
|
|
|
METERMAIDS:
-----------
- Adding devicestate providers, a new architecture to add non-channel related
device state information, like parking lots, queues, meetmes, vending machines
and Windows 98 reboots (lots of blinking on those lights)
- Adding provider for parking lots, so you can subscribe to the status of a
parking lot
- Adding provider for meetme, so you can have a blinking lamp for a meetme
( Example: exten => edvina,hint,meetme:1234 )
- Adding support for directed parking - set the PARKINGEXTEN before you manually
call Park() and you will be parked on that space. If it's occupied, dialplan
execution will continue.
This work was sponsored by Voop A/S - www.voop.com
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@36055 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-26 16:43:21 +00:00
|
|
|
res |= ast_devstate_prov_add("Meetme", meetmestate);
|
2007-02-10 00:40:57 +00:00
|
|
|
res |= ast_devstate_prov_add("SLA", sla_state);
|
|
|
|
|
2008-04-18 18:15:11 +00:00
|
|
|
res |= ast_custom_function_register(&meetme_info_acf);
|
2008-06-09 22:51:59 +00:00
|
|
|
ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
|
2008-04-18 18:15:11 +00:00
|
|
|
|
2005-10-18 22:52:21 +00:00
|
|
|
return res;
|
|
|
|
}
|
2005-01-07 07:23:31 +00:00
|
|
|
|
2006-08-21 02:11:39 +00:00
|
|
|
static int reload(void)
|
2005-11-08 23:19:30 +00:00
|
|
|
{
|
2008-06-05 19:07:27 +00:00
|
|
|
ast_unload_realtime("meetme");
|
2007-02-10 00:40:57 +00:00
|
|
|
return load_config(1);
|
2005-11-08 23:19:30 +00:00
|
|
|
}
|
|
|
|
|
2010-07-20 19:35:02 +00:00
|
|
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MeetMe conference bridge",
|
2021-08-11 11:15:16 +00:00
|
|
|
.support_level = AST_MODULE_SUPPORT_DEPRECATED,
|
2015-05-06 00:49:04 +00:00
|
|
|
.load = load_module,
|
|
|
|
.unload = unload_module,
|
|
|
|
.reload = reload,
|
|
|
|
.load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
|
2017-12-29 08:57:17 +00:00
|
|
|
.optional_modules = "func_speex",
|
2015-05-06 00:49:04 +00:00
|
|
|
);
|