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