Asterisk - The Open Source Telephony Project  GIT-master-a1fa8df
conf_config_parser.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2011, Digium, Inc.
5  *
6  * David Vossel <dvossel@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief ConfBridge config parser
22  *
23  * \author David Vossel <dvossel@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/logger.h"
33 #include "asterisk/config.h"
35 #include "include/confbridge.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/cli.h"
39 #include "asterisk/stringfields.h"
40 #include "asterisk/pbx.h"
41 
42 
43 /*** DOCUMENTATION
44  <configInfo name="app_confbridge" language="en_US">
45  <synopsis>Conference Bridge Application</synopsis>
46  <configFile name="confbridge.conf">
47  <configObject name="global">
48  <synopsis>Unused, but reserved.</synopsis>
49  </configObject>
50  <configObject name="user_profile">
51  <synopsis>A named profile to apply to specific callers.</synopsis>
52  <description><para>Callers in a ConfBridge have a profile associated with them
53  that determine their options. A configuration section is determined to be a
54  user_profile when the <literal>type</literal> parameter has a value
55  of <literal>user</literal>.
56  </para></description>
57  <configOption name="type">
58  <synopsis>Define this configuration category as a user profile.</synopsis>
59  <description><para>The type parameter determines how a context in the
60  configuration file is interpreted.</para>
61  <enumlist>
62  <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
63  <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
64  <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
65  </enumlist>
66  </description>
67  </configOption>
68  <configOption name="admin">
69  <synopsis>Sets if the user is an admin or not</synopsis>
70  </configOption>
71  <configOption name="send_events" default="no">
72  <synopsis>Sets if events are send to the user</synopsis>
73  <description><para>If events are enabled for this bridge and this option is
74  set, users will receive events like join, leave, talking, etc. via text
75  messages. For users accessing the bridge via chan_pjsip, this means
76  in-dialog MESSAGE messages. This is most useful for WebRTC participants
77  where the browser application can use the messages to alter the user
78  interface.</para></description>
79  </configOption>
80  <configOption name="echo_events" default="yes">
81  <synopsis>Sets if events are echoed back to the user that
82  triggered them</synopsis>
83  <description><para>If events are enabled for this user and this option
84  is set, the user will receive events they trigger, talking, mute, etc.
85  If not set, they will not receive their own events.
86  </para></description>
87  </configOption>
88  <configOption name="marked">
89  <synopsis>Sets if this is a marked user or not</synopsis>
90  </configOption>
91  <configOption name="startmuted">
92  <synopsis>Sets if all users should start out muted</synopsis>
93  </configOption>
94  <configOption name="music_on_hold_when_empty">
95  <synopsis>Play MOH when user is alone or waiting on a marked user</synopsis>
96  </configOption>
97  <configOption name="quiet">
98  <synopsis>Silence enter/leave prompts and user intros for this user</synopsis>
99  </configOption>
100  <configOption name="announce_user_count">
101  <synopsis>Sets if the number of users should be announced to the user</synopsis>
102  </configOption>
103  <configOption name="announce_user_count_all">
104  <synopsis>Announce user count to all the other users when this user joins</synopsis>
105  <description><para>Sets if the number of users should be announced to all the other users
106  in the conference when this user joins. This option can be either set to 'yes' or
107  a number. When set to a number, the announcement will only occur once the user
108  count is above the specified number.
109  </para></description>
110  </configOption>
111  <configOption name="announce_only_user">
112  <synopsis>Announce to a user when they join an empty conference</synopsis>
113  </configOption>
114  <configOption name="wait_marked">
115  <synopsis>Sets if the user must wait for a marked user to enter before joining a conference</synopsis>
116  </configOption>
117  <configOption name="end_marked">
118  <synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
119  </configOption>
120  <configOption name="talk_detection_events">
121  <synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
122  </configOption>
123  <configOption name="dtmf_passthrough">
124  <synopsis>Sets whether or not DTMF should pass through the conference</synopsis>
125  </configOption>
126  <configOption name="announce_join_leave">
127  <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter</synopsis>
128  </configOption>
129  <configOption name="announce_join_leave_review">
130  <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter.
131  The user will be asked to review the recording of their name before entering the conference.</synopsis>
132  </configOption>
133  <configOption name="pin">
134  <synopsis>Sets a PIN the user must enter before joining the conference</synopsis>
135  </configOption>
136  <configOption name="music_on_hold_class">
137  <synopsis>The MOH class to use for this user</synopsis>
138  </configOption>
139  <configOption name="announcement">
140  <synopsis>Sound file to play to the user when they join a conference</synopsis>
141  </configOption>
142  <configOption name="denoise">
143  <synopsis>Apply a denoise filter to the audio before mixing</synopsis>
144  <description><para>Sets whether or not a denoise filter should be applied
145  to the audio before mixing or not. Off by default. Requires
146  <literal>codec_speex</literal> to be built and installed. Do not confuse this option
147  with <replaceable>drop_silence</replaceable>. Denoise is useful if there is a lot of background
148  noise for a user as it attempts to remove the noise while preserving
149  the speech. This option does NOT remove silence from being mixed into
150  the conference and does come at the cost of a slight performance hit.
151  </para></description>
152  </configOption>
153  <configOption name="dsp_drop_silence">
154  <synopsis>Drop what Asterisk detects as silence from audio sent to the bridge</synopsis>
155  <description><para>
156  This option drops what Asterisk detects as silence from
157  entering into the bridge. Enabling this option will drastically
158  improve performance and help remove the buildup of background
159  noise from the conference. Highly recommended for large conferences
160  due to its performance enhancements.
161  </para></description>
162  </configOption>
163  <configOption name="dsp_silence_threshold">
164  <synopsis>The number of milliseconds of silence necessary to declare talking stopped.</synopsis>
165  <description>
166  <para>The time in milliseconds of sound falling below the
167  <replaceable>dsp_talking_threshold</replaceable> option when
168  a user is considered to stop talking. This value affects several
169  operations and should not be changed unless the impact on call
170  quality is fully understood.
171  </para>
172  <para>What this value affects internally:
173  </para>
174  <para>1. When talk detection AMI events are enabled, this value
175  determines when the user has stopped talking after a
176  period of talking. If this value is set too low
177  AMI events indicating the user has stopped talking
178  may get falsely sent out when the user briefly pauses
179  during mid sentence.
180  </para>
181  <para>2. The <replaceable>drop_silence</replaceable> option
182  depends on this value to determine when the user's audio should
183  begin to be dropped from the conference bridge after the user
184  stops talking. If this value is set too low the user's
185  audio stream may sound choppy to the other participants. This
186  is caused by the user transitioning constantly from silence to
187  talking during mid sentence.
188  </para>
189  <para>The best way to approach this option is to set it slightly
190  above the maximum amount of milliseconds of silence a user may
191  generate during natural speech.
192  </para>
193  <para>Valid values are 1 through 2^31.</para>
194  </description>
195  </configOption>
196  <configOption name="dsp_talking_threshold">
197  <synopsis>Average magnitude threshold to determine talking.</synopsis>
198  <description>
199  <para>The minimum average magnitude per sample in a frame
200  for the DSP to consider talking/noise present. A value below
201  this level is considered silence. This value affects several
202  operations and should not be changed unless the impact on call
203  quality is fully understood.
204  </para>
205  <para>What this value affects internally:
206  </para>
207  <para>1. Audio is only mixed out of a user's incoming audio
208  stream if talking is detected. If this value is set too
209  high the user will hear himself talking.
210  </para>
211  <para>2. When talk detection AMI events are enabled, this value
212  determines when talking has begun which results in
213  an AMI event to fire. If this value is set too low
214  AMI events may be falsely triggered by variants in
215  room noise.
216  </para>
217  <para>3. The <replaceable>drop_silence</replaceable> option
218  depends on this value to determine when the user's audio should
219  be mixed into the bridge after periods of silence. If this value
220  is too high the user's speech will get discarded as they will
221  be considered silent.
222  </para>
223  <para>Valid values are 1 through 2^15.</para>
224  </description>
225  </configOption>
226  <configOption name="jitterbuffer">
227  <synopsis>Place a jitter buffer on the user's audio stream before audio mixing is performed</synopsis>
228  <description><para>
229  Enabling this option places a jitterbuffer on the user's audio stream
230  before audio mixing is performed. This is highly recommended but will
231  add a slight delay to the audio. This option is using the <literal>JITTERBUFFER</literal>
232  dialplan function's default adaptive jitterbuffer. For a more fine tuned
233  jitterbuffer, disable this option and use the <literal>JITTERBUFFER</literal> dialplan function
234  on the user before entering the ConfBridge application.
235  </para></description>
236  </configOption>
237  <configOption name="template">
238  <synopsis>When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile</synopsis>
239  </configOption>
240  <configOption name="timeout">
241  <synopsis>Kick the user out of the conference after this many seconds. 0 means there is no timeout for the user.</synopsis>
242  </configOption>
243  <configOption name="text_messaging" default="yes">
244  <synopsis>Sets if text messages are sent to the user.</synopsis>
245  <description><para>If text messaging is enabled for this user then
246  text messages will be sent to it. These may be events or from other
247  participants in the conference bridge. If disabled then no text
248  messages are sent to the user.</para></description>
249  </configOption>
250  <configOption name="answer_channel" default="yes">
251  <synopsis>Sets if a user's channel should be answered if currently unanswered.</synopsis>
252  </configOption>
253  </configObject>
254  <configObject name="bridge_profile">
255  <synopsis>A named profile to apply to specific bridges.</synopsis>
256  <description><para>ConfBridge bridges have a profile associated with them
257  that determine their options. A configuration section is determined to be a
258  <literal>bridge_profile</literal> when the <literal>type</literal> parameter has a value
259  of <literal>bridge</literal>.
260  </para></description>
261  <configOption name="type">
262  <synopsis>Define this configuration category as a bridge profile</synopsis>
263  <description><para>The type parameter determines how a context in the
264  configuration file is interpreted.</para>
265  <enumlist>
266  <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
267  <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
268  <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
269  </enumlist>
270  </description>
271  </configOption>
272  <configOption name="jitterbuffer">
273  <synopsis>Place a jitter buffer on the conference's audio stream</synopsis>
274  </configOption>
275  <configOption name="internal_sample_rate">
276  <synopsis>Set the internal native sample rate for mixing the conference</synopsis>
277  <description><para>
278  Sets the internal native sample rate the
279  conference is mixed at. This is set to automatically
280  adjust the sample rate to the best quality by default.
281  Other values can be anything from 8000-192000. If a
282  sample rate is set that Asterisk does not support, the
283  closest sample rate Asterisk does support to the one requested
284  will be used.
285  </para></description>
286  </configOption>
287  <configOption name="maximum_sample_rate">
288  <synopsis>Set the maximum native sample rate for mixing the conference</synopsis>
289  <description><para>
290  Sets the maximum native sample rate the
291  conference is mixed at. This is set to not have a
292  maximum by default. If a sample rate is specified,
293  though, the native sample rate will never exceed it.
294  </para></description>
295  </configOption>
296  <configOption name="language" default="en">
297  <synopsis>The language used for announcements to the conference.</synopsis>
298  <description><para>
299  By default, announcements to a conference use English. Which means
300  the prompts played to all users within the conference will be
301  English. By changing the language of a bridge, this will change
302  the language of the prompts played to all users.
303  </para></description>
304  </configOption>
305  <configOption name="mixing_interval">
306  <synopsis>Sets the internal mixing interval in milliseconds for the bridge</synopsis>
307  <description><para>
308  Sets the internal mixing interval in milliseconds for the bridge. This
309  number reflects how tight or loose the mixing will be for the conference.
310  In order to improve performance a larger mixing interval such as 40ms may
311  be chosen. Using a larger mixing interval comes at the cost of introducing
312  larger amounts of delay into the bridge. Valid values here are 10, 20, 40,
313  or 80.
314  </para></description>
315  </configOption>
316  <configOption name="binaural_active">
317  <synopsis>If true binaural conferencing with stereo audio is active</synopsis>
318  <description><para>
319  Activates binaural mixing for a conference bridge.
320  Binaural features are disabled by default.
321  </para></description>
322  </configOption>
323  <configOption name="record_conference">
324  <synopsis>Record the conference starting with the first active user's entrance and ending with the last active user's exit</synopsis>
325  <description><para>
326  Records the conference call starting when the first user
327  enters the room, and ending when the last user exits the room.
328  The default recorded filename is
329  <filename>'confbridge-${name of conference bridge}-${start time}.wav'</filename>
330  and the default format is 8khz slinear. This file will be
331  located in the configured monitoring directory in <filename>asterisk.conf</filename>.
332  </para></description>
333  </configOption>
334  <configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
335  <synopsis>The filename of the conference recording</synopsis>
336  <description><para>
337  When <replaceable>record_conference</replaceable> is set to yes, the specific name of the
338  record file can be set using this option. Note that since multiple
339  conferences may use the same bridge profile, this may cause issues
340  depending on the configuration. It is recommended to only use this
341  option dynamically with the <literal>CONFBRIDGE()</literal> dialplan function. This
342  allows the record name to be specified and a unique name to be chosen.
343  By default, the record_file is stored in Asterisk's spool/monitor directory
344  with a unique filename starting with the 'confbridge' prefix.
345  </para></description>
346  </configOption>
347  <configOption name="record_file_append" default="yes">
348  <synopsis>Append to record file when starting/stopping on same conference recording</synopsis>
349  <description><para>
350  When <replaceable>record_file_append</replaceable> is set to yes, stopping and starting recording on a
351  conference adds the new portion to end of current record_file. When this is
352  set to no, a new <replaceable>record_file</replaceable> is generated every time you start then stop recording
353  on a conference.
354  </para></description>
355  </configOption>
356  <configOption name="record_file_timestamp" default="yes">
357  <synopsis>Append the start time to the record_file name so that it is unique.</synopsis>
358  <description><para>
359  When <replaceable>record_file_timestamp</replaceable> is set to yes, the start time is appended to
360  <replaceable>record_file</replaceable> so that the filename is unique. This allows you to specify
361  a <replaceable>record_file</replaceable> but not overwrite existing recordings.
362  </para></description>
363  </configOption>
364  <configOption name="record_options" default="">
365  <synopsis>Pass additional options to MixMonitor when recording</synopsis>
366  <description><para>
367  Pass additional options to MixMonitor when <replaceable>record_conference</replaceable> is set to yes.
368  See <literal>MixMonitor</literal> for available options.
369  </para></description>
370  </configOption>
371  <configOption name="record_command" default="">
372  <synopsis>Execute a command after recording ends</synopsis>
373  <description><para>
374  Executes the specified command when recording ends. Any strings matching <literal>^{X}</literal> will be
375  unescaped to <variable>X</variable>. All variables will be evaluated at the time ConfBridge is called.
376  </para></description>
377  </configOption>
378  <configOption name="regcontext">
379  <synopsis>The name of the context into which to register the name of the conference bridge as NoOP() at priority 1</synopsis>
380  <description><para>
381  When set this will cause the name of the created conference to be registered
382  into the named context at priority 1 with an operation of NoOP(). This can
383  then be used in other parts of the dialplan to test for the existence of a
384  specific conference bridge.
385  You should be aware that there are potential races between testing for the
386  existence of a bridge, and taking action upon that information, consider
387  for example two callers executing the check simultaniously, and then taking
388  special action as "first caller" into the bridge. The same for exiting,
389  directly after the check the bridge can be destroyed before the new caller
390  enters (creating a new bridge), for example, and the "first member" actions
391  could thus be missed.
392  </para></description>
393  </configOption>
394  <configOption name="video_mode">
395  <synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis>
396  <description><para>
397  Sets how confbridge handles video distribution to the conference participants.
398  Note that participants wanting to view and be the source of a video feed
399  <emphasis>MUST</emphasis> be sharing the same video codec. Also, using video in conjunction with
400  with the jitterbuffer currently results in the audio being slightly out of sync
401  with the video. This is a result of the jitterbuffer only working on the audio
402  stream. It is recommended to disable the jitterbuffer when video is used.</para>
403  <enumlist>
404  <enum name="none">
405  <para>No video sources are set by default in the conference. It is still
406  possible for a user to be set as a video source via AMI or DTMF action
407  at any time.</para>
408  </enum>
409  <enum name="follow_talker">
410  <para>The video feed will follow whoever is talking and providing video.</para>
411  </enum>
412  <enum name="last_marked">
413  <para>The last marked user to join the conference with video capabilities
414  will be the single source of video distributed to all participants.
415  If multiple marked users are capable of video, the last one to join
416  is always the source, when that user leaves it goes to the one who
417  joined before them.</para>
418  </enum>
419  <enum name="first_marked">
420  <para>The first marked user to join the conference with video capabilities
421  is the single source of video distribution among all participants. If
422  that user leaves, the marked user to join after them becomes the source.</para>
423  </enum>
424  <enum name="sfu">
425  <para>Selective Forwarding Unit - Sets multi-stream
426  operation for a multi-party video conference.</para>
427  </enum>
428  </enumlist>
429  </description>
430  </configOption>
431  <configOption name="max_members">
432  <synopsis>Limit the maximum number of participants for a single conference</synopsis>
433  <description><para>
434  This option limits the number of participants for a single
435  conference to a specific number. By default conferences
436  have no participant limit. After the limit is reached, the
437  conference will be locked until someone leaves. Note however
438  that an Admin user will always be alowed to join the conference
439  regardless if this limit is reached or not.
440  </para></description>
441  </configOption>
442  <configOption name="sound_">
443  <synopsis>Override the various conference bridge sound files</synopsis>
444  <description><para>
445  All sounds in the conference are customizable using the bridge profile options below.
446  Simply state the option followed by the filename or full path of the filename after
447  the option. Example: <literal>sound_had_joined=conf-hasjoin</literal> This will play the <literal>conf-hasjoin</literal>
448  sound file found in the sounds directory when announcing someone's name is joining the
449  conference.</para>
450  <enumlist>
451  <enum name="sound_join"><para>The sound played to everyone when someone enters the conference.</para></enum>
452  <enum name="sound_leave"><para>The sound played to everyone when someone leaves the conference.</para></enum>
453  <enum name="sound_has_joined"><para>The sound played before announcing someone's name has
454  joined the conference. This is used for user intros.
455  Example <literal>"_____ has joined the conference"</literal></para></enum>
456  <enum name="sound_has_left"><para>The sound played when announcing someone's name has
457  left the conference. This is used for user intros.
458  Example <literal>"_____ has left the conference"</literal></para></enum>
459  <enum name="sound_kicked"><para>The sound played to a user who has been kicked from the conference.</para></enum>
460  <enum name="sound_muted"><para>The sound played when the mute option it toggled on.</para></enum>
461  <enum name="sound_unmuted"><para>The sound played when the mute option it toggled off.</para></enum>
462  <enum name="sound_binaural_on"><para>The sound played when binaural auudio is turned on.</para></enum>
463  <enum name="sound_binaural_off"><para>The sound played when the binaural audio is turned off.</para></enum>
464  <enum name="sound_only_person"><para>The sound played when the user is the only person in the conference.</para></enum>
465  <enum name="sound_only_one"><para>The sound played to a user when there is only one other
466  person is in the conference.</para></enum>
467  <enum name="sound_there_are"><para>The sound played when announcing how many users there
468  are in a conference.</para></enum>
469  <enum name="sound_other_in_party"><para>This file is used in conjunction with <literal>sound_there_are</literal>
470  when announcing how many users there are in the conference.
471  The sounds are stringed together like this.
472  <literal>"sound_there_are" ${number of participants} "sound_other_in_party"</literal></para></enum>
473  <enum name="sound_place_into_conference"><para>The sound played when someone is placed into the conference
474  after waiting for a marked user.</para></enum>
475  <enum name="sound_wait_for_leader"><para>The sound played when a user is placed into a conference that
476  can not start until a marked user enters.</para></enum>
477  <enum name="sound_leader_has_left"><para>The sound played when the last marked user leaves the conference.</para></enum>
478  <enum name="sound_get_pin"><para>The sound played when prompting for a conference pin number.</para></enum>
479  <enum name="sound_invalid_pin"><para>The sound played when an invalid pin is entered too many times.</para></enum>
480  <enum name="sound_locked"><para>The sound played to a user trying to join a locked conference.</para></enum>
481  <enum name="sound_locked_now"><para>The sound played to an admin after toggling the conference to locked mode.</para></enum>
482  <enum name="sound_unlocked_now"><para>The sound played to an admin after toggling the conference to unlocked mode.</para></enum>
483  <enum name="sound_error_menu"><para>The sound played when an invalid menu option is entered.</para></enum>
484  </enumlist>
485  </description>
486  </configOption>
487  <configOption name="video_update_discard" default="2000">
488  <synopsis>Sets the amount of time in milliseconds after sending a video update to discard subsequent video updates</synopsis>
489  <description><para>
490  Sets the amount of time in milliseconds after sending a video update request
491  that subsequent video updates should be discarded. This means that if we
492  send a video update we will discard any other video update requests until
493  after the configured amount of time has elapsed. This prevents flooding of
494  video update requests from clients.
495  </para></description>
496  </configOption>
497  <configOption name="remb_send_interval" default="0">
498  <synopsis>Sets the interval in milliseconds that a combined REMB frame will be sent to video sources</synopsis>
499  <description><para>
500  Sets the interval in milliseconds that a combined REMB frame will be sent
501  to video sources. This is done by taking all REMB frames that have been
502  received since the last REMB frame was sent, making a combined value,
503  and sending it to the source. A REMB frame contains receiver estimated
504  maximum bitrate information. By creating a combined REMB frame the
505  sender of video can be influenced on the bitrate they choose, allowing
506  better quality for all receivers.
507  </para></description>
508  </configOption>
509  <configOption name="remb_behavior" default="average">
510  <synopsis>Sets how REMB reports are generated from multiple sources</synopsis>
511  <description><para>
512  Sets how REMB reports are combined from multiple sources to form one. A REMB report
513  consists of information about the receiver estimated maximum bitrate. As a source
514  stream may be forwarded to multiple receivers the reports must be combined into
515  a single one which is sent to the sender.</para>
516  <enumlist>
517  <enum name="average">
518  <para>The average of all estimated maximum bitrates is taken and sent
519  to the sender.</para>
520  </enum>
521  <enum name="lowest">
522  <para>The lowest estimated maximum bitrate is forwarded to the sender.</para>
523  </enum>
524  <enum name="highest">
525  <para>The highest estimated maximum bitrate is forwarded to the sender.</para>
526  </enum>
527  <enum name="average_all">
528  <para>The average of all estimated maximum bitrates is taken from all
529  receivers in the bridge and a single value is sent to each sender.</para>
530  </enum>
531  <enum name="lowest_all">
532  <para>The lowest estimated maximum bitrate of all receivers in the bridge
533  is taken and sent to each sender.</para>
534  </enum>
535  <enum name="highest_all">
536  <para>The highest estimated maximum bitrate of all receivers in the bridge
537  is taken and sent to each sender.</para>
538  </enum>
539  <enum name="force">
540  <para>The bitrate configured in <literal>remb_estimated_bitrate</literal>
541  is sent to each sender.</para>
542  </enum>
543  </enumlist>
544  </description>
545  <see-also><ref type="configOption">remb_estimated_bitrate</ref></see-also>
546  </configOption>
547  <configOption name="remb_estimated_bitrate">
548  <synopsis>Sets the estimated bitrate sent to each participant in REMB reports</synopsis>
549  <description><para>
550  When <literal>remb_behavior</literal> is set to <literal>force</literal>,
551  this options sets the estimated bitrate (in bits per second) sent to each participant
552  in REMB reports.
553  </para></description>
554  <see-also><ref type="configOption">remb_behavior</ref></see-also>
555  </configOption>
556  <configOption name="enable_events" default="no">
557  <synopsis>Enables events for this bridge</synopsis>
558  <description><para>
559  If enabled, recipients who joined the bridge via a channel driver
560  that supports Enhanced Messaging (currently only chan_pjsip) will
561  receive in-dialog messages containing a JSON body describing the
562  event. The Content-Type header will be
563  <literal>text/x-ast-confbridge-event</literal>.
564  This feature must also be enabled in user profiles.</para>
565  </description>
566  </configOption>
567  <configOption name="template">
568  <synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
569  </configOption>
570  </configObject>
571  <configObject name="menu">
572  <synopsis>A conference user menu</synopsis>
573  <description>
574  <para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
575  can have a DTMF menu assigned to their profile when they enter the
576  <literal>ConfBridge</literal> application.</para>
577  </description>
578  <configOption name="type">
579  <synopsis>Define this configuration category as a menu</synopsis>
580  <description><para>The type parameter determines how a context in the
581  configuration file is interpreted.</para>
582  <enumlist>
583  <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
584  <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
585  <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
586  </enumlist>
587  </description>
588  </configOption>
589  <configOption name="template">
590  <synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
591  </configOption>
592  <configOption name="^[0-9A-D*#]+$">
593  <synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
594  <description>
595  <para>The ConfBridge application also has the ability to apply custom DTMF menus to
596  each channel using the application. Like the User and Bridge profiles a menu
597  is passed in to ConfBridge as an argument in the dialplan.</para>
598  <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
599  <note><para>
600  To have the first DTMF digit in a sequence be the '#' character, you need to
601  escape it. If it is not escaped then normal config file processing will
602  think it is a directive like #include. For example: The mute setting is
603  toggled when <literal>#1</literal> is pressed.</para>
604  <para><literal>\#1=toggle_mute</literal></para>
605  </note>
606  <note><para>
607  A single DTMF sequence can have multiple actions associated with it. This is
608  accomplished by stringing the actions together and using a <literal>,</literal> as the
609  delimiter. Example: Both listening and talking volume is reset when <literal>5</literal> is
610  pressed. <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
611  <enumlist>
612  <enum name="playback(filename&amp;filename2&amp;...)"><para>
613  <literal>playback</literal> will play back an audio file to a channel
614  and then immediately return to the conference.
615  This file can not be interupted by DTMF.
616  Multiple files can be chained together using the
617  <literal>&amp;</literal> character.</para></enum>
618  <enum name="playback_and_continue(filename&amp;filename2&amp;...)"><para>
619  <literal>playback_and_continue</literal> will
620  play back a prompt while continuing to
621  collect the dtmf sequence. This is useful
622  when using a menu prompt that describes all
623  the menu options. Note however that any DTMF
624  during this action will terminate the prompts
625  playback. Prompt files can be chained together
626  using the <literal>&amp;</literal> character as a delimiter.</para></enum>
627  <enum name="toggle_mute"><para>
628  Toggle turning on and off mute. Mute will make the user silent
629  to everyone else, but the user will still be able to listen in.
630  </para></enum>
631  <enum name="toggle_binaural"><para>
632  Toggle turning on and off binaural audio processing.
633  </para></enum>
634  <enum name="no_op"><para>
635  This action does nothing (No Operation). Its only real purpose exists for
636  being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
637  <enum name="decrease_listening_volume"><para>
638  Decreases the channel's listening volume.</para></enum>
639  <enum name="increase_listening_volume"><para>
640  Increases the channel's listening volume.</para></enum>
641  <enum name="reset_listening_volume"><para>
642  Reset channel's listening volume to default level.</para></enum>
643  <enum name="decrease_talking_volume"><para>
644  Decreases the channel's talking volume.</para></enum>
645  <enum name="increase_talking_volume"><para>
646  Increases the channel's talking volume.</para></enum>
647  <enum name="reset_talking_volume"><para>
648  Reset channel's talking volume to default level.</para></enum>
649  <enum name="dialplan_exec(context,exten,priority)"><para>
650  The <literal>dialplan_exec</literal> action allows a user
651  to escape from the conference and execute
652  commands in the dialplan. Once the dialplan
653  exits the user will be put back into the
654  conference. The possibilities are endless!</para></enum>
655  <enum name="leave_conference"><para>
656  This action allows a user to exit the conference and continue
657  execution in the dialplan.</para></enum>
658  <enum name="admin_kick_last"><para>
659  This action allows an Admin to kick the last participant from the
660  conference. This action will only work for admins which allows
661  a single menu to be used for both users and admins.</para></enum>
662  <enum name="admin_toggle_conference_lock"><para>
663  This action allows an Admin to toggle locking and
664  unlocking the conference. Non admins can not use
665  this action even if it is in their menu.</para></enum>
666  <enum name="set_as_single_video_src"><para>
667  This action allows any user to set themselves as the
668  single video source distributed to all participants.
669  This will make the video feed stick to them regardless
670  of what the <literal>video_mode</literal> is set to.</para></enum>
671  <enum name="release_as_single_video_src"><para>
672  This action allows a user to release themselves as
673  the video source. If <literal>video_mode</literal> is not set to <literal>none</literal>
674  this action will result in the conference returning to
675  whatever video mode the bridge profile is using.</para>
676  <para>Note that this action will have no effect if the user
677  is not currently the video source. Also, the user is
678  not guaranteed by using this action that they will not
679  become the video source again. The bridge will return
680  to whatever operation the <literal>video_mode</literal> option is set to
681  upon release of the video src.</para></enum>
682  <enum name="admin_toggle_mute_participants"><para>
683  This action allows an administrator to toggle the mute
684  state for all non-admins within a conference. All
685  admin users are unaffected by this option. Note that all
686  users, regardless of their admin status, are notified
687  that the conference is muted.</para></enum>
688  <enum name="participant_count"><para>
689  This action plays back the number of participants currently
690  in a conference</para></enum>
691  </enumlist>
692  </description>
693  </configOption>
694  </configObject>
695  </configFile>
696  </configInfo>
697 ***/
698 
703 };
704 
705 static int verify_default_profiles(void);
706 static void *bridge_profile_alloc(const char *category);
707 static void *bridge_profile_find(struct ao2_container *container, const char *category);
709 
710 static void bridge_profile_destructor(void *obj)
711 {
712  struct bridge_profile *b_profile = obj;
713  ao2_cleanup(b_profile->sounds);
714 }
715 
716 static void *bridge_profile_alloc(const char *category)
717 {
718  struct bridge_profile *b_profile;
719 
720  if (!(b_profile = ao2_alloc(sizeof(*b_profile), bridge_profile_destructor))) {
721  return NULL;
722  }
723 
724  if (!(b_profile->sounds = bridge_profile_sounds_alloc())) {
725  ao2_ref(b_profile, -1);
726  return NULL;
727  }
728 
729  ast_copy_string(b_profile->name, category, sizeof(b_profile->name));
730 
731  return b_profile;
732 }
733 
734 static void *bridge_profile_find(struct ao2_container *container, const char *category)
735 {
736  return ao2_find(container, category, OBJ_KEY);
737 }
738 
739 static struct aco_type bridge_type = {
740  .type = ACO_ITEM,
741  .name = "bridge_profile",
742  .category_match = ACO_BLACKLIST_EXACT,
743  .category = "general",
744  .matchfield = "type",
745  .matchvalue = "bridge",
746  .item_alloc = bridge_profile_alloc,
747  .item_find = bridge_profile_find,
748  .item_offset = offsetof(struct confbridge_cfg, bridge_profiles),
749 };
750 
751 static void *user_profile_alloc(const char *category);
752 static void *user_profile_find(struct ao2_container *container, const char *category);
753 static void user_profile_destructor(void *obj)
754 {
755  return;
756 }
757 
758 static void *user_profile_alloc(const char *category)
759 {
760  struct user_profile *u_profile;
761 
762  if (!(u_profile = ao2_alloc(sizeof(*u_profile), user_profile_destructor))) {
763  return NULL;
764  }
765 
766  ast_copy_string(u_profile->name, category, sizeof(u_profile->name));
767 
768  return u_profile;
769 }
770 
771 static void *user_profile_find(struct ao2_container *container, const char *category)
772 {
773  return ao2_find(container, category, OBJ_KEY);
774 }
775 
776 static struct aco_type user_type = {
777  .type = ACO_ITEM,
778  .name = "user_profile",
779  .category_match = ACO_BLACKLIST_EXACT,
780  .category = "general",
781  .matchfield = "type",
782  .matchvalue = "user",
783  .item_alloc = user_profile_alloc,
784  .item_find = user_profile_find,
785  .item_offset = offsetof(struct confbridge_cfg, user_profiles),
786 };
787 
788 static void *menu_alloc(const char *category);
789 static void *menu_find(struct ao2_container *container, const char *category);
790 static void menu_destructor(void *obj);
791 
792 static void *menu_alloc(const char *category)
793 {
794  struct conf_menu *menu;
795  if (!(menu = ao2_alloc(sizeof(*menu), menu_destructor))) {
796  return NULL;
797  }
798  ast_copy_string(menu->name, category, sizeof(menu->name));
799  return menu;
800 }
801 
802 static void *menu_find(struct ao2_container *container, const char *category)
803 {
804  return ao2_find(container, category, OBJ_KEY);
805 }
806 
807 static struct aco_type menu_type = {
808  .type = ACO_ITEM,
809  .name = "menu",
810  .category_match = ACO_BLACKLIST_EXACT,
811  .category = "general",
812  .matchfield = "type",
813  .matchvalue = "menu",
814  .item_alloc = menu_alloc,
815  .item_find = menu_find,
816  .item_offset = offsetof(struct confbridge_cfg, menus),
817 };
818 
819 /* Used to pass to aco_option_register */
820 static struct aco_type *bridge_types[] = ACO_TYPES(&bridge_type);
821 static struct aco_type *menu_types[] = ACO_TYPES(&menu_type);
822 static struct aco_type *user_types[] = ACO_TYPES(&user_type);
823 
824 /* The general category is reserved, but unused */
825 static struct aco_type general_type = {
826  .type = ACO_GLOBAL,
827  .name = "global",
828  .category_match = ACO_WHITELIST_EXACT,
829  .category = "general",
830 };
831 
832 static struct aco_file confbridge_conf = {
833  .filename = "confbridge.conf",
834  .types = ACO_TYPES(&bridge_type, &user_type, &menu_type, &general_type),
835 };
836 
838 
839 static void *confbridge_cfg_alloc(void);
840 
842  .files = ACO_FILES(&confbridge_conf),
843  .pre_apply_config = verify_default_profiles,
844 );
845 
846 /*! bridge profile container functions */
847 static int bridge_cmp_cb(void *obj, void *arg, int flags)
848 {
849  const struct bridge_profile *left = obj;
850  const struct bridge_profile *right = arg;
851  const char *right_name = arg;
852  int cmp;
853 
854  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
855  default:
856  case OBJ_POINTER:
857  right_name = right->name;
858  /* Fall through */
859  case OBJ_KEY:
860  cmp = strcasecmp(left->name, right_name);
861  break;
862  case OBJ_PARTIAL_KEY:
863  cmp = strncasecmp(left->name, right_name, strlen(right_name));
864  break;
865  }
866  return cmp ? 0 : CMP_MATCH;
867 }
868 
869 static int bridge_hash_cb(const void *obj, const int flags)
870 {
871  const struct bridge_profile *b_profile = obj;
872  const char *name = obj;
873  int hash;
874 
875  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
876  default:
877  case OBJ_POINTER:
878  name = b_profile->name;
879  /* Fall through */
880  case OBJ_KEY:
881  hash = ast_str_case_hash(name);
882  break;
883  case OBJ_PARTIAL_KEY:
884  /* Should never happen in hash callback. */
885  ast_assert(0);
886  hash = 0;
887  break;
888  }
889  return hash;
890 }
891 
892 /*! menu container functions */
893 static int menu_cmp_cb(void *obj, void *arg, int flags)
894 {
895  const struct conf_menu *left = obj;
896  const struct conf_menu *right = arg;
897  const char *right_name = arg;
898  int cmp;
899 
900  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
901  default:
902  case OBJ_POINTER:
903  right_name = right->name;
904  /* Fall through */
905  case OBJ_KEY:
906  cmp = strcasecmp(left->name, right_name);
907  break;
908  case OBJ_PARTIAL_KEY:
909  cmp = strncasecmp(left->name, right_name, strlen(right_name));
910  break;
911  }
912  return cmp ? 0 : CMP_MATCH;
913 }
914 
915 static int menu_hash_cb(const void *obj, const int flags)
916 {
917  const struct conf_menu *menu = obj;
918  const char *name = obj;
919  int hash;
920 
921  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
922  default:
923  case OBJ_POINTER:
924  name = menu->name;
925  /* Fall through */
926  case OBJ_KEY:
927  hash = ast_str_case_hash(name);
928  break;
929  case OBJ_PARTIAL_KEY:
930  /* Should never happen in hash callback. */
931  ast_assert(0);
932  hash = 0;
933  break;
934  }
935  return hash;
936 }
937 
938 static void menu_destructor(void *obj)
939 {
940  struct conf_menu *menu = obj;
941  struct conf_menu_entry *entry = NULL;
942 
943  while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
945  ast_free(entry);
946  }
947 }
948 
949 /*! User profile container functions */
950 static int user_cmp_cb(void *obj, void *arg, int flags)
951 {
952  const struct user_profile *left = obj;
953  const struct user_profile *right = arg;
954  const char *right_name = arg;
955  int cmp;
956 
957  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
958  default:
959  case OBJ_POINTER:
960  right_name = right->name;
961  /* Fall through */
962  case OBJ_KEY:
963  cmp = strcasecmp(left->name, right_name);
964  break;
965  case OBJ_PARTIAL_KEY:
966  cmp = strncasecmp(left->name, right_name, strlen(right_name));
967  break;
968  }
969  return cmp ? 0 : CMP_MATCH;
970 }
971 
972 static int user_hash_cb(const void *obj, const int flags)
973 {
974  const struct user_profile *u_profile = obj;
975  const char *name = obj;
976  int hash;
977 
978  switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
979  default:
980  case OBJ_POINTER:
981  name = u_profile->name;
982  /* Fall through */
983  case OBJ_KEY:
984  hash = ast_str_case_hash(name);
985  break;
986  case OBJ_PARTIAL_KEY:
987  /* Should never happen in hash callback. */
988  ast_assert(0);
989  hash = 0;
990  break;
991  }
992  return hash;
993 }
994 
995 /*! Bridge Profile Sounds functions */
996 static void bridge_profile_sounds_destroy_cb(void *obj)
997 {
998  struct bridge_profile_sounds *sounds = obj;
1000 }
1001 
1003 {
1005 
1006  if (!sounds) {
1007  return NULL;
1008  }
1009  if (ast_string_field_init(sounds, 512)) {
1010  ao2_ref(sounds, -1);
1011  return NULL;
1012  }
1013 
1014  return sounds;
1015 }
1016 
1017 static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
1018 {
1019  struct bridge_profile_sounds *sounds = b_profile->sounds;
1020  if (ast_strlen_zero(sound_file)) {
1021  return -1;
1022  }
1023 
1024  if (!strcasecmp(sound_name, "sound_only_person")) {
1025  ast_string_field_set(sounds, onlyperson, sound_file);
1026  } else if (!strcasecmp(sound_name, "sound_only_one")) {
1027  ast_string_field_set(sounds, onlyone, sound_file);
1028  } else if (!strcasecmp(sound_name, "sound_has_joined")) {
1029  ast_string_field_set(sounds, hasjoin, sound_file);
1030  } else if (!strcasecmp(sound_name, "sound_has_left")) {
1031  ast_string_field_set(sounds, hasleft, sound_file);
1032  } else if (!strcasecmp(sound_name, "sound_kicked")) {
1033  ast_string_field_set(sounds, kicked, sound_file);
1034  } else if (!strcasecmp(sound_name, "sound_muted")) {
1035  ast_string_field_set(sounds, muted, sound_file);
1036  } else if (!strcasecmp(sound_name, "sound_unmuted")) {
1037  ast_string_field_set(sounds, unmuted, sound_file);
1038  } else if (!strcasecmp(sound_name, "sound_binaural_on")) {
1039  ast_string_field_set(sounds, binauralon, sound_file);
1040  } else if (!strcasecmp(sound_name, "sound_binaural_off")) {
1041  ast_string_field_set(sounds, binauraloff, sound_file);
1042  } else if (!strcasecmp(sound_name, "sound_there_are")) {
1043  ast_string_field_set(sounds, thereare, sound_file);
1044  } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
1045  ast_string_field_set(sounds, otherinparty, sound_file);
1046  } else if (!strcasecmp(sound_name, "sound_place_into_conference")) {
1047  static int deprecation_warning = 1;
1048  if (deprecation_warning) {
1049  ast_log(LOG_WARNING, "sound_place_into_conference is deprecated"
1050  " and unused. Use sound_begin for similar functionality.");
1051  deprecation_warning = 0;
1052  }
1053  ast_string_field_set(sounds, placeintoconf, sound_file);
1054  } else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
1055  ast_string_field_set(sounds, waitforleader, sound_file);
1056  } else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
1057  ast_string_field_set(sounds, leaderhasleft, sound_file);
1058  } else if (!strcasecmp(sound_name, "sound_get_pin")) {
1059  ast_string_field_set(sounds, getpin, sound_file);
1060  } else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
1061  ast_string_field_set(sounds, invalidpin, sound_file);
1062  } else if (!strcasecmp(sound_name, "sound_locked")) {
1063  ast_string_field_set(sounds, locked, sound_file);
1064  } else if (!strcasecmp(sound_name, "sound_unlocked_now")) {
1065  ast_string_field_set(sounds, unlockednow, sound_file);
1066  } else if (!strcasecmp(sound_name, "sound_locked_now")) {
1067  ast_string_field_set(sounds, lockednow, sound_file);
1068  } else if (!strcasecmp(sound_name, "sound_error_menu")) {
1069  ast_string_field_set(sounds, errormenu, sound_file);
1070  } else if (!strcasecmp(sound_name, "sound_join")) {
1071  ast_string_field_set(sounds, join, sound_file);
1072  } else if (!strcasecmp(sound_name, "sound_leave")) {
1073  ast_string_field_set(sounds, leave, sound_file);
1074  } else if (!strcasecmp(sound_name, "sound_participants_muted")) {
1075  ast_string_field_set(sounds, participantsmuted, sound_file);
1076  } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) {
1077  ast_string_field_set(sounds, participantsunmuted, sound_file);
1078  } else if (!strcasecmp(sound_name, "sound_begin")) {
1079  ast_string_field_set(sounds, begin, sound_file);
1080  } else {
1081  return -1;
1082  }
1083 
1084  return 0;
1085 }
1086 
1087 /*! CONFBRIDGE dialplan function functions and channel datastore. */
1089  struct bridge_profile b_profile;
1090  struct user_profile u_profile;
1091  struct conf_menu *menu;
1092  unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
1093  unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
1094  unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
1095 };
1096 
1098 {
1100  ao2_cleanup(b_data->menu);
1101  ast_free(b_data);
1102 }
1103 
1104 static void func_confbridge_destroy_cb(void *data)
1105 {
1106  struct func_confbridge_data *b_data = data;
1108 };
1109 
1111  .type = "confbridge",
1112  .destroy = func_confbridge_destroy_cb
1113 };
1114 
1115 int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1116 {
1117  struct ast_datastore *datastore;
1118  struct func_confbridge_data *b_data;
1119  char *parse;
1120  struct ast_variable tmpvar = { 0, };
1121  struct ast_variable template = {
1122  .name = "template",
1123  .file = "CONFBRIDGE"
1124  };
1126  AST_APP_ARG(type);
1127  AST_APP_ARG(option);
1128  );
1129 
1130  if (!chan) {
1131  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1132  return -1;
1133  }
1134 
1135  /* parse all the required arguments and make sure they exist. */
1136  if (ast_strlen_zero(data)) {
1137  return -1;
1138  }
1139  parse = ast_strdupa(data);
1140  AST_STANDARD_APP_ARGS(args, parse);
1141  if (ast_strlen_zero(args.type) || ast_strlen_zero(args.option)) {
1142  return -1;
1143  }
1144 
1145  ast_channel_lock(chan);
1146  datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
1147  if (!datastore) {
1148  datastore = ast_datastore_alloc(&confbridge_datastore, NULL);
1149  if (!datastore) {
1150  ast_channel_unlock(chan);
1151  return 0;
1152  }
1153  b_data = ast_calloc(1, sizeof(*b_data));
1154  if (!b_data) {
1155  ast_channel_unlock(chan);
1156  ast_datastore_free(datastore);
1157  return 0;
1158  }
1159  datastore->data = b_data;
1161  if (!b_data->b_profile.sounds) {
1162  ast_channel_unlock(chan);
1163  ast_datastore_free(datastore);
1164  return 0;
1165  }
1166  if (!(b_data->menu = menu_alloc("dialplan"))) {
1167  ast_channel_unlock(chan);
1168  ast_datastore_free(datastore);
1169  return 0;
1170  }
1171  ast_channel_datastore_add(chan, datastore);
1172  } else {
1173  b_data = datastore->data;
1174  }
1175  ast_channel_unlock(chan);
1176 
1177  /* SET(CONFBRIDGE(type,option)=value) */
1178  if (!value) {
1179  value = "";
1180  }
1181  tmpvar.name = args.option;
1182  tmpvar.value = value;
1183  tmpvar.file = "CONFBRIDGE";
1184  if (!strcasecmp(args.type, "bridge")) {
1185  if (!strcasecmp(args.option, "clear")) {
1186  b_data->b_usable = 0;
1188  memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
1189  if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
1190  /* If this reallocation fails, the datastore has become unusable and must be destroyed. */
1191  ast_channel_lock(chan);
1192  ast_channel_datastore_remove(chan, datastore);
1193  ast_channel_unlock(chan);
1194  ast_datastore_free(datastore);
1195  }
1196  return 0;
1197  }
1198 
1199  if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
1200  template.value = DEFAULT_BRIDGE_PROFILE;
1201  aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
1202  }
1203 
1204  if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
1205  b_data->b_usable = 1;
1206  return 0;
1207  }
1208  } else if (!strcasecmp(args.type, "user")) {
1209  if (!strcasecmp(args.option, "clear")) {
1210  b_data->u_usable = 0;
1212  memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
1213  return 0;
1214  }
1215 
1216  if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
1217  template.value = DEFAULT_USER_PROFILE;
1218  aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
1219  }
1220 
1221  if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
1222  b_data->u_usable = 1;
1223  return 0;
1224  }
1225  } else if (!strcasecmp(args.type, "menu")) {
1226  if (!strcasecmp(args.option, "clear")) {
1227  b_data->m_usable = 0;
1228  ao2_cleanup(b_data->menu);
1229  if (!(b_data->menu = menu_alloc("dialplan"))) {
1230  /* If this reallocation fails, the datastore has become unusable and must be destroyed */
1231  ast_channel_lock(chan);
1232  ast_channel_datastore_remove(chan, datastore);
1233  ast_channel_unlock(chan);
1234  ast_datastore_free(datastore);
1235  }
1236  return 0;
1237  }
1238 
1239  if (b_data && !b_data->m_usable && strcasecmp(args.option, "template")) {
1240  template.value = DEFAULT_MENU_PROFILE;
1241  aco_process_var(&menu_type, "dialplan", &template, &b_data->menu);
1242  }
1243 
1244  if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
1245  b_data->m_usable = 1;
1246  return 0;
1247  }
1248  }
1249 
1250  ast_log(LOG_WARNING, "%s(%s,%s) cannot be set to '%s'. Invalid type, option, or value.\n",
1251  cmd, args.type, args.option, value);
1252  return -1;
1253 }
1254 
1255 static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
1256 {
1257  struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
1258 
1259  if (!menu_action) {
1260  return -1;
1261  }
1262  menu_action->id = id;
1263 
1264  switch (id) {
1265  case MENU_ACTION_NOOP:
1278  case MENU_ACTION_LEAVE:
1281  break;
1282  case MENU_ACTION_PLAYBACK:
1284  if (!(ast_strlen_zero(databuf))) {
1285  ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
1286  } else {
1287  ast_free(menu_action);
1288  return -1;
1289  }
1290  break;
1292  if (!(ast_strlen_zero(databuf))) {
1295  AST_APP_ARG(exten);
1297  );
1298  AST_STANDARD_APP_ARGS(args, databuf);
1299  if (!ast_strlen_zero(args.context)) {
1300  ast_copy_string(menu_action->data.dialplan_args.context,
1301  args.context,
1302  sizeof(menu_action->data.dialplan_args.context));
1303  }
1304  if (!ast_strlen_zero(args.exten)) {
1305  ast_copy_string(menu_action->data.dialplan_args.exten,
1306  args.exten,
1307  sizeof(menu_action->data.dialplan_args.exten));
1308  }
1309  menu_action->data.dialplan_args.priority = 1; /* 1 by default */
1310  if (!ast_strlen_zero(args.priority) &&
1311  (sscanf(args.priority, "%30d", &menu_action->data.dialplan_args.priority) != 1)) {
1312  /* invalid priority */
1313  ast_free(menu_action);
1314  return -1;
1315  }
1316  } else {
1317  ast_free(menu_action);
1318  return -1;
1319  }
1320  };
1321 
1322  AST_LIST_INSERT_TAIL(&menu_entry->actions, menu_action, action);
1323 
1324  return 0;
1325 }
1326 
1327 static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
1328 {
1329  struct conf_menu_entry *menu_entry = NULL, *cur = NULL;
1330  int res = 0;
1331  char *tmp_action_names = ast_strdupa(action_names);
1332  char *action = NULL;
1333  char *action_args;
1334  char *tmp;
1335  char buf[PATH_MAX];
1336  char *delimiter = ",";
1337 
1338  if (!(menu_entry = ast_calloc(1, sizeof(*menu_entry)))) {
1339  return -1;
1340  }
1341 
1342  for (;;) {
1343  char *comma;
1344  char *startbrace;
1345  char *endbrace;
1346  unsigned int action_len;
1347 
1348  if (ast_strlen_zero(tmp_action_names)) {
1349  break;
1350  }
1351  startbrace = strchr(tmp_action_names, '(');
1352  endbrace = strchr(tmp_action_names, ')');
1353  comma = strchr(tmp_action_names, ',');
1354 
1355  /* If the next action has brackets with comma delimited arguments in it,
1356  * make the delimeter ')' instead of a comma to preserve the argments */
1357  if (startbrace && endbrace && comma && (comma > startbrace && comma < endbrace)) {
1358  delimiter = ")";
1359  } else {
1360  delimiter = ",";
1361  }
1362 
1363  if (!(action = strsep(&tmp_action_names, delimiter))) {
1364  break;
1365  }
1366 
1367  action = ast_strip(action);
1368  if (ast_strlen_zero(action)) {
1369  continue;
1370  }
1371 
1372  action_len = strlen(action);
1373  ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
1374  if (!strcasecmp(action, "toggle_mute")) {
1376  } else if (!strcasecmp(action, "toggle_binaural")) {
1378  } else if (!strcasecmp(action, "no_op")) {
1379  res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL);
1380  } else if (!strcasecmp(action, "increase_listening_volume")) {
1382  } else if (!strcasecmp(action, "decrease_listening_volume")) {
1384  } else if (!strcasecmp(action, "increase_talking_volume")) {
1386  } else if (!strcasecmp(action, "reset_listening_volume")) {
1388  } else if (!strcasecmp(action, "reset_talking_volume")) {
1390  } else if (!strcasecmp(action, "decrease_talking_volume")) {
1392  } else if (!strcasecmp(action, "admin_toggle_conference_lock")) {
1394  } else if (!strcasecmp(action, "admin_toggle_mute_participants")) {
1396  } else if (!strcasecmp(action, "participant_count")) {
1398  } else if (!strcasecmp(action, "admin_kick_last")) {
1400  } else if (!strcasecmp(action, "leave_conference")) {
1401  res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL);
1402  } else if (!strcasecmp(action, "set_as_single_video_src")) {
1404  } else if (!strcasecmp(action, "release_as_single_video_src")) {
1406  } else if (!strncasecmp(action, "dialplan_exec(", 14)) {
1407  ast_copy_string(buf, action, sizeof(buf));
1408  action_args = buf;
1409  if ((action_args = strchr(action, '('))) {
1410  action_args++;
1411  }
1412  /* it is possible that this argument may or may not
1413  * have a closing brace at this point, it all depends on if
1414  * comma delimited arguments were provided */
1415  if ((tmp = strchr(action, ')'))) {
1416  *tmp = '\0';
1417  }
1418  res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DIALPLAN_EXEC, action_args);
1419  } else if (action_len >= 21 && !strncasecmp(action, "playback_and_continue(", 22)) {
1420  ast_copy_string(buf, action, sizeof(buf));
1421  action_args = buf;
1422  if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1423  *tmp = '\0';
1424  action_args++;
1425  }
1426  res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK_AND_CONTINUE, action_args);
1427  } else if (action_len >= 8 && !strncasecmp(action, "playback(", 9)) {
1428  ast_copy_string(buf, action, sizeof(buf));
1429  action_args = buf;
1430  if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1431  *tmp = '\0';
1432  action_args++;
1433  }
1434  res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, action_args);
1435  }
1436  }
1437 
1438  /* if adding any of the actions failed, bail */
1439  if (res) {
1440  struct conf_menu_action *menu_action;
1441  while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
1442  ast_free(menu_action);
1443  }
1444  ast_free(menu_entry);
1445  return -1;
1446  }
1447 
1448  /* remove any list entry with an identical DTMF sequence for overrides */
1450  if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
1452  ast_free(cur);
1453  break;
1454  }
1455  }
1457 
1458  AST_LIST_INSERT_TAIL(&menu->entries, menu_entry, entry);
1459 
1460  return 0;
1461 }
1462 
1463 static char *complete_user_profile_name(const char *line, const char *word, int pos, int state)
1464 {
1465  int which = 0;
1466  char *res = NULL;
1467  int wordlen = strlen(word);
1468  struct ao2_iterator i;
1469  struct user_profile *u_profile = NULL;
1471 
1472  if (!cfg) {
1473  return NULL;
1474  }
1475 
1476  i = ao2_iterator_init(cfg->user_profiles, 0);
1477  while ((u_profile = ao2_iterator_next(&i))) {
1478  if (!strncasecmp(u_profile->name, word, wordlen) && ++which > state) {
1479  res = ast_strdup(u_profile->name);
1480  ao2_ref(u_profile, -1);
1481  break;
1482  }
1483  ao2_ref(u_profile, -1);
1484  }
1486 
1487  return res;
1488 }
1489 
1491 {
1492  struct ao2_iterator it;
1493  struct user_profile *u_profile;
1494  RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1495 
1496  switch (cmd) {
1497  case CLI_INIT:
1498  e->command = "confbridge show profile users";
1499  e->usage =
1500  "Usage: confbridge show profile users\n";
1501  return NULL;
1502  case CLI_GENERATE:
1503  return NULL;
1504  }
1505 
1506  if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1507  return NULL;
1508  }
1509 
1510  ast_cli(a->fd,"--------- User Profiles -----------\n");
1511  ao2_lock(cfg->user_profiles);
1512  it = ao2_iterator_init(cfg->user_profiles, 0);
1513  while ((u_profile = ao2_iterator_next(&it))) {
1514  ast_cli(a->fd,"%s\n", u_profile->name);
1515  ao2_ref(u_profile, -1);
1516  }
1517  ao2_iterator_destroy(&it);
1518  ao2_unlock(cfg->user_profiles);
1519 
1520  return CLI_SUCCESS;
1521 }
1522 static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1523 {
1524  struct user_profile u_profile;
1525 
1526  switch (cmd) {
1527  case CLI_INIT:
1528  e->command = "confbridge show profile user";
1529  e->usage =
1530  "Usage: confbridge show profile user [<profile name>]\n";
1531  return NULL;
1532  case CLI_GENERATE:
1533  if (a->pos == 4) {
1534  return complete_user_profile_name(a->line, a->word, a->pos, a->n);
1535  }
1536  return NULL;
1537  }
1538 
1539  if (a->argc != 5) {
1540  return CLI_SHOWUSAGE;
1541  }
1542 
1543  if (!(conf_find_user_profile(NULL, a->argv[4], &u_profile))) {
1544  ast_cli(a->fd, "No conference user profile named '%s' found!\n", a->argv[4]);
1545  return CLI_SUCCESS;
1546  }
1547 
1548  ast_cli(a->fd,"--------------------------------------------\n");
1549  ast_cli(a->fd,"Name: %s\n",
1550  u_profile.name);
1551  ast_cli(a->fd,"Admin: %s\n",
1552  u_profile.flags & USER_OPT_ADMIN ?
1553  "true" : "false");
1554  ast_cli(a->fd,"Send Events: %s\n",
1555  u_profile.flags & USER_OPT_SEND_EVENTS ?
1556  "true" : "false");
1557  ast_cli(a->fd,"Echo Events: %s\n",
1558  u_profile.flags & USER_OPT_ECHO_EVENTS ?
1559  "true" : "false");
1560  ast_cli(a->fd,"Marked User: %s\n",
1561  u_profile.flags & USER_OPT_MARKEDUSER ?
1562  "true" : "false");
1563  ast_cli(a->fd,"Start Muted: %s\n",
1564  u_profile.flags & USER_OPT_STARTMUTED?
1565  "true" : "false");
1566  ast_cli(a->fd,"MOH When Empty: %s\n",
1567  u_profile.flags & USER_OPT_MUSICONHOLD ?
1568  "enabled" : "disabled");
1569  ast_cli(a->fd,"MOH Class: %s\n",
1570  ast_strlen_zero(u_profile.moh_class) ?
1571  "default" : u_profile.moh_class);
1572  ast_cli(a->fd,"Announcement: %s\n",
1573  u_profile.announcement);
1574  ast_cli(a->fd,"Quiet: %s\n",
1575  u_profile.flags & USER_OPT_QUIET ?
1576  "enabled" : "disabled");
1577  ast_cli(a->fd,"Wait Marked: %s\n",
1578  u_profile.flags & USER_OPT_WAITMARKED ?
1579  "enabled" : "disabled");
1580  ast_cli(a->fd,"END Marked: %s\n",
1581  u_profile.flags & USER_OPT_ENDMARKED ?
1582  "enabled" : "disabled");
1583  ast_cli(a->fd,"Drop_silence: %s\n",
1584  u_profile.flags & USER_OPT_DROP_SILENCE ?
1585  "enabled" : "disabled");
1586  ast_cli(a->fd,"Silence Threshold: %ums\n",
1587  u_profile.silence_threshold);
1588  ast_cli(a->fd,"Talking Threshold: %u\n",
1589  u_profile.talking_threshold);
1590  ast_cli(a->fd,"Denoise: %s\n",
1591  u_profile.flags & USER_OPT_DENOISE ?
1592  "enabled" : "disabled");
1593  ast_cli(a->fd,"Jitterbuffer: %s\n",
1594  u_profile.flags & USER_OPT_JITTERBUFFER ?
1595  "enabled" : "disabled");
1596  ast_cli(a->fd,"Talk Detect Events: %s\n",
1597  u_profile.flags & USER_OPT_TALKER_DETECT ?
1598  "enabled" : "disabled");
1599  ast_cli(a->fd,"DTMF Pass Through: %s\n",
1600  u_profile.flags & USER_OPT_DTMF_PASS ?
1601  "enabled" : "disabled");
1602  ast_cli(a->fd,"PIN: %s\n",
1603  ast_strlen_zero(u_profile.pin) ?
1604  "None" : u_profile.pin);
1605  ast_cli(a->fd,"Announce User Count: %s\n",
1606  u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
1607  "enabled" : "disabled");
1608  ast_cli(a->fd,"Announce join/leave: %s\n",
1611  "enabled (with review)" : "enabled" : "disabled");
1612  ast_cli(a->fd,"Announce User Count all: %s\n",
1613  u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNTALL ?
1614  "enabled" : "disabled");
1615  ast_cli(a->fd,"Text Messaging: %s\n",
1616  u_profile.flags & USER_OPT_TEXT_MESSAGING ?
1617  "enabled" : "disabled");
1618  ast_cli(a->fd,"Answer Channel: %s\n",
1619  u_profile.flags & USER_OPT_ANSWER_CHANNEL ?
1620  "true" : "false");
1621  ast_cli(a->fd, "\n");
1622 
1623  return CLI_SUCCESS;
1624 }
1625 
1626 static char *complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
1627 {
1628  int which = 0;
1629  char *res = NULL;
1630  int wordlen = strlen(word);
1631  struct ao2_iterator i;
1632  struct bridge_profile *b_profile = NULL;
1634 
1635  if (!cfg) {
1636  return NULL;
1637  }
1638 
1639  i = ao2_iterator_init(cfg->bridge_profiles, 0);
1640  while ((b_profile = ao2_iterator_next(&i))) {
1641  if (!strncasecmp(b_profile->name, word, wordlen) && ++which > state) {
1642  res = ast_strdup(b_profile->name);
1643  ao2_ref(b_profile, -1);
1644  break;
1645  }
1646  ao2_ref(b_profile, -1);
1647  }
1649 
1650  return res;
1651 }
1652 
1654 {
1655  struct ao2_iterator it;
1656  struct bridge_profile *b_profile;
1657  RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1658 
1659  switch (cmd) {
1660  case CLI_INIT:
1661  e->command = "confbridge show profile bridges";
1662  e->usage =
1663  "Usage: confbridge show profile bridges\n";
1664  return NULL;
1665  case CLI_GENERATE:
1666  return NULL;
1667  }
1668 
1669  if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1670  return NULL;
1671  }
1672 
1673  ast_cli(a->fd,"--------- Bridge Profiles -----------\n");
1674  ao2_lock(cfg->bridge_profiles);
1675  it = ao2_iterator_init(cfg->bridge_profiles, 0);
1676  while ((b_profile = ao2_iterator_next(&it))) {
1677  ast_cli(a->fd,"%s\n", b_profile->name);
1678  ao2_ref(b_profile, -1);
1679  }
1680  ao2_iterator_destroy(&it);
1681  ao2_unlock(cfg->bridge_profiles);
1682 
1683  return CLI_SUCCESS;
1684 }
1685 
1687 {
1688  struct bridge_profile b_profile;
1689  char tmp[64];
1690 
1691  switch (cmd) {
1692  case CLI_INIT:
1693  e->command = "confbridge show profile bridge";
1694  e->usage =
1695  "Usage: confbridge show profile bridge <profile name>\n";
1696  return NULL;
1697  case CLI_GENERATE:
1698  if (a->pos == 4) {
1699  return complete_bridge_profile_name(a->line, a->word, a->pos, a->n);
1700  }
1701  return NULL;
1702  }
1703 
1704  if (a->argc != 5) {
1705  return CLI_SHOWUSAGE;
1706  }
1707 
1708  if (!(conf_find_bridge_profile(NULL, a->argv[4], &b_profile))) {
1709  ast_cli(a->fd, "No conference bridge profile named '%s' found!\n", a->argv[4]);
1710  return CLI_SUCCESS;
1711  }
1712 
1713  ast_cli(a->fd,"--------------------------------------------\n");
1714  ast_cli(a->fd,"Name: %s\n", b_profile.name);
1715  ast_cli(a->fd,"Language: %s\n", b_profile.language);
1716 
1717  if (b_profile.internal_sample_rate) {
1718  snprintf(tmp, sizeof(tmp), "%u", b_profile.internal_sample_rate);
1719  } else {
1720  ast_copy_string(tmp, "auto", sizeof(tmp));
1721  }
1722  ast_cli(a->fd,"Internal Sample Rate: %s\n", tmp);
1723 
1724  if (b_profile.maximum_sample_rate) {
1725  snprintf(tmp, sizeof(tmp), "%u", b_profile.maximum_sample_rate);
1726  } else {
1727  ast_copy_string(tmp, "none", sizeof(tmp));
1728  }
1729  ast_cli(a->fd,"Maximum Sample Rate: %s\n", tmp);
1730 
1731  if (b_profile.mix_interval) {
1732  ast_cli(a->fd,"Mixing Interval: %u\n", b_profile.mix_interval);
1733  } else {
1734  ast_cli(a->fd,"Mixing Interval: Default 20ms\n");
1735  }
1736 
1737  ast_cli(a->fd,"Record Conference: %s\n",
1738  b_profile.flags & BRIDGE_OPT_RECORD_CONFERENCE ?
1739  "yes" : "no");
1740 
1741  ast_cli(a->fd,"Record File Append: %s\n",
1742  b_profile.flags & BRIDGE_OPT_RECORD_FILE_APPEND ?
1743  "yes" : "no");
1744 
1745  ast_cli(a->fd,"Record File Timestamp: %s\n",
1747  "yes" : "no");
1748 
1749  ast_cli(a->fd,"Record File: %s\n",
1750  ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
1751  b_profile.rec_file);
1752 
1753  ast_cli(a->fd,"Record Options: %s\n",
1754  b_profile.rec_options);
1755 
1756  ast_cli(a->fd,"Record Command: %s\n",
1757  b_profile.rec_command);
1758 
1759  if (b_profile.max_members) {
1760  ast_cli(a->fd,"Max Members: %u\n", b_profile.max_members);
1761  } else {
1762  ast_cli(a->fd,"Max Members: No Limit\n");
1763  }
1764 
1765  ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext);
1766 
1767  switch (b_profile.flags
1773  ast_cli(a->fd, "Video Mode: last_marked\n");
1774  break;
1776  ast_cli(a->fd, "Video Mode: first_marked\n");
1777  break;
1779  ast_cli(a->fd, "Video Mode: follow_talker\n");
1780  break;
1782  ast_cli(a->fd, "Video Mode: sfu\n");
1783  break;
1784  case 0:
1785  ast_cli(a->fd, "Video Mode: no video\n");
1786  break;
1787  default:
1788  /* Opps. We have more than one video mode flag set. */
1789  ast_assert(0);
1790  break;
1791  }
1792 
1793  ast_cli(a->fd,"Video Update Discard: %u\n", b_profile.video_update_discard);
1794  ast_cli(a->fd,"REMB Send Interval: %u\n", b_profile.remb_send_interval);
1795 
1796  switch (b_profile.flags
1801  ast_cli(a->fd, "REMB Behavior: average\n");
1802  break;
1804  ast_cli(a->fd, "REMB Behavior: lowest\n");
1805  break;
1807  ast_cli(a->fd, "REMB Behavior: highest\n");
1808  break;
1810  ast_cli(a->fd, "REMB Behavior: average_all\n");
1811  break;
1813  ast_cli(a->fd, "REMB Behavior: lowest_all\n");
1814  break;
1816  ast_cli(a->fd, "REMB Behavior: highest_all\n");
1817  break;
1818  default:
1819  ast_assert(0);
1820  break;
1821  }
1822 
1823  ast_cli(a->fd,"Enable Events: %s\n",
1824  b_profile.flags & BRIDGE_OPT_ENABLE_EVENTS ?
1825  "yes" : "no");
1826 
1827  ast_cli(a->fd,"sound_only_person: %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds));
1828  ast_cli(a->fd,"sound_only_one: %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds));
1829  ast_cli(a->fd,"sound_has_joined: %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds));
1830  ast_cli(a->fd,"sound_has_left: %s\n", conf_get_sound(CONF_SOUND_HAS_LEFT, b_profile.sounds));
1831  ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
1832  ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
1833  ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
1834  ast_cli(a->fd,"sound_binaural_on: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_ON, b_profile.sounds));
1835  ast_cli(a->fd,"sound_binaural_off: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_OFF, b_profile.sounds));
1836  ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
1837  ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
1838  ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
1839  ast_cli(a->fd,"sound_wait_for_leader: %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
1840  ast_cli(a->fd,"sound_leader_has_left: %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
1841  ast_cli(a->fd,"sound_get_pin: %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
1842  ast_cli(a->fd,"sound_invalid_pin: %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
1843  ast_cli(a->fd,"sound_locked: %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));
1844  ast_cli(a->fd,"sound_unlocked_now: %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds));
1845  ast_cli(a->fd,"sound_lockednow: %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds));
1846  ast_cli(a->fd,"sound_error_menu: %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds));
1847  ast_cli(a->fd,"sound_join: %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds));
1848  ast_cli(a->fd,"sound_leave: %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds));
1849  ast_cli(a->fd,"sound_participants_muted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds));
1850  ast_cli(a->fd,"sound_participants_unmuted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds));
1851  ast_cli(a->fd,"sound_begin: %s\n", conf_get_sound(CONF_SOUND_BEGIN, b_profile.sounds));
1852  ast_cli(a->fd,"\n");
1853 
1854  conf_bridge_profile_destroy(&b_profile);
1855  return CLI_SUCCESS;
1856 }
1857 
1858 static char *complete_menu_name(const char *line, const char *word, int pos, int state)
1859 {
1860  int which = 0;
1861  char *res = NULL;
1862  int wordlen = strlen(word);
1863  struct ao2_iterator i;
1864  struct conf_menu *menu = NULL;
1866 
1867  if (!cfg) {
1868  return NULL;
1869  }
1870 
1871  i = ao2_iterator_init(cfg->menus, 0);
1872  while ((menu = ao2_iterator_next(&i))) {
1873  if (!strncasecmp(menu->name, word, wordlen) && ++which > state) {
1874  res = ast_strdup(menu->name);
1875  ao2_ref(menu, -1);
1876  break;
1877  }
1878  ao2_ref(menu, -1);
1879  }
1881 
1882  return res;
1883 }
1884 
1885 static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1886 {
1887  struct ao2_iterator it;
1888  struct conf_menu *menu;
1889  RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1890 
1891  switch (cmd) {
1892  case CLI_INIT:
1893  e->command = "confbridge show menus";
1894  e->usage =
1895  "Usage: confbridge show profile menus\n";
1896  return NULL;
1897  case CLI_GENERATE:
1898  return NULL;
1899  }
1900 
1901  if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1902  return NULL;
1903  }
1904 
1905  ast_cli(a->fd,"--------- Menus -----------\n");
1906  ao2_lock(cfg->menus);
1907  it = ao2_iterator_init(cfg->menus, 0);
1908  while ((menu = ao2_iterator_next(&it))) {
1909  ast_cli(a->fd,"%s\n", menu->name);
1910  ao2_ref(menu, -1);
1911  }
1912  ao2_iterator_destroy(&it);
1913  ao2_unlock(cfg->menus);
1914 
1915  return CLI_SUCCESS;
1916 }
1917 
1918 static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1919 {
1920  RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
1921  RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1922  struct conf_menu_entry *menu_entry = NULL;
1923  struct conf_menu_action *menu_action = NULL;
1924 
1925  switch (cmd) {
1926  case CLI_INIT:
1927  e->command = "confbridge show menu";
1928  e->usage =
1929  "Usage: confbridge show menu [<menu name>]\n";
1930  return NULL;
1931  case CLI_GENERATE:
1932  if (a->pos == 3) {
1933  return complete_menu_name(a->line, a->word, a->pos, a->n);
1934  }
1935  return NULL;
1936  }
1937 
1938  if (a->argc != 4) {
1939  return CLI_SHOWUSAGE;
1940  }
1941 
1942  if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1943  return NULL;
1944  }
1945 
1946  if (!(menu = menu_find(cfg->menus, a->argv[3]))) {
1947  ast_cli(a->fd, "No conference menu named '%s' found!\n", a->argv[3]);
1948  return CLI_SUCCESS;
1949  }
1950  ao2_lock(menu);
1951 
1952  ast_cli(a->fd,"Name: %s\n", menu->name);
1953  AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
1954  int action_num = 0;
1955  ast_cli(a->fd, "%s=", menu_entry->dtmf);
1956  AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
1957  if (action_num) {
1958  ast_cli(a->fd, ", ");
1959  }
1960  switch (menu_action->id) {
1962  ast_cli(a->fd, "toggle_mute");
1963  break;
1965  ast_cli(a->fd, "toggle_binaural");
1966  break;
1967  case MENU_ACTION_NOOP:
1968  ast_cli(a->fd, "no_op");
1969  break;
1971  ast_cli(a->fd, "increase_listening_volume");
1972  break;
1974  ast_cli(a->fd, "decrease_listening_volume");
1975  break;
1977  ast_cli(a->fd, "reset_listening_volume");
1978  break;
1980  ast_cli(a->fd, "reset_talking_volume");
1981  break;
1983  ast_cli(a->fd, "increase_talking_volume");
1984  break;
1986  ast_cli(a->fd, "decrease_talking_volume");
1987  break;
1988  case MENU_ACTION_PLAYBACK:
1989  ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
1990  break;
1992  ast_cli(a->fd, "playback_and_continue(%s)", menu_action->data.playback_file);
1993  break;
1995  ast_cli(a->fd, "dialplan_exec(%s,%s,%d)",
1996  menu_action->data.dialplan_args.context,
1997  menu_action->data.dialplan_args.exten,
1998  menu_action->data.dialplan_args.priority);
1999  break;
2001  ast_cli(a->fd, "admin_toggle_conference_lock");
2002  break;
2004  ast_cli(a->fd, "admin_toggle_mute_participants");
2005  break;
2007  ast_cli(a->fd, "participant_count");
2008  break;
2010  ast_cli(a->fd, "admin_kick_last");
2011  break;
2012  case MENU_ACTION_LEAVE:
2013  ast_cli(a->fd, "leave_conference");
2014  break;
2016  ast_cli(a->fd, "set_as_single_video_src");
2017  break;
2019  ast_cli(a->fd, "release_as_single_video_src");
2020  break;
2021  }
2022  action_num++;
2023  }
2024  ast_cli(a->fd,"\n");
2025  }
2026 
2027 
2028  ao2_unlock(menu);
2029  return CLI_SUCCESS;
2030 }
2031 
2033  AST_CLI_DEFINE(handle_cli_confbridge_show_user_profile, "Show a conference user profile."),
2034  AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profile, "Show a conference bridge profile."),
2035  AST_CLI_DEFINE(handle_cli_confbridge_show_menu, "Show a conference menu"),
2036  AST_CLI_DEFINE(handle_cli_confbridge_show_user_profiles, "Show a list of conference user profiles."),
2037  AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profiles, "Show a list of conference bridge profiles."),
2038  AST_CLI_DEFINE(handle_cli_confbridge_show_menus, "Show a list of conference menus"),
2039 
2040 };
2041 
2042 static void confbridge_cfg_destructor(void *obj)
2043 {
2044  struct confbridge_cfg *cfg = obj;
2045  ao2_cleanup(cfg->user_profiles);
2047  ao2_cleanup(cfg->menus);
2048 }
2049 
2051 {
2052  struct confbridge_cfg *cfg;
2053 
2054  if (!(cfg = ao2_alloc(sizeof(*cfg), confbridge_cfg_destructor))) {
2055  return NULL;
2056  }
2057 
2060  if (!cfg->user_profiles) {
2061  goto error;
2062  }
2063 
2066  if (!cfg->bridge_profiles) {
2067  goto error;
2068  }
2069 
2072  if (!cfg->menus) {
2073  goto error;
2074  }
2075 
2076  return cfg;
2077 error:
2078  ao2_ref(cfg, -1);
2079  return NULL;
2080 }
2081 
2082 static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2083 {
2084  struct user_profile *u_profile = obj;
2085 
2086  if (strcasecmp(var->name, "announce_user_count_all")) {
2087  return -1;
2088  }
2089  if (ast_true(var->value)) {
2090  u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2091  } else if (ast_false(var->value)) {
2092  u_profile->flags = u_profile->flags & ~USER_OPT_ANNOUNCEUSERCOUNTALL;
2093  } else if (sscanf(var->value, "%30u", &u_profile->announce_user_count_all_after) == 1) {
2094  u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2095  } else {
2096  return -1;
2097  }
2098  return 0;
2099 }
2100 
2101 static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2102 {
2103  struct bridge_profile *b_profile = obj;
2104 
2105  if (strcasecmp(var->name, "mixing_interval")) {
2106  return -1;
2107  }
2108  if (sscanf(var->value, "%30u", &b_profile->mix_interval) != 1) {
2109  return -1;
2110  }
2111  switch (b_profile->mix_interval) {
2112  case 10:
2113  case 20:
2114  case 40:
2115  case 80:
2116  return 0;
2117  default:
2118  return -1;
2119  }
2120 }
2121 
2122 static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2123 {
2124  struct bridge_profile *b_profile = obj;
2125 
2126  if (strcasecmp(var->name, "video_mode")) {
2127  return -1;
2128  }
2129  if (!strcasecmp(var->value, "first_marked")) {
2130  ast_set_flags_to(b_profile,
2136  } else if (!strcasecmp(var->value, "last_marked")) {
2137  ast_set_flags_to(b_profile,
2143  } else if (!strcasecmp(var->value, "follow_talker")) {
2144  ast_set_flags_to(b_profile,
2150  } else if (!strcasecmp(var->value, "sfu")) {
2151  ast_set_flags_to(b_profile,
2157  } else if (!strcasecmp(var->value, "none")) {
2158  ast_clear_flag(b_profile,
2163  } else {
2164  return -1;
2165  }
2166  return 0;
2167 }
2168 
2169 static int remb_behavior_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2170 {
2171  struct bridge_profile *b_profile = obj;
2172 
2173  if (strcasecmp(var->name, "remb_behavior")) {
2174  return -1;
2175  }
2176 
2184  );
2185 
2186  if (!strcasecmp(var->value, "average")) {
2188  } else if (!strcasecmp(var->value, "lowest")) {
2190  } else if (!strcasecmp(var->value, "highest")) {
2192  } else if (!strcasecmp(var->value, "average_all")) {
2194  } else if (!strcasecmp(var->value, "lowest_all")) {
2196  } else if (!strcasecmp(var->value, "highest_all")) {
2198  } else if (!strcasecmp(var->value, "force")) {
2200  } else {
2201  return -1;
2202  }
2203  return 0;
2204 }
2205 
2206 static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2207 {
2208  struct user_profile *u_profile = obj;
2209 
2210  return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
2211 }
2212 
2213 static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2214 {
2215  struct bridge_profile *b_profile = obj;
2217  struct bridge_profile_sounds *oldsounds = b_profile->sounds;
2218 
2219  if (!sounds) {
2220  return -1;
2221  }
2222  if (!(conf_find_bridge_profile(NULL, var->value, b_profile))) {
2223  ao2_ref(sounds, -1);
2224  return -1;
2225  }
2226  /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds
2227  * structure of a dynamic profile will need to be altered, a completely new sounds structure must be
2228  * created instead of simply holding a reference to the one built by the config file. */
2229  ast_string_field_set(sounds, onlyperson, b_profile->sounds->onlyperson);
2230  ast_string_field_set(sounds, onlyone, b_profile->sounds->onlyone);
2231  ast_string_field_set(sounds, hasjoin, b_profile->sounds->hasjoin);
2232  ast_string_field_set(sounds, hasleft, b_profile->sounds->hasleft);
2233  ast_string_field_set(sounds, kicked, b_profile->sounds->kicked);
2234  ast_string_field_set(sounds, muted, b_profile->sounds->muted);
2235  ast_string_field_set(sounds, unmuted, b_profile->sounds->unmuted);
2236  ast_string_field_set(sounds, thereare, b_profile->sounds->thereare);
2237  ast_string_field_set(sounds, otherinparty, b_profile->sounds->otherinparty);
2238  ast_string_field_set(sounds, placeintoconf, b_profile->sounds->placeintoconf);
2239  ast_string_field_set(sounds, waitforleader, b_profile->sounds->waitforleader);
2240  ast_string_field_set(sounds, leaderhasleft, b_profile->sounds->leaderhasleft);
2241  ast_string_field_set(sounds, getpin, b_profile->sounds->getpin);
2242  ast_string_field_set(sounds, invalidpin, b_profile->sounds->invalidpin);
2243  ast_string_field_set(sounds, locked, b_profile->sounds->locked);
2244  ast_string_field_set(sounds, unlockednow, b_profile->sounds->unlockednow);
2245  ast_string_field_set(sounds, lockednow, b_profile->sounds->lockednow);
2246  ast_string_field_set(sounds, errormenu, b_profile->sounds->errormenu);
2247  ast_string_field_set(sounds, join, b_profile->sounds->join);
2248  ast_string_field_set(sounds, leave, b_profile->sounds->leave);
2249  ast_string_field_set(sounds, participantsmuted, b_profile->sounds->participantsmuted);
2250  ast_string_field_set(sounds, participantsunmuted, b_profile->sounds->participantsunmuted);
2251  ast_string_field_set(sounds, begin, b_profile->sounds->begin);
2252 
2253  ao2_ref(b_profile->sounds, -1); /* sounds struct copied over to it from the template by reference only. */
2254  ao2_ref(oldsounds, -1); /* original sounds struct we don't need anymore */
2255  b_profile->sounds = sounds; /* the new sounds struct that is a deep copy of the one from the template. */
2256 
2257  return 0;
2258 }
2259 
2260 static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
2261 {
2262  struct conf_menu_action *menu_action;
2263  struct conf_menu_action *new_menu_action;
2264 
2265  ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
2267 
2268  AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
2269  if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
2270  return -1;
2271  }
2272  memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
2273  AST_LIST_NEXT(new_menu_action, action) = NULL;
2274  AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
2275  }
2276 
2277  return 0;
2278 }
2279 
2280 static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
2281 {
2282  /* Copy each menu item to the dst struct */
2283  struct conf_menu_entry *cur;
2284 
2285  AST_LIST_TRAVERSE(&src->entries, cur, entry) {
2286  struct conf_menu_entry *cpy;
2287 
2288  if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
2289  return -1;
2290  }
2291 
2292  if (copy_menu_entry(cpy, cur)) {
2294  ast_free(cpy);
2295  return -1;
2296  }
2297  AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
2298  }
2299 
2300  return 0;
2301 }
2302 
2303 static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2304 {
2305  struct conf_menu *dst_menu = obj;
2307  RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
2308 
2309  if (!cfg) {
2310  return 0;
2311  }
2312 
2313  if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
2314  return -1;
2315  }
2316 
2317  if (conf_menu_profile_copy(dst_menu, src_menu)) {
2318  return -1;
2319  }
2320 
2321  return 0;
2322 }
2323 
2324 static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2325 {
2326  set_sound(var->name, var->value, obj);
2327  return 0;
2328 }
2329 
2330 static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2331 {
2332  add_menu_entry(obj, var->name, var->value);
2333  return 0;
2334 }
2335 
2336 static int verify_default_profiles(void)
2337 {
2340  RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
2341  /* We can only be called as a result of an aco_process_config so this is safe */
2342  struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
2343 
2344  if (!cfg) {
2345  return 0;
2346  }
2347 
2349  if (!bridge_profile) {
2351  if (!bridge_profile) {
2352  return -1;
2353  }
2354  ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_BRIDGE_PROFILE);
2357  }
2358 
2360  if (!user_profile) {
2362  if (!user_profile) {
2363  return -1;
2364  }
2365  ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_USER_PROFILE);
2368  }
2369 
2370  menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
2371  if (!menu_profile) {
2372  menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
2373  if (!menu_profile) {
2374  return -1;
2375  }
2376  ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
2377  aco_set_defaults(&menu_type, DEFAULT_MENU_PROFILE, menu_profile);
2378  ao2_link(cfg->menus, menu_profile);
2379  }
2380 
2381  return 0;
2382 }
2383 
2385 {
2386  if (aco_info_init(&cfg_info)) {
2387  return -1;
2388  }
2389 
2390  /* User options */
2391  aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
2392  aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
2393  aco_option_register(&cfg_info, "send_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_SEND_EVENTS);
2394  aco_option_register(&cfg_info, "echo_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ECHO_EVENTS);
2395  aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
2396  aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
2397  aco_option_register(&cfg_info, "music_on_hold_when_empty", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MUSICONHOLD);
2398  aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
2399  aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
2400  aco_option_register(&cfg_info, "announce_user_count", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCEUSERCOUNT);
2401  /* Negative logic. Defaults to "yes" and evaluates with ast_false(). If !ast_false(), USER_OPT_NOONLYPERSON is cleared */
2402  aco_option_register(&cfg_info, "announce_only_user", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 0, FLDSET(struct user_profile, flags), USER_OPT_NOONLYPERSON);
2403  aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
2404  aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
2405  aco_option_register(&cfg_info, "talk_detection_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TALKER_DETECT);
2406  aco_option_register(&cfg_info, "dtmf_passthrough", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DTMF_PASS);
2407  aco_option_register(&cfg_info, "announce_join_leave", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE);
2408  aco_option_register(&cfg_info, "announce_join_leave_review", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW);
2409  aco_option_register(&cfg_info, "pin", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, pin));
2410  aco_option_register(&cfg_info, "music_on_hold_class", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, moh_class));
2411  aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
2412  aco_option_register(&cfg_info, "denoise", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DENOISE);
2413  aco_option_register(&cfg_info, "dsp_drop_silence", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DROP_SILENCE);
2414  aco_option_register(&cfg_info, "dsp_silence_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_SILENCE_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, silence_threshold));
2415  aco_option_register(&cfg_info, "dsp_talking_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_TALKING_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, talking_threshold));
2416  aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER);
2417  aco_option_register(&cfg_info, "timeout", ACO_EXACT, user_types, "0", OPT_UINT_T, 0, FLDSET(struct user_profile, timeout));
2418  aco_option_register(&cfg_info, "text_messaging", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TEXT_MESSAGING);
2419  aco_option_register(&cfg_info, "answer_channel", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANSWER_CHANNEL);
2420 
2421  /* This option should only be used with the CONFBRIDGE dialplan function */
2422  aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
2423 
2424 /* XXX ASTERISK-21271 need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
2425  /* Bridge options */
2426  aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
2427  aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
2428  /* "auto" will fail to parse as a uint, but we use PARSE_DEFAULT to set the value to 0 in that case, which is the value that auto resolves to */
2429  aco_option_register(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, internal_sample_rate), 0);
2430  aco_option_register(&cfg_info, "binaural_active", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_BINAURAL_ACTIVE);
2431  aco_option_register(&cfg_info, "maximum_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, maximum_sample_rate), 0);
2432  aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
2433  aco_option_register(&cfg_info, "record_conference", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_CONFERENCE);
2434  aco_option_register_custom(&cfg_info, "video_mode", ACO_EXACT, bridge_types, NULL, video_mode_handler, 0);
2435  aco_option_register(&cfg_info, "record_file_append", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_APPEND);
2436  aco_option_register(&cfg_info, "record_file_timestamp", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_TIMESTAMP);
2437  aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
2438  aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
2439  aco_option_register(&cfg_info, "record_options", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_options));
2440  aco_option_register(&cfg_info, "record_command", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_command));
2441  aco_option_register(&cfg_info, "regcontext", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, regcontext));
2442  aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language));
2443  aco_option_register_custom(&cfg_info, "sound_", ACO_PREFIX, bridge_types, NULL, sound_option_handler, 0);
2444  aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard));
2445  aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval));
2446  aco_option_register_custom(&cfg_info, "remb_behavior", ACO_EXACT, bridge_types, "average", remb_behavior_handler, 0);
2447  aco_option_register(&cfg_info, "remb_estimated_bitrate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_estimated_bitrate));
2448  aco_option_register(&cfg_info, "enable_events", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_ENABLE_EVENTS);
2449  /* This option should only be used with the CONFBRIDGE dialplan function */
2450  aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0);
2451 
2452  /* Menu options */
2453  aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
2454  /* This option should only be used with the CONFBRIDGE dialplan function */
2455  aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0);
2456  aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
2457 
2458  if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
2459  goto error;
2460  }
2461 
2462  if (ast_cli_register_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser))) {
2463  goto error;
2464  }
2465 
2466  return 0;
2467 error:
2469  return -1;
2470 }
2471 
2473 {
2474  if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2475  /* On a reload, just keep the config we already have in place. */
2476  return -1;
2477  }
2478  return 0;
2479 }
2480 
2481 static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
2482 {
2483  *dst = *src;
2484 }
2485 
2486 const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
2487 {
2488  struct user_profile *tmp2;
2489  struct ast_datastore *datastore = NULL;
2490  struct func_confbridge_data *b_data = NULL;
2492 
2493  if (chan && ast_strlen_zero(user_profile_name)) {
2494  ast_channel_lock(chan);
2495  datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2496  ast_channel_unlock(chan);
2497  if (datastore) {
2498  b_data = datastore->data;
2499  if (b_data->u_usable) {
2500  conf_user_profile_copy(result, &b_data->u_profile);
2501  return result;
2502  }
2503  }
2504  }
2505 
2506  if (!cfg) {
2507  return NULL;
2508  }
2509  if (ast_strlen_zero(user_profile_name)) {
2510  user_profile_name = DEFAULT_USER_PROFILE;
2511  }
2512  if (!(tmp2 = ao2_find(cfg->user_profiles, user_profile_name, OBJ_KEY))) {
2513  return NULL;
2514  }
2515  ao2_lock(tmp2);
2516  conf_user_profile_copy(result, tmp2);
2517  ao2_unlock(tmp2);
2518  ao2_ref(tmp2, -1);
2519 
2520  return result;
2521 }
2522 
2524 {
2525  *dst = *src;
2526  if (src->sounds) {
2527  ao2_ref(src->sounds, +1);
2528  }
2529 }
2530 
2532 {
2533  if (b_profile->sounds) {
2534  ao2_ref(b_profile->sounds, -1);
2535  b_profile->sounds = NULL;
2536  }
2537 }
2538 
2539 const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
2540 {
2541  struct bridge_profile *tmp2;
2542  struct ast_datastore *datastore = NULL;
2543  struct func_confbridge_data *b_data = NULL;
2545 
2546  if (chan && ast_strlen_zero(bridge_profile_name)) {
2547  ast_channel_lock(chan);
2548  datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2549  ast_channel_unlock(chan);
2550  if (datastore) {
2551  b_data = datastore->data;
2552  if (b_data->b_usable) {
2553  conf_bridge_profile_copy(result, &b_data->b_profile);
2554  return result;
2555  }
2556  }
2557  }
2558 
2559  if (!cfg) {
2560  return NULL;
2561  }
2562  if (ast_strlen_zero(bridge_profile_name)) {
2563  bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
2564  }
2565  if (!(tmp2 = ao2_find(cfg->bridge_profiles, bridge_profile_name, OBJ_KEY))) {
2566  return NULL;
2567  }
2568  ao2_lock(tmp2);
2569  conf_bridge_profile_copy(result, tmp2);
2570  ao2_unlock(tmp2);
2571  ao2_ref(tmp2, -1);
2572 
2573  return result;
2574 }
2575 
2578  struct conf_menu_entry menu_entry;
2579  struct conf_menu *menu;
2580 };
2581 
2582 static void menu_hook_destroy(void *hook_pvt)
2583 {
2584  struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2585  struct conf_menu_action *action = NULL;
2586 
2587  ao2_cleanup(pvt->menu);
2588 
2589  while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
2590  ast_free(action);
2591  }
2592  ast_free(pvt);
2593 }
2594 
2595 static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
2596 {
2597  struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2598 
2599  return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
2600 }
2601 
2603 {
2604  struct conf_menu_action *menu_action = NULL;
2605  while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
2606  ast_free(menu_action);
2607  }
2608 }
2609 
2610 int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
2611 {
2612  struct conf_menu_entry *menu_entry = NULL;
2613 
2614  ao2_lock(menu);
2615  AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2616  if (!strcasecmp(menu_entry->dtmf, dtmf_sequence)) {
2617  copy_menu_entry(result, menu_entry);
2618  ao2_unlock(menu);
2619  return 1;
2620  }
2621  }
2622  ao2_unlock(menu);
2623 
2624  return 0;
2625 }
2626 
2627 static int apply_menu_to_user(struct confbridge_user *user, struct conf_menu *menu)
2628 {
2629  struct conf_menu_entry *menu_entry;
2630 
2631  SCOPED_AO2LOCK(menu_lock, menu);
2632  AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2633  struct dtmf_menu_hook_pvt *pvt;
2634 
2635  if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
2636  return -1;
2637  }
2638  pvt->user = user;
2639  pvt->menu = ao2_bump(menu);
2640 
2641  if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
2642  menu_hook_destroy(pvt);
2643  return -1;
2644  }
2645 
2646  if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
2648  menu_hook_destroy(pvt);
2649  }
2650  }
2651  strcpy(user->menu_name, menu->name); /* Safe */
2652 
2653  return 0;
2654 }
2655 
2656 int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
2657 {
2659  RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2660 
2661  if (chan && ast_strlen_zero(menu_profile_name)) {
2662  struct ast_datastore *datastore;
2663  struct func_confbridge_data *b_data;
2664 
2665  ast_channel_lock(chan);
2666  datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2667  ast_channel_unlock(chan);
2668  if (datastore) {
2669  /* If a menu exists in the CONFBRIDGE function datastore, use it. */
2670  b_data = datastore->data;
2671  if (b_data->m_usable) {
2672  menu = ao2_bump(b_data->menu);
2673  return apply_menu_to_user(user, menu);
2674  }
2675  }
2676  }
2677 
2678  /* Otherwise, we need to get whatever menu profile is specified to use (or default). */
2679  if (!cfg) {
2680  return -1;
2681  }
2682 
2683  if (ast_strlen_zero(menu_profile_name)) {
2684  menu_profile_name = DEFAULT_MENU_PROFILE;
2685  }
2686 
2687  if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
2688  return -1;
2689  }
2690 
2691  return apply_menu_to_user(user, menu);
2692 }
2693 
2695 {
2696  ast_cli_unregister_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser));
2697  aco_info_destroy(&cfg_info);
2699 }
static char user[512]
const char * type
Definition: datastore.h:32
const ast_string_field unlockednow
Definition: confbridge.h:222
static char * complete_menu_name(const char *line, const char *word, int pos, int state)
static const char type[]
Definition: chan_ooh323.c:109
static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
const ast_string_field thereare
Definition: confbridge.h:222
struct conf_menu_action::@78::@80 dialplan_args
static int verify_default_profiles(void)
#define ast_channel_lock(chan)
Definition: channel.h:2913
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
struct conf_menu * menu
static int user_hash_cb(const void *obj, const int flags)
static int user_cmp_cb(void *obj, void *arg, int flags)
static const char name[]
Definition: format_mp3.c:68
Asterisk main include file. File version handling, generic pbx functions.
struct user_profile u_profile
const ast_string_field join
Definition: confbridge.h:222
static int menu_hash_cb(const void *obj, const int flags)
struct conf_menu::@83 entries
static char * handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void * confbridge_cfg_alloc(void)
static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static char * handle_cli_confbridge_show_user_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static AO2_GLOBAL_OBJ_STATIC(cfg_handle)
const ast_string_field otherinparty
Definition: confbridge.h:222
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
static unsigned char leave[]
Definition: leave.h:12
static struct aco_type user_type
static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
const char * conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
Looks to see if sound file is stored in bridge profile sounds, if not default sound is provided...
Definition: confbridge.h:136
#define OBJ_KEY
Definition: astobj2.h:1155
char name[MAX_PROFILE_NAME]
Definition: confbridge.h:226
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define OBJ_POINTER
Definition: astobj2.h:1154
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
char rec_command[128]
Definition: confbridge.h:230
static void func_confbridge_data_destructor(struct func_confbridge_data *b_data)
static int apply_menu_to_user(struct confbridge_user *user, struct conf_menu *menu)
static struct aco_file confbridge_conf
static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
const struct user_profile * conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
find a user profile given a user profile&#39;s name and store that profile in result structure.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
static struct aco_type general_type
static int tmp()
Definition: bt_open.c:389
char rec_file[PATH_MAX]
Definition: confbridge.h:228
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
struct bridge_profile_sounds * sounds
Definition: confbridge.h:236
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
const ast_string_field onlyone
Definition: confbridge.h:222
Definition: cli.h:152
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
Destroys and frees all the actions stored in a menu_entry structure.
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
Type for a default handler that should do nothing.
Structure for a data store type.
Definition: datastore.h:31
struct bridge_profile b_profile
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
struct ao2_container * bridge_profiles
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static char * complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
#define ast_assert(a)
Definition: utils.h:710
unsigned int silence_threshold
Definition: confbridge.h:162
static char * handle_cli_confbridge_show_bridge_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void func_confbridge_destroy_cb(void *data)
#define ao2_unlock(a)
Definition: astobj2.h:730
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag...
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2400
static char * complete_user_profile_name(const char *line, const char *word, int pos, int state)
const char * args
static struct aco_type bridge_type
#define NULL
Definition: resample.c:96
The representation of a single configuration file to be processed.
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static void menu_hook_destroy(void *hook_pvt)
static int priority
enum aco_type_t type
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
unsigned int announce_user_count_all_after
Definition: confbridge.h:158
conf_menu_action_id
Definition: confbridge.h:94
#define ast_set_flags_to(p, flag, value)
Definition: utils.h:104
const char * line
Definition: cli.h:162
const ast_string_field hasjoin
Definition: confbridge.h:222
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
char dtmf[MAXIMUM_DTMF_FEATURE_STRING]
Definition: confbridge.h:138
struct conf_menu * menu
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1156
static struct aco_type * menu_types[]
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src)
copies a bridge profile
#define ao2_bump(obj)
Definition: astobj2.h:491
Type for default option handler for character array strings.
static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define AST_LOG_NOTICE
Definition: logger.h:268
Configuration File Parser.
const ast_string_field begin
Definition: confbridge.h:222
struct ao2_container * menus
#define ast_log
Definition: astobj2.c:42
#define __stringify(x)
Definition: asterisk.h:214
static struct aco_type menu_type
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define DEFAULT_TALKING_THRESHOLD
Definition: confbridge.h:46
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
static void bridge_profile_sounds_destroy_cb(void *obj)
static void menu_destructor(void *obj)
static void * bridge_profile_alloc(const char *category)
static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
const ast_string_field errormenu
Definition: confbridge.h:222
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
Type for default option handler for unsigned integers.
static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
unsigned int flags
Definition: confbridge.h:231
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const int n
Definition: cli.h:165
int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct confbridge_user *user, struct conf_menu_entry *menu_entry, struct conf_menu *menu)
Once a DTMF sequence matches a sequence in the user&#39;s DTMF menu, this function will get called to per...
static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
void conf_bridge_profile_destroy(struct bridge_profile *b_profile)
Destroy a bridge profile found by &#39;conf_find_bridge_profile&#39;.
const char * category
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int conf_reload_config(void)
reload confbridge.conf file
const ast_string_field binauraloff
Definition: confbridge.h:222
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:121
struct ao2_container * container
Definition: res_fax.c:502
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
char language[MAX_LANGUAGE]
Definition: confbridge.h:227
const ast_string_field waitforleader
Definition: confbridge.h:222
unsigned int flags
Definition: confbridge.h:157
static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
unsigned int maximum_sample_rate
Definition: confbridge.h:234
#define ARRAY_LEN(a)
Definition: utils.h:639
static void confbridge_cfg_destructor(void *obj)
Core PBX routines and definitions.
unsigned int internal_sample_rate
Definition: confbridge.h:233
static struct stasis_rest_handlers sounds
REST handler for /api-docs/sounds.json.
Their was an error and no changes were applied.
const char *const * argv
Definition: cli.h:161
char pin[MAX_PIN]
Definition: confbridge.h:154
char playback_file[PATH_MAX]
Definition: confbridge.h:123
static int menu_cmp_cb(void *obj, void *arg, int flags)
Configuration option-handling.
unsigned int video_update_discard
Definition: confbridge.h:238
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
char rec_options[128]
Definition: confbridge.h:229
void conf_destroy_config(void)
destroy the information loaded from the confbridge.conf file
#define CLI_SHOWUSAGE
Definition: cli.h:45
const ast_string_field getpin
Definition: confbridge.h:222
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
static struct ast_cli_entry cli_confbridge_parser[]
static struct aco_type * user_types[]
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
static void * user_profile_alloc(const char *category)
const ast_string_field participantsmuted
Definition: confbridge.h:222
static struct aco_type * bridge_types[]
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ao2_container * user_profiles
static const struct ast_datastore_info confbridge_datastore
static char * handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
unsigned int max_members
Definition: confbridge.h:232
const ast_string_field leave
Definition: confbridge.h:222
unsigned int talking_threshold
Definition: confbridge.h:160
const ast_string_field lockednow
Definition: confbridge.h:222
static void * menu_alloc(const char *category)
#define ast_channel_unlock(chan)
Definition: channel.h:2914
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
find a menu profile given a menu profile&#39;s name and apply the menu in DTMF hooks. ...
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
const ast_string_field binauralon
Definition: confbridge.h:222
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
const ast_string_field participantsunmuted
Definition: confbridge.h:222
struct confbridge_user * user
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
struct ast_bridge_features features
Definition: confbridge.h:278
const char * word
Definition: cli.h:163
char regcontext[AST_MAX_CONTEXT]
Definition: confbridge.h:237
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
union conf_menu_action::@78 data
const ast_string_field unmuted
Definition: confbridge.h:222
int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
Finds a menu_entry in a menu structure matched by DTMF sequence.
static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
structure to hold users read from users.conf
int ast_bridge_dtmf_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a DTMF hook to a bridge features structure.
Definition: bridge.c:3245
#define ast_clear_flag(p, flag)
Definition: utils.h:77
char name[MAX_PROFILE_NAME]
Definition: confbridge.h:148
static char * handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Support for logging to various files, console and syslog Configuration in file logger.conf.
const char * usage
Definition: cli.h:177
static corosync_cfg_handle_t cfg_handle
Definition: res_corosync.c:284
#define CLI_SUCCESS
Definition: cli.h:44
enum conf_menu_action_id id
Definition: confbridge.h:121
const ast_string_field invalidpin
Definition: confbridge.h:222
#define ACO_FILES(...)
static int bridge_hash_cb(const void *obj, const int flags)
void * data
Definition: datastore.h:70
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
Structure that contains information regarding a channel in a bridge.
char * strsep(char **str, const char *delims)
const ast_string_field onlyperson
Definition: confbridge.h:222
char menu_name[MAX_PROFILE_NAME]
Definition: confbridge.h:275
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
Type information about a category-level configurable object.
static void * menu_find(struct ao2_container *container, const char *category)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static int bridge_cmp_cb(void *obj, void *arg, int flags)
static int remb_behavior_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
char name[MAX_PROFILE_NAME]
Definition: confbridge.h:153
const int pos
Definition: cli.h:164
const char * filename
#define DEFAULT_MENU_PROFILE
Definition: confbridge.h:43
static PGresult * result
Definition: cel_pgsql.c:88
int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static char regcontext[AST_MAX_CONTEXT]
Definition: chan_iax2.c:321
static void * user_profile_find(struct ao2_container *container, const char *category)
The structure that represents a conference bridge user.
Definition: confbridge.h:271
#define DEFAULT_BRIDGE_PROFILE
Definition: confbridge.h:42
Definition: search.h:40
int error(const char *format,...)
Definition: utils/frame.c:999
struct conf_menu_entry::@81 actions
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
enum queue_result id
Definition: app_queue.c:1513
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define PATH_MAX
Definition: asterisk.h:40
int conf_load_config(void)
load confbridge.conf file
Generic container type.
#define DEFAULT_USER_PROFILE
Definition: confbridge.h:41
static void bridge_profile_destructor(void *obj)
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
const ast_string_field muted
Definition: confbridge.h:222
static char * handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
char moh_class[128]
Definition: confbridge.h:155
int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
Parse a single ast_variable and apply it to an object.
unsigned int remb_send_interval
Definition: confbridge.h:239
const ast_string_field leaderhasleft
Definition: confbridge.h:222
const ast_string_field kicked
Definition: confbridge.h:222
CONFIG_INFO_STANDARD(cfg_info, cfg_handle, confbridge_cfg_alloc,.files=ACO_FILES(&confbridge_conf),.pre_apply_config=verify_default_profiles,)
unsigned int mix_interval
Definition: confbridge.h:235
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2386
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2395
static void user_profile_destructor(void *obj)
const ast_string_field locked
Definition: confbridge.h:222
#define DEFAULT_SILENCE_THRESHOLD
Definition: confbridge.h:49
Channel Bridging API.
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250
static struct bridge_profile_sounds * bridge_profile_sounds_alloc(void)
static void * bridge_profile_find(struct ao2_container *container, const char *category)
char announcement[PATH_MAX]
Definition: confbridge.h:156
short word
struct conf_menu_entry menu_entry
#define AST_APP_ARG(name)
Define an application argument.
const ast_string_field placeintoconf
Definition: confbridge.h:222
const ast_string_field hasleft
Definition: confbridge.h:222
const struct bridge_profile * conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
Find a bridge profile given a bridge profile&#39;s name and store that profile in result structure...
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549
static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)