Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
52 <version>12.0.0</version>
53 </since>
54 <synopsis>A named profile to apply to specific callers.</synopsis>
55 <description><para>Callers in a ConfBridge have a profile associated with them
56 that determine their options. A configuration section is determined to be a
57 user_profile when the <literal>type</literal> parameter has a value
58 of <literal>user</literal>.
59 </para></description>
60 <configOption name="type">
61 <since>
62 <version>11.0.0</version>
63 </since>
64 <synopsis>Define this configuration category as a user profile.</synopsis>
65 <description><para>The type parameter determines how a context in the
66 configuration file is interpreted.</para>
67 <enumlist>
68 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
69 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
70 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
71 </enumlist>
72 </description>
73 </configOption>
74 <configOption name="admin">
75 <since>
76 <version>11.0.0</version>
77 </since>
78 <synopsis>Sets if the user is an admin or not</synopsis>
79 </configOption>
80 <configOption name="send_events" default="no">
81 <since>
82 <version>15.5.0</version>
83 </since>
84 <synopsis>Sets if events are send to the user</synopsis>
85 <description><para>If events are enabled for this bridge and this option is
86 set, users will receive events like join, leave, talking, etc. via text
87 messages. For users accessing the bridge via chan_pjsip, this means
88 in-dialog MESSAGE messages. This is most useful for WebRTC participants
89 where the browser application can use the messages to alter the user
90 interface.</para></description>
91 </configOption>
92 <configOption name="echo_events" default="yes">
93 <since>
94 <version>15.5.0</version>
95 </since>
96 <synopsis>Sets if events are echoed back to the user that
97 triggered them</synopsis>
98 <description><para>If events are enabled for this user and this option
99 is set, the user will receive events they trigger, talking, mute, etc.
100 If not set, they will not receive their own events.
101 </para></description>
102 </configOption>
103 <configOption name="marked">
104 <since>
105 <version>11.0.0</version>
106 </since>
107 <synopsis>Sets if this is a marked user or not</synopsis>
108 </configOption>
109 <configOption name="startmuted">
110 <since>
111 <version>11.0.0</version>
112 </since>
113 <synopsis>Sets if all users should start out muted</synopsis>
114 </configOption>
115 <configOption name="music_on_hold_when_empty">
116 <since>
117 <version>11.0.0</version>
118 </since>
119 <synopsis>Play MOH when user is alone or waiting on a marked user</synopsis>
120 </configOption>
121 <configOption name="quiet">
122 <since>
123 <version>11.0.0</version>
124 </since>
125 <synopsis>Silence enter/leave prompts and user intros for this user</synopsis>
126 </configOption>
127 <configOption name="hear_own_join_sound">
128 <since>
129 <version>16.26.0</version>
130 <version>18.12.0</version>
131 <version>19.4.0</version>
132 </since>
133 <synopsis>Determines if the user also hears the join sound when they enter a conference</synopsis>
134 </configOption>
135 <configOption name="announce_user_count">
136 <since>
137 <version>11.0.0</version>
138 </since>
139 <synopsis>Sets if the number of users should be announced to the user</synopsis>
140 </configOption>
141 <configOption name="announce_user_count_all">
142 <since>
143 <version>11.0.0</version>
144 </since>
145 <synopsis>Announce user count to all the other users when this user joins</synopsis>
146 <description><para>Sets if the number of users should be announced to all the other users
147 in the conference when this user joins. This option can be either set to 'yes' or
148 a number. When set to a number, the announcement will only occur once the user
149 count is above the specified number.
150 </para></description>
151 </configOption>
152 <configOption name="announce_only_user">
153 <since>
154 <version>11.0.0</version>
155 </since>
156 <synopsis>Announce to a user when they join an empty conference</synopsis>
157 </configOption>
158 <configOption name="wait_marked">
159 <since>
160 <version>11.0.0</version>
161 </since>
162 <synopsis>Sets if the user must wait for a marked user to enter before joining a conference</synopsis>
163 </configOption>
164 <configOption name="end_marked">
165 <since>
166 <version>11.0.0</version>
167 </since>
168 <synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
169 </configOption>
170 <configOption name="end_marked_any">
171 <since>
172 <version>16.29.0</version>
173 <version>18.15.0</version>
174 <version>19.7.0</version>
175 </since>
176 <synopsis>Kick the user from the conference when any marked user leaves</synopsis>
177 </configOption>
178 <configOption name="talk_detection_events">
179 <since>
180 <version>11.0.0</version>
181 </since>
182 <synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
183 </configOption>
184 <configOption name="dtmf_passthrough">
185 <since>
186 <version>11.0.0</version>
187 </since>
188 <synopsis>Sets whether or not DTMF should pass through the conference</synopsis>
189 </configOption>
190 <configOption name="announce_join_leave">
191 <since>
192 <version>11.0.0</version>
193 </since>
194 <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter</synopsis>
195 </configOption>
196 <configOption name="announce_join_leave_review">
197 <since>
198 <version>13.0.0</version>
199 </since>
200 <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter.
201 The user will be asked to review the recording of their name before entering the conference.</synopsis>
202 </configOption>
203 <configOption name="pin">
204 <since>
205 <version>11.0.0</version>
206 </since>
207 <synopsis>Sets a PIN the user must enter before joining the conference</synopsis>
208 </configOption>
209 <configOption name="music_on_hold_class">
210 <since>
211 <version>11.0.0</version>
212 </since>
213 <synopsis>The MOH class to use for this user</synopsis>
214 </configOption>
215 <configOption name="announcement">
216 <since>
217 <version>11.0.0</version>
218 </since>
219 <synopsis>Sound file to play to the user when they join a conference</synopsis>
220 </configOption>
221 <configOption name="denoise">
222 <since>
223 <version>11.0.0</version>
224 </since>
225 <synopsis>Apply a denoise filter to the audio before mixing</synopsis>
226 <description><para>Sets whether or not a denoise filter should be applied
227 to the audio before mixing or not. Off by default. Requires
228 <literal>codec_speex</literal> to be built and installed. Do not confuse this option
229 with <replaceable>drop_silence</replaceable>. Denoise is useful if there is a lot of background
230 noise for a user as it attempts to remove the noise while preserving
231 the speech. This option does NOT remove silence from being mixed into
232 the conference and does come at the cost of a slight performance hit.
233 </para></description>
234 </configOption>
235 <configOption name="dsp_drop_silence">
236 <since>
237 <version>11.0.0</version>
238 </since>
239 <synopsis>Drop what Asterisk detects as silence from audio sent to the bridge</synopsis>
240 <description><para>
241 This option drops what Asterisk detects as silence from
242 entering into the bridge. Enabling this option will drastically
243 improve performance and help remove the buildup of background
244 noise from the conference. Highly recommended for large conferences
245 due to its performance enhancements.
246 </para></description>
247 </configOption>
248 <configOption name="dsp_silence_threshold">
249 <since>
250 <version>11.0.0</version>
251 </since>
252 <synopsis>The number of milliseconds of silence necessary to declare talking stopped.</synopsis>
253 <description>
254 <para>The time in milliseconds of sound falling below the
255 <replaceable>dsp_talking_threshold</replaceable> option when
256 a user is considered to stop talking. This value affects several
257 operations and should not be changed unless the impact on call
258 quality is fully understood.
259 </para>
260 <para>What this value affects internally:
261 </para>
262 <para>1. When talk detection AMI events are enabled, this value
263 determines when the user has stopped talking after a
264 period of talking. If this value is set too low
265 AMI events indicating the user has stopped talking
266 may get falsely sent out when the user briefly pauses
267 during mid sentence.
268 </para>
269 <para>2. The <replaceable>drop_silence</replaceable> option
270 depends on this value to determine when the user's audio should
271 begin to be dropped from the conference bridge after the user
272 stops talking. If this value is set too low the user's
273 audio stream may sound choppy to the other participants. This
274 is caused by the user transitioning constantly from silence to
275 talking during mid sentence.
276 </para>
277 <para>The best way to approach this option is to set it slightly
278 above the maximum amount of milliseconds of silence a user may
279 generate during natural speech.
280 </para>
281 <para>Valid values are 1 through 2^31.</para>
282 </description>
283 </configOption>
284 <configOption name="dsp_talking_threshold">
285 <since>
286 <version>11.10.0</version>
287 <version>12.3.0</version>
288 </since>
289 <synopsis>Average magnitude threshold to determine talking.</synopsis>
290 <description>
291 <para>The minimum average magnitude per sample in a frame
292 for the DSP to consider talking/noise present. A value below
293 this level is considered silence. This value affects several
294 operations and should not be changed unless the impact on call
295 quality is fully understood.
296 </para>
297 <para>What this value affects internally:
298 </para>
299 <para>1. Audio is only mixed out of a user's incoming audio
300 stream if talking is detected. If this value is set too
301 high the user will hear himself talking.
302 </para>
303 <para>2. When talk detection AMI events are enabled, this value
304 determines when talking has begun which results in
305 an AMI event to fire. If this value is set too low
306 AMI events may be falsely triggered by variants in
307 room noise.
308 </para>
309 <para>3. The <replaceable>drop_silence</replaceable> option
310 depends on this value to determine when the user's audio should
311 be mixed into the bridge after periods of silence. If this value
312 is too high the user's speech will get discarded as they will
313 be considered silent.
314 </para>
315 <para>Valid values are 1 through 2^15.</para>
316 </description>
317 </configOption>
318 <configOption name="jitterbuffer">
319 <since>
320 <version>11.0.0</version>
321 </since>
322 <synopsis>Place a jitter buffer on the user's audio stream before audio mixing is performed</synopsis>
323 <description><para>
324 Enabling this option places a jitterbuffer on the user's audio stream
325 before audio mixing is performed. This is highly recommended but will
326 add a slight delay to the audio. This option is using the <literal>JITTERBUFFER</literal>
327 dialplan function's default adaptive jitterbuffer. For a more fine tuned
328 jitterbuffer, disable this option and use the <literal>JITTERBUFFER</literal> dialplan function
329 on the user before entering the ConfBridge application.
330 </para></description>
331 </configOption>
332 <configOption name="template">
333 <since>
334 <version>11.0.0</version>
335 </since>
336 <synopsis>When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile</synopsis>
337 </configOption>
338 <configOption name="timeout">
339 <since>
340 <version>13.7.0</version>
341 </since>
342 <synopsis>Kick the user out of the conference after this many seconds. 0 means there is no timeout for the user.</synopsis>
343 </configOption>
344 <configOption name="text_messaging" default="yes">
345 <since>
346 <version>16.10.0</version>
347 <version>17.4.0</version>
348 </since>
349 <synopsis>Sets if text messages are sent to the user.</synopsis>
350 <description><para>If text messaging is enabled for this user then
351 text messages will be sent to it. These may be events or from other
352 participants in the conference bridge. If disabled then no text
353 messages are sent to the user.</para></description>
354 </configOption>
355 <configOption name="answer_channel" default="yes">
356 <since>
357 <version>16.19.0</version>
358 <version>18.5.0</version>
359 </since>
360 <synopsis>Sets if a user's channel should be answered if currently unanswered.</synopsis>
361 </configOption>
362 </configObject>
363 <configObject name="bridge_profile">
364 <since>
365 <version>12.0.0</version>
366 </since>
367 <synopsis>A named profile to apply to specific bridges.</synopsis>
368 <description><para>ConfBridge bridges have a profile associated with them
369 that determine their options. A configuration section is determined to be a
370 <literal>bridge_profile</literal> when the <literal>type</literal> parameter has a value
371 of <literal>bridge</literal>.
372 </para></description>
373 <configOption name="type">
374 <since>
375 <version>12.0.0</version>
376 </since>
377 <synopsis>Define this configuration category as a bridge profile</synopsis>
378 <description><para>The type parameter determines how a context in the
379 configuration file is interpreted.</para>
380 <enumlist>
381 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
382 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
383 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
384 </enumlist>
385 </description>
386 </configOption>
387 <configOption name="jitterbuffer">
388 <since>
389 <version>11.0.0</version>
390 </since>
391 <synopsis>Place a jitter buffer on the conference's audio stream</synopsis>
392 </configOption>
393 <configOption name="internal_sample_rate">
394 <since>
395 <version>18.22.0</version>
396 <version>20.7.0</version>
397 <version>21.2.0</version>
398 </since>
399 <synopsis>Set the internal native sample rate for mixing the conference</synopsis>
400 <description><para>
401 Sets the internal native sample rate the
402 conference is mixed at. This is set to automatically
403 adjust the sample rate to the best quality by default.
404 Other values can be anything from 8000-192000. If a
405 sample rate is set that Asterisk does not support, the
406 closest sample rate Asterisk does support to the one requested
407 will be used.
408 </para></description>
409 </configOption>
410 <configOption name="maximum_sample_rate">
411 <since>
412 <version>18.22.0</version>
413 <version>20.7.0</version>
414 <version>21.2.0</version>
415 </since>
416 <synopsis>Set the maximum native sample rate for mixing the conference</synopsis>
417 <description><para>
418 Sets the maximum native sample rate the
419 conference is mixed at. This is set to not have a
420 maximum by default. If a sample rate is specified,
421 though, the native sample rate will never exceed it.
422 </para></description>
423 </configOption>
424 <configOption name="language" default="en">
425 <since>
426 <version>11.7.0</version>
427 </since>
428 <synopsis>The language used for announcements to the conference.</synopsis>
429 <description><para>
430 By default, announcements to a conference use English. Which means
431 the prompts played to all users within the conference will be
432 English. By changing the language of a bridge, this will change
433 the language of the prompts played to all users.
434 </para></description>
435 </configOption>
436 <configOption name="mixing_interval">
437 <since>
438 <version>11.0.0</version>
439 </since>
440 <synopsis>Sets the internal mixing interval in milliseconds for the bridge</synopsis>
441 <description><para>
442 Sets the internal mixing interval in milliseconds for the bridge. This
443 number reflects how tight or loose the mixing will be for the conference.
444 In order to improve performance a larger mixing interval such as 40ms may
445 be chosen. Using a larger mixing interval comes at the cost of introducing
446 larger amounts of delay into the bridge. Valid values here are 10, 20, 40,
447 or 80.
448 </para></description>
449 </configOption>
450 <configOption name="binaural_active">
451 <since>
452 <version>15.0.0</version>
453 </since>
454 <synopsis>If true binaural conferencing with stereo audio is active</synopsis>
455 <description><para>
456 Activates binaural mixing for a conference bridge.
457 Binaural features are disabled by default.
458 </para></description>
459 </configOption>
460 <configOption name="record_conference">
461 <since>
462 <version>11.0.0</version>
463 </since>
464 <synopsis>Record the conference starting with the first active user's entrance and ending with the last active user's exit</synopsis>
465 <description><para>
466 Records the conference call starting when the first user
467 enters the room, and ending when the last user exits the room.
468 The default recorded filename is
469 <filename>'confbridge-${name of conference bridge}-${start time}.wav'</filename>
470 and the default format is 8khz slinear. This file will be
471 located in the configured monitoring directory in <filename>asterisk.conf</filename>.
472 </para></description>
473 </configOption>
474 <configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
475 <since>
476 <version>11.0.0</version>
477 </since>
478 <synopsis>The filename of the conference recording</synopsis>
479 <description><para>
480 When <replaceable>record_conference</replaceable> is set to yes, the specific name of the
481 record file can be set using this option. Note that since multiple
482 conferences may use the same bridge profile, this may cause issues
483 depending on the configuration. It is recommended to only use this
484 option dynamically with the <literal>CONFBRIDGE()</literal> dialplan function. This
485 allows the record name to be specified and a unique name to be chosen.
486 By default, the record_file is stored in Asterisk's spool/monitor directory
487 with a unique filename starting with the 'confbridge' prefix.
488 </para></description>
489 </configOption>
490 <configOption name="record_file_append" default="yes">
491 <since>
492 <version>12.0.0</version>
493 </since>
494 <synopsis>Append to record file when starting/stopping on same conference recording</synopsis>
495 <description><para>
496 When <replaceable>record_file_append</replaceable> is set to yes, stopping and starting recording on a
497 conference adds the new portion to end of current record_file. When this is
498 set to no, a new <replaceable>record_file</replaceable> is generated every time you start then stop recording
499 on a conference.
500 </para></description>
501 </configOption>
502 <configOption name="record_file_timestamp" default="yes">
503 <since>
504 <version>14.0.0</version>
505 </since>
506 <synopsis>Append the start time to the record_file name so that it is unique.</synopsis>
507 <description><para>
508 When <replaceable>record_file_timestamp</replaceable> is set to yes, the start time is appended to
509 <replaceable>record_file</replaceable> so that the filename is unique. This allows you to specify
510 a <replaceable>record_file</replaceable> but not overwrite existing recordings.
511 </para></description>
512 </configOption>
513 <configOption name="record_options" default="">
514 <since>
515 <version>14.0.0</version>
516 </since>
517 <synopsis>Pass additional options to MixMonitor when recording</synopsis>
518 <description><para>
519 Pass additional options to MixMonitor when <replaceable>record_conference</replaceable> is set to yes.
520 See <literal>MixMonitor</literal> for available options.
521 </para></description>
522 </configOption>
523 <configOption name="record_command" default="">
524 <since>
525 <version>14.0.0</version>
526 </since>
527 <synopsis>Execute a command after recording ends</synopsis>
528 <description><para>
529 Executes the specified command when recording ends. Any strings matching <literal>^{X}</literal> will be
530 unescaped to <variable>X</variable>. All variables will be evaluated at the time ConfBridge is called.
531 </para></description>
532 </configOption>
533 <configOption name="regcontext">
534 <since>
535 <version>13.10.0</version>
536 </since>
537 <synopsis>The name of the context into which to register the name of the conference bridge as NoOP() at priority 1</synopsis>
538 <description><para>
539 When set this will cause the name of the created conference to be registered
540 into the named context at priority 1 with an operation of NoOP(). This can
541 then be used in other parts of the dialplan to test for the existence of a
542 specific conference bridge.
543 You should be aware that there are potential races between testing for the
544 existence of a bridge, and taking action upon that information, consider
545 for example two callers executing the check simultaneously, and then taking
546 special action as "first caller" into the bridge. The same for exiting,
547 directly after the check the bridge can be destroyed before the new caller
548 enters (creating a new bridge), for example, and the "first member" actions
549 could thus be missed.
550 </para></description>
551 </configOption>
552 <configOption name="video_mode">
553 <since>
554 <version>11.0.0</version>
555 </since>
556 <synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis>
557 <description><para>
558 Sets how confbridge handles video distribution to the conference participants.
559 Note that participants wanting to view and be the source of a video feed
560 <emphasis>MUST</emphasis> be sharing the same video codec. Also, using video in conjunction with
561 with the jitterbuffer currently results in the audio being slightly out of sync
562 with the video. This is a result of the jitterbuffer only working on the audio
563 stream. It is recommended to disable the jitterbuffer when video is used.</para>
564 <enumlist>
565 <enum name="none">
566 <para>No video sources are set by default in the conference. It is still
567 possible for a user to be set as a video source via AMI or DTMF action
568 at any time.</para>
569 </enum>
570 <enum name="follow_talker">
571 <para>The video feed will follow whoever is talking and providing video.</para>
572 </enum>
573 <enum name="last_marked">
574 <para>The last marked user to join the conference with video capabilities
575 will be the single source of video distributed to all participants.
576 If multiple marked users are capable of video, the last one to join
577 is always the source, when that user leaves it goes to the one who
578 joined before them.</para>
579 </enum>
580 <enum name="first_marked">
581 <para>The first marked user to join the conference with video capabilities
582 is the single source of video distribution among all participants. If
583 that user leaves, the marked user to join after them becomes the source.</para>
584 </enum>
585 <enum name="sfu">
586 <para>Selective Forwarding Unit - Sets multi-stream
587 operation for a multi-party video conference.</para>
588 </enum>
589 </enumlist>
590 </description>
591 </configOption>
592 <configOption name="max_members">
593 <since>
594 <version>11.0.0</version>
595 </since>
596 <synopsis>Limit the maximum number of participants for a single conference</synopsis>
597 <description><para>
598 This option limits the number of participants for a single
599 conference to a specific number. By default conferences
600 have no participant limit. After the limit is reached, the
601 conference will be locked until someone leaves. Note however
602 that an Admin user will always be alowed to join the conference
603 regardless if this limit is reached or not.
604 </para></description>
605 </configOption>
606 <configOption name="sound_">
607 <since>
608 <version>13.19.0</version>
609 <version>15.2.0</version>
610 </since>
611 <synopsis>Override the various conference bridge sound files</synopsis>
612 <description><para>
613 All sounds in the conference are customizable using the bridge profile options below.
614 Simply state the option followed by the filename or full path of the filename after
615 the option. Example: <literal>sound_had_joined=conf-hasjoin</literal> This will play the <literal>conf-hasjoin</literal>
616 sound file found in the sounds directory when announcing someone's name is joining the
617 conference.</para>
618 <enumlist>
619 <enum name="sound_join"><para>The sound played to everyone when someone enters the conference.</para></enum>
620 <enum name="sound_leave"><para>The sound played to everyone when someone leaves the conference.</para></enum>
621 <enum name="sound_has_joined"><para>The sound played before announcing someone's name has
622 joined the conference. This is used for user intros.
623 Example <literal>"_____ has joined the conference"</literal></para></enum>
624 <enum name="sound_has_left"><para>The sound played when announcing someone's name has
625 left the conference. This is used for user intros.
626 Example <literal>"_____ has left the conference"</literal></para></enum>
627 <enum name="sound_kicked"><para>The sound played to a user who has been kicked from the conference.</para></enum>
628 <enum name="sound_muted"><para>The sound played when the mute option it toggled on.</para></enum>
629 <enum name="sound_unmuted"><para>The sound played when the mute option it toggled off.</para></enum>
630 <enum name="sound_binaural_on"><para>The sound played when binaural audio is turned on.</para></enum>
631 <enum name="sound_binaural_off"><para>The sound played when the binaural audio is turned off.</para></enum>
632 <enum name="sound_only_person"><para>The sound played when the user is the only person in the conference.</para></enum>
633 <enum name="sound_only_one"><para>The sound played to a user when there is only one other
634 person is in the conference.</para></enum>
635 <enum name="sound_there_are"><para>The sound played when announcing how many users there
636 are in a conference.</para></enum>
637 <enum name="sound_other_in_party"><para>This file is used in conjunction with <literal>sound_there_are</literal>
638 when announcing how many users there are in the conference.
639 The sounds are stringed together like this.
640 <literal>"sound_there_are" ${number of participants} "sound_other_in_party"</literal></para></enum>
641 <enum name="sound_place_into_conference"><para>The sound played when someone is placed into the conference
642 after waiting for a marked user.</para></enum>
643 <enum name="sound_wait_for_leader"><para>The sound played when a user is placed into a conference that
644 can not start until a marked user enters.</para></enum>
645 <enum name="sound_leader_has_left"><para>The sound played when the last marked user leaves the conference.</para></enum>
646 <enum name="sound_get_pin"><para>The sound played when prompting for a conference pin number.</para></enum>
647 <enum name="sound_invalid_pin"><para>The sound played when an invalid pin is entered too many times.</para></enum>
648 <enum name="sound_locked"><para>The sound played to a user trying to join a locked conference.</para></enum>
649 <enum name="sound_locked_now"><para>The sound played to an admin after toggling the conference to locked mode.</para></enum>
650 <enum name="sound_unlocked_now"><para>The sound played to an admin after toggling the conference to unlocked mode.</para></enum>
651 <enum name="sound_error_menu"><para>The sound played when an invalid menu option is entered.</para></enum>
652 </enumlist>
653 </description>
654 </configOption>
655 <configOption name="video_update_discard" default="2000">
656 <since>
657 <version>15.0.0</version>
658 </since>
659 <synopsis>Sets the amount of time in milliseconds after sending a video update to discard subsequent video updates</synopsis>
660 <description><para>
661 Sets the amount of time in milliseconds after sending a video update request
662 that subsequent video updates should be discarded. This means that if we
663 send a video update we will discard any other video update requests until
664 after the configured amount of time has elapsed. This prevents flooding of
665 video update requests from clients.
666 </para></description>
667 </configOption>
668 <configOption name="remb_send_interval" default="0">
669 <since>
670 <version>15.4.0</version>
671 </since>
672 <synopsis>Sets the interval in milliseconds that a combined REMB frame will be sent to video sources</synopsis>
673 <description><para>
674 Sets the interval in milliseconds that a combined REMB frame will be sent
675 to video sources. This is done by taking all REMB frames that have been
676 received since the last REMB frame was sent, making a combined value,
677 and sending it to the source. A REMB frame contains receiver estimated
678 maximum bitrate information. By creating a combined REMB frame the
679 sender of video can be influenced on the bitrate they choose, allowing
680 better quality for all receivers.
681 </para></description>
682 </configOption>
683 <configOption name="remb_behavior" default="average">
684 <since>
685 <version>15.4.0</version>
686 </since>
687 <synopsis>Sets how REMB reports are generated from multiple sources</synopsis>
688 <description><para>
689 Sets how REMB reports are combined from multiple sources to form one. A REMB report
690 consists of information about the receiver estimated maximum bitrate. As a source
691 stream may be forwarded to multiple receivers the reports must be combined into
692 a single one which is sent to the sender.</para>
693 <enumlist>
694 <enum name="average">
695 <para>The average of all estimated maximum bitrates is taken and sent
696 to the sender.</para>
697 </enum>
698 <enum name="lowest">
699 <para>The lowest estimated maximum bitrate is forwarded to the sender.</para>
700 </enum>
701 <enum name="highest">
702 <para>The highest estimated maximum bitrate is forwarded to the sender.</para>
703 </enum>
704 <enum name="average_all">
705 <para>The average of all estimated maximum bitrates is taken from all
706 receivers in the bridge and a single value is sent to each sender.</para>
707 </enum>
708 <enum name="lowest_all">
709 <para>The lowest estimated maximum bitrate of all receivers in the bridge
710 is taken and sent to each sender.</para>
711 </enum>
712 <enum name="highest_all">
713 <para>The highest estimated maximum bitrate of all receivers in the bridge
714 is taken and sent to each sender.</para>
715 </enum>
716 <enum name="force">
717 <para>The bitrate configured in <literal>remb_estimated_bitrate</literal>
718 is sent to each sender.</para>
719 </enum>
720 </enumlist>
721 </description>
722 <see-also><ref type="configOption">remb_estimated_bitrate</ref></see-also>
723 </configOption>
724 <configOption name="remb_estimated_bitrate">
725 <since>
726 <version>16.15.0</version>
727 <version>17.9.0</version>
728 <version>18.1.0</version>
729 </since>
730 <synopsis>Sets the estimated bitrate sent to each participant in REMB reports</synopsis>
731 <description><para>
732 When <literal>remb_behavior</literal> is set to <literal>force</literal>,
733 this options sets the estimated bitrate (in bits per second) sent to each participant
734 in REMB reports.
735 </para></description>
736 <see-also><ref type="configOption">remb_behavior</ref></see-also>
737 </configOption>
738 <configOption name="enable_events" default="no">
739 <since>
740 <version>15.5.0</version>
741 </since>
742 <synopsis>Enables events for this bridge</synopsis>
743 <description><para>
744 If enabled, recipients who joined the bridge via a channel driver
745 that supports Enhanced Messaging (currently only chan_pjsip) will
746 receive in-dialog messages containing a JSON body describing the
747 event. The Content-Type header will be
748 <literal>text/x-ast-confbridge-event</literal>.
749 This feature must also be enabled in user profiles.</para>
750 </description>
751 </configOption>
752 <configOption name="template">
753 <since>
754 <version>11.0.0</version>
755 </since>
756 <synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
757 </configOption>
758 </configObject>
759 <configObject name="menu">
760 <since>
761 <version>12.0.0</version>
762 </since>
763 <synopsis>A conference user menu</synopsis>
764 <description>
765 <para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
766 can have a DTMF menu assigned to their profile when they enter the
767 <literal>ConfBridge</literal> application.</para>
768 </description>
769 <configOption name="type">
770 <since>
771 <version>12.0.0</version>
772 </since>
773 <synopsis>Define this configuration category as a menu</synopsis>
774 <description><para>The type parameter determines how a context in the
775 configuration file is interpreted.</para>
776 <enumlist>
777 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
778 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
779 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
780 </enumlist>
781 </description>
782 </configOption>
783 <configOption name="template">
784 <since>
785 <version>13.0.0</version>
786 </since>
787 <synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
788 </configOption>
789 <configOption name="^[0-9A-D*#]+$">
790 <synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
791 <description>
792 <para>The ConfBridge application also has the ability to apply custom DTMF menus to
793 each channel using the application. Like the User and Bridge profiles a menu
794 is passed in to ConfBridge as an argument in the dialplan.</para>
795 <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
796 <note><para>
797 To have the first DTMF digit in a sequence be the '#' character, you need to
798 escape it. If it is not escaped then normal config file processing will
799 think it is a directive like #include. For example: The mute setting is
800 toggled when <literal>#1</literal> is pressed.</para>
801 <para><literal>\#1=toggle_mute</literal></para>
802 </note>
803 <note><para>
804 A single DTMF sequence can have multiple actions associated with it. This is
805 accomplished by stringing the actions together and using a <literal>,</literal> as the
806 delimiter. Example: Both listening and talking volume is reset when <literal>5</literal> is
807 pressed. <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
808 <enumlist>
809 <enum name="playback(filename&amp;filename2&amp;...)"><para>
810 <literal>playback</literal> will play back an audio file to a channel
811 and then immediately return to the conference.
812 This file can not be interupted by DTMF.
813 Multiple files can be chained together using the
814 <literal>&amp;</literal> character.</para></enum>
815 <enum name="playback_and_continue(filename&amp;filename2&amp;...)"><para>
816 <literal>playback_and_continue</literal> will
817 play back a prompt while continuing to
818 collect the dtmf sequence. This is useful
819 when using a menu prompt that describes all
820 the menu options. Note however that any DTMF
821 during this action will terminate the prompts
822 playback. Prompt files can be chained together
823 using the <literal>&amp;</literal> character as a delimiter.</para></enum>
824 <enum name="toggle_mute"><para>
825 Toggle turning on and off mute. Mute will make the user silent
826 to everyone else, but the user will still be able to listen in.
827 </para></enum>
828 <enum name="toggle_binaural"><para>
829 Toggle turning on and off binaural audio processing.
830 </para></enum>
831 <enum name="no_op"><para>
832 This action does nothing (No Operation). Its only real purpose exists for
833 being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
834 <enum name="decrease_listening_volume"><para>
835 Decreases the channel's listening volume.</para></enum>
836 <enum name="increase_listening_volume"><para>
837 Increases the channel's listening volume.</para></enum>
838 <enum name="reset_listening_volume"><para>
839 Reset channel's listening volume to default level.</para></enum>
840 <enum name="decrease_talking_volume"><para>
841 Decreases the channel's talking volume.</para></enum>
842 <enum name="increase_talking_volume"><para>
843 Increases the channel's talking volume.</para></enum>
844 <enum name="reset_talking_volume"><para>
845 Reset channel's talking volume to default level.</para></enum>
846 <enum name="dialplan_exec(context,exten,priority)"><para>
847 The <literal>dialplan_exec</literal> action allows a user
848 to escape from the conference and execute
849 commands in the dialplan. Once the dialplan
850 exits the user will be put back into the
851 conference. The possibilities are endless!</para></enum>
852 <enum name="leave_conference"><para>
853 This action allows a user to exit the conference and continue
854 execution in the dialplan.</para></enum>
855 <enum name="admin_kick_last"><para>
856 This action allows an Admin to kick the last participant from the
857 conference. This action will only work for admins which allows
858 a single menu to be used for both users and admins.</para></enum>
859 <enum name="admin_toggle_conference_lock"><para>
860 This action allows an Admin to toggle locking and
861 unlocking the conference. Non admins can not use
862 this action even if it is in their menu.</para></enum>
863 <enum name="set_as_single_video_src"><para>
864 This action allows any user to set themselves as the
865 single video source distributed to all participants.
866 This will make the video feed stick to them regardless
867 of what the <literal>video_mode</literal> is set to.</para></enum>
868 <enum name="release_as_single_video_src"><para>
869 This action allows a user to release themselves as
870 the video source. If <literal>video_mode</literal> is not set to <literal>none</literal>
871 this action will result in the conference returning to
872 whatever video mode the bridge profile is using.</para>
873 <para>Note that this action will have no effect if the user
874 is not currently the video source. Also, the user is
875 not guaranteed by using this action that they will not
876 become the video source again. The bridge will return
877 to whatever operation the <literal>video_mode</literal> option is set to
878 upon release of the video src.</para></enum>
879 <enum name="admin_toggle_mute_participants"><para>
880 This action allows an administrator to toggle the mute
881 state for all non-admins within a conference. All
882 admin users are unaffected by this option. Note that all
883 users, regardless of their admin status, are notified
884 that the conference is muted.</para></enum>
885 <enum name="participant_count"><para>
886 This action plays back the number of participants currently
887 in a conference</para></enum>
888 </enumlist>
889 </description>
890 </configOption>
891 </configObject>
892 </configFile>
893 </configInfo>
894***/
895
900};
901
902static int verify_default_profiles(void);
903static void *bridge_profile_alloc(const char *category);
904static void *bridge_profile_find(struct ao2_container *container, const char *category);
906
907static void bridge_profile_destructor(void *obj)
908{
909 struct bridge_profile *b_profile = obj;
910 ao2_cleanup(b_profile->sounds);
911}
912
913static void *bridge_profile_alloc(const char *category)
914{
915 struct bridge_profile *b_profile;
916
917 if (!(b_profile = ao2_alloc(sizeof(*b_profile), bridge_profile_destructor))) {
918 return NULL;
919 }
920
921 if (!(b_profile->sounds = bridge_profile_sounds_alloc())) {
922 ao2_ref(b_profile, -1);
923 return NULL;
924 }
925
926 ast_copy_string(b_profile->name, category, sizeof(b_profile->name));
927
928 return b_profile;
929}
930
931static void *bridge_profile_find(struct ao2_container *container, const char *category)
932{
933 return ao2_find(container, category, OBJ_KEY);
934}
935
936static struct aco_type bridge_type = {
937 .type = ACO_ITEM,
938 .name = "bridge_profile",
939 .category_match = ACO_BLACKLIST_EXACT,
940 .category = "general",
941 .matchfield = "type",
942 .matchvalue = "bridge",
943 .item_alloc = bridge_profile_alloc,
944 .item_find = bridge_profile_find,
945 .item_offset = offsetof(struct confbridge_cfg, bridge_profiles),
946};
947
948static void *user_profile_alloc(const char *category);
949static void *user_profile_find(struct ao2_container *container, const char *category);
950static void user_profile_destructor(void *obj)
951{
952 return;
953}
954
955static void *user_profile_alloc(const char *category)
956{
957 struct user_profile *u_profile;
958
959 if (!(u_profile = ao2_alloc(sizeof(*u_profile), user_profile_destructor))) {
960 return NULL;
961 }
962
963 ast_copy_string(u_profile->name, category, sizeof(u_profile->name));
964
965 return u_profile;
966}
967
968static void *user_profile_find(struct ao2_container *container, const char *category)
969{
970 return ao2_find(container, category, OBJ_KEY);
971}
972
973static struct aco_type user_type = {
974 .type = ACO_ITEM,
975 .name = "user_profile",
976 .category_match = ACO_BLACKLIST_EXACT,
977 .category = "general",
978 .matchfield = "type",
979 .matchvalue = "user",
980 .item_alloc = user_profile_alloc,
981 .item_find = user_profile_find,
982 .item_offset = offsetof(struct confbridge_cfg, user_profiles),
983};
984
985static void *menu_alloc(const char *category);
986static void *menu_find(struct ao2_container *container, const char *category);
987static void menu_destructor(void *obj);
988
989static void *menu_alloc(const char *category)
990{
991 struct conf_menu *menu;
992 if (!(menu = ao2_alloc(sizeof(*menu), menu_destructor))) {
993 return NULL;
994 }
995 ast_copy_string(menu->name, category, sizeof(menu->name));
996 return menu;
997}
998
999static void *menu_find(struct ao2_container *container, const char *category)
1000{
1001 return ao2_find(container, category, OBJ_KEY);
1002}
1003
1004static struct aco_type menu_type = {
1005 .type = ACO_ITEM,
1006 .name = "menu",
1007 .category_match = ACO_BLACKLIST_EXACT,
1008 .category = "general",
1009 .matchfield = "type",
1010 .matchvalue = "menu",
1011 .item_alloc = menu_alloc,
1012 .item_find = menu_find,
1013 .item_offset = offsetof(struct confbridge_cfg, menus),
1014};
1015
1016/* Used to pass to aco_option_register */
1020
1021/* The general category is reserved, but unused */
1022static struct aco_type general_type = {
1023 .type = ACO_GLOBAL,
1024 .name = "global",
1025 .category_match = ACO_WHITELIST_EXACT,
1026 .category = "general",
1027};
1028
1029static struct aco_file confbridge_conf = {
1030 .filename = "confbridge.conf",
1032};
1033
1035
1036static void *confbridge_cfg_alloc(void);
1037
1039 .files = ACO_FILES(&confbridge_conf),
1040 .pre_apply_config = verify_default_profiles,
1041);
1042
1043/*! bridge profile container functions */
1044static int bridge_cmp_cb(void *obj, void *arg, int flags)
1045{
1046 const struct bridge_profile *left = obj;
1047 const struct bridge_profile *right = arg;
1048 const char *right_name = arg;
1049 int cmp;
1050
1051 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1052 default:
1053 case OBJ_POINTER:
1054 right_name = right->name;
1055 /* Fall through */
1056 case OBJ_KEY:
1057 cmp = strcasecmp(left->name, right_name);
1058 break;
1059 case OBJ_PARTIAL_KEY:
1060 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1061 break;
1062 }
1063 return cmp ? 0 : CMP_MATCH;
1064}
1065
1066static int bridge_hash_cb(const void *obj, const int flags)
1067{
1068 const struct bridge_profile *b_profile = obj;
1069 const char *name = obj;
1070 int hash;
1071
1072 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1073 default:
1074 case OBJ_POINTER:
1075 name = b_profile->name;
1076 /* Fall through */
1077 case OBJ_KEY:
1078 hash = ast_str_case_hash(name);
1079 break;
1080 case OBJ_PARTIAL_KEY:
1081 /* Should never happen in hash callback. */
1082 ast_assert(0);
1083 hash = 0;
1084 break;
1085 }
1086 return hash;
1087}
1088
1089/*! menu container functions */
1090static int menu_cmp_cb(void *obj, void *arg, int flags)
1091{
1092 const struct conf_menu *left = obj;
1093 const struct conf_menu *right = arg;
1094 const char *right_name = arg;
1095 int cmp;
1096
1097 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1098 default:
1099 case OBJ_POINTER:
1100 right_name = right->name;
1101 /* Fall through */
1102 case OBJ_KEY:
1103 cmp = strcasecmp(left->name, right_name);
1104 break;
1105 case OBJ_PARTIAL_KEY:
1106 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1107 break;
1108 }
1109 return cmp ? 0 : CMP_MATCH;
1110}
1111
1112static int menu_hash_cb(const void *obj, const int flags)
1113{
1114 const struct conf_menu *menu = obj;
1115 const char *name = obj;
1116 int hash;
1117
1118 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1119 default:
1120 case OBJ_POINTER:
1121 name = menu->name;
1122 /* Fall through */
1123 case OBJ_KEY:
1124 hash = ast_str_case_hash(name);
1125 break;
1126 case OBJ_PARTIAL_KEY:
1127 /* Should never happen in hash callback. */
1128 ast_assert(0);
1129 hash = 0;
1130 break;
1131 }
1132 return hash;
1133}
1134
1135static void menu_destructor(void *obj)
1136{
1137 struct conf_menu *menu = obj;
1138 struct conf_menu_entry *entry = NULL;
1139
1140 while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
1142 ast_free(entry);
1143 }
1144}
1145
1146/*! User profile container functions */
1147static int user_cmp_cb(void *obj, void *arg, int flags)
1148{
1149 const struct user_profile *left = obj;
1150 const struct user_profile *right = arg;
1151 const char *right_name = arg;
1152 int cmp;
1153
1154 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1155 default:
1156 case OBJ_POINTER:
1157 right_name = right->name;
1158 /* Fall through */
1159 case OBJ_KEY:
1160 cmp = strcasecmp(left->name, right_name);
1161 break;
1162 case OBJ_PARTIAL_KEY:
1163 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1164 break;
1165 }
1166 return cmp ? 0 : CMP_MATCH;
1167}
1168
1169static int user_hash_cb(const void *obj, const int flags)
1170{
1171 const struct user_profile *u_profile = obj;
1172 const char *name = obj;
1173 int hash;
1174
1175 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1176 default:
1177 case OBJ_POINTER:
1178 name = u_profile->name;
1179 /* Fall through */
1180 case OBJ_KEY:
1181 hash = ast_str_case_hash(name);
1182 break;
1183 case OBJ_PARTIAL_KEY:
1184 /* Should never happen in hash callback. */
1185 ast_assert(0);
1186 hash = 0;
1187 break;
1188 }
1189 return hash;
1190}
1191
1192/*! Bridge Profile Sounds functions */
1194{
1195 struct bridge_profile_sounds *sounds = obj;
1197}
1198
1200{
1202
1203 if (!sounds) {
1204 return NULL;
1205 }
1206 if (ast_string_field_init(sounds, 512)) {
1207 ao2_ref(sounds, -1);
1208 return NULL;
1209 }
1210
1211 return sounds;
1212}
1213
1214static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
1215{
1216 struct bridge_profile_sounds *sounds = b_profile->sounds;
1217 if (ast_strlen_zero(sound_file)) {
1218 return -1;
1219 }
1220
1221 if (!strcasecmp(sound_name, "sound_only_person")) {
1223 } else if (!strcasecmp(sound_name, "sound_only_one")) {
1224 ast_string_field_set(sounds, onlyone, sound_file);
1225 } else if (!strcasecmp(sound_name, "sound_has_joined")) {
1226 ast_string_field_set(sounds, hasjoin, sound_file);
1227 } else if (!strcasecmp(sound_name, "sound_has_left")) {
1228 ast_string_field_set(sounds, hasleft, sound_file);
1229 } else if (!strcasecmp(sound_name, "sound_kicked")) {
1230 ast_string_field_set(sounds, kicked, sound_file);
1231 } else if (!strcasecmp(sound_name, "sound_muted")) {
1232 ast_string_field_set(sounds, muted, sound_file);
1233 } else if (!strcasecmp(sound_name, "sound_unmuted")) {
1234 ast_string_field_set(sounds, unmuted, sound_file);
1235 } else if (!strcasecmp(sound_name, "sound_binaural_on")) {
1237 } else if (!strcasecmp(sound_name, "sound_binaural_off")) {
1239 } else if (!strcasecmp(sound_name, "sound_there_are")) {
1240 ast_string_field_set(sounds, thereare, sound_file);
1241 } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
1243 } else if (!strcasecmp(sound_name, "sound_place_into_conference")) {
1244 static int deprecation_warning = 1;
1245 if (deprecation_warning) {
1246 ast_log(LOG_WARNING, "sound_place_into_conference is deprecated"
1247 " and unused. Use sound_begin for similar functionality.");
1248 deprecation_warning = 0;
1249 }
1251 } else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
1253 } else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
1255 } else if (!strcasecmp(sound_name, "sound_get_pin")) {
1256 ast_string_field_set(sounds, getpin, sound_file);
1257 } else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
1259 } else if (!strcasecmp(sound_name, "sound_locked")) {
1260 ast_string_field_set(sounds, locked, sound_file);
1261 } else if (!strcasecmp(sound_name, "sound_unlocked_now")) {
1263 } else if (!strcasecmp(sound_name, "sound_locked_now")) {
1265 } else if (!strcasecmp(sound_name, "sound_error_menu")) {
1267 } else if (!strcasecmp(sound_name, "sound_join")) {
1268 ast_string_field_set(sounds, join, sound_file);
1269 } else if (!strcasecmp(sound_name, "sound_leave")) {
1270 ast_string_field_set(sounds, leave, sound_file);
1271 } else if (!strcasecmp(sound_name, "sound_participants_muted")) {
1273 } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) {
1275 } else if (!strcasecmp(sound_name, "sound_begin")) {
1276 ast_string_field_set(sounds, begin, sound_file);
1277 } else {
1278 return -1;
1279 }
1280
1281 return 0;
1282}
1283
1284/*! CONFBRIDGE dialplan function functions and channel datastore. */
1289 unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
1290 unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
1291 unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
1292};
1293
1295{
1297 ao2_cleanup(b_data->menu);
1298 ast_free(b_data);
1299}
1300
1301static void func_confbridge_destroy_cb(void *data)
1302{
1303 struct func_confbridge_data *b_data = data;
1305};
1306
1308 .type = "confbridge",
1310};
1311
1312int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1313{
1314 struct ast_datastore *datastore;
1315 struct func_confbridge_data *b_data;
1316 char *parse;
1317 struct ast_variable tmpvar = { 0, };
1318 struct ast_variable template = {
1319 .name = "template",
1320 .file = "CONFBRIDGE"
1321 };
1324 AST_APP_ARG(option);
1325 );
1326
1327 if (!chan) {
1328 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1329 return -1;
1330 }
1331
1332 /* parse all the required arguments and make sure they exist. */
1333 if (ast_strlen_zero(data)) {
1334 return -1;
1335 }
1336 parse = ast_strdupa(data);
1338 if (ast_strlen_zero(args.type) || ast_strlen_zero(args.option)) {
1339 return -1;
1340 }
1341
1342 ast_channel_lock(chan);
1344 if (!datastore) {
1346 if (!datastore) {
1347 ast_channel_unlock(chan);
1348 return 0;
1349 }
1350 b_data = ast_calloc(1, sizeof(*b_data));
1351 if (!b_data) {
1352 ast_channel_unlock(chan);
1353 ast_datastore_free(datastore);
1354 return 0;
1355 }
1356 datastore->data = b_data;
1358 if (!b_data->b_profile.sounds) {
1359 ast_channel_unlock(chan);
1360 ast_datastore_free(datastore);
1361 return 0;
1362 }
1363 if (!(b_data->menu = menu_alloc("dialplan"))) {
1364 ast_channel_unlock(chan);
1365 ast_datastore_free(datastore);
1366 return 0;
1367 }
1368 ast_channel_datastore_add(chan, datastore);
1369 } else {
1370 b_data = datastore->data;
1371 }
1372 ast_channel_unlock(chan);
1373
1374 /* SET(CONFBRIDGE(type,option)=value) */
1375 if (!value) {
1376 value = "";
1377 }
1378 tmpvar.name = args.option;
1379 tmpvar.value = value;
1380 tmpvar.file = "CONFBRIDGE";
1381 if (!strcasecmp(args.type, "bridge")) {
1382 if (!strcasecmp(args.option, "clear")) {
1383 b_data->b_usable = 0;
1385 memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
1386 if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
1387 /* If this reallocation fails, the datastore has become unusable and must be destroyed. */
1388 ast_channel_lock(chan);
1389 ast_channel_datastore_remove(chan, datastore);
1390 ast_channel_unlock(chan);
1391 ast_datastore_free(datastore);
1392 }
1393 return 0;
1394 }
1395
1396 if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
1397 template.value = DEFAULT_BRIDGE_PROFILE;
1398 aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
1399 }
1400
1401 if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
1402 b_data->b_usable = 1;
1403 return 0;
1404 }
1405 } else if (!strcasecmp(args.type, "user")) {
1406 if (!strcasecmp(args.option, "clear")) {
1407 b_data->u_usable = 0;
1409 memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
1410 return 0;
1411 }
1412
1413 if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
1414 template.value = DEFAULT_USER_PROFILE;
1415 aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
1416 }
1417
1418 if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
1419 b_data->u_usable = 1;
1420 return 0;
1421 }
1422 } else if (!strcasecmp(args.type, "menu")) {
1423 if (!strcasecmp(args.option, "clear")) {
1424 b_data->m_usable = 0;
1425 ao2_cleanup(b_data->menu);
1426 if (!(b_data->menu = menu_alloc("dialplan"))) {
1427 /* If this reallocation fails, the datastore has become unusable and must be destroyed */
1428 ast_channel_lock(chan);
1429 ast_channel_datastore_remove(chan, datastore);
1430 ast_channel_unlock(chan);
1431 ast_datastore_free(datastore);
1432 }
1433 return 0;
1434 }
1435
1436 if (b_data && !b_data->m_usable && strcasecmp(args.option, "template")) {
1437 template.value = DEFAULT_MENU_PROFILE;
1438 aco_process_var(&menu_type, "dialplan", &template, &b_data->menu);
1439 }
1440
1441 if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
1442 b_data->m_usable = 1;
1443 return 0;
1444 }
1445 }
1446
1447 ast_log(LOG_WARNING, "%s(%s,%s) cannot be set to '%s'. Invalid type, option, or value.\n",
1448 cmd, args.type, args.option, value);
1449 return -1;
1450}
1451
1452static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
1453{
1454 struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
1455
1456 if (!menu_action) {
1457 return -1;
1458 }
1459 menu_action->id = id;
1460
1461 switch (id) {
1462 case MENU_ACTION_NOOP:
1475 case MENU_ACTION_LEAVE:
1478 break;
1481 if (!(ast_strlen_zero(databuf))) {
1482 ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
1483 } else {
1484 ast_free(menu_action);
1485 return -1;
1486 }
1487 break;
1489 if (!(ast_strlen_zero(databuf))) {
1492 AST_APP_ARG(exten);
1494 );
1495 AST_STANDARD_APP_ARGS(args, databuf);
1496 if (!ast_strlen_zero(args.context)) {
1498 args.context,
1499 sizeof(menu_action->data.dialplan_args.context));
1500 }
1501 if (!ast_strlen_zero(args.exten)) {
1503 args.exten,
1504 sizeof(menu_action->data.dialplan_args.exten));
1505 }
1506 menu_action->data.dialplan_args.priority = 1; /* 1 by default */
1507 if (!ast_strlen_zero(args.priority) &&
1508 (sscanf(args.priority, "%30d", &menu_action->data.dialplan_args.priority) != 1)) {
1509 /* invalid priority */
1510 ast_free(menu_action);
1511 return -1;
1512 }
1513 } else {
1514 ast_free(menu_action);
1515 return -1;
1516 }
1517 };
1518
1519 AST_LIST_INSERT_TAIL(&menu_entry->actions, menu_action, action);
1520
1521 return 0;
1522}
1523
1524static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
1525{
1526 struct conf_menu_entry *menu_entry = NULL, *cur = NULL;
1527 int res = 0;
1528 char *tmp_action_names = ast_strdupa(action_names);
1529 char *action = NULL;
1530 char *action_args;
1531 char *tmp;
1532 char buf[PATH_MAX];
1533 char *delimiter = ",";
1534
1535 if (!(menu_entry = ast_calloc(1, sizeof(*menu_entry)))) {
1536 return -1;
1537 }
1538
1539 for (;;) {
1540 char *comma;
1541 char *startbrace;
1542 char *endbrace;
1543 unsigned int action_len;
1544
1545 if (ast_strlen_zero(tmp_action_names)) {
1546 break;
1547 }
1548 startbrace = strchr(tmp_action_names, '(');
1549 endbrace = strchr(tmp_action_names, ')');
1550 comma = strchr(tmp_action_names, ',');
1551
1552 /* If the next action has brackets with comma delimited arguments in it,
1553 * make the delimeter ')' instead of a comma to preserve the arguments */
1554 if (startbrace && endbrace && comma && (comma > startbrace && comma < endbrace)) {
1555 delimiter = ")";
1556 } else {
1557 delimiter = ",";
1558 }
1559
1560 if (!(action = strsep(&tmp_action_names, delimiter))) {
1561 break;
1562 }
1563
1564 action = ast_strip(action);
1565 if (ast_strlen_zero(action)) {
1566 continue;
1567 }
1568
1569 action_len = strlen(action);
1570 ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
1571 if (!strcasecmp(action, "toggle_mute")) {
1573 } else if (!strcasecmp(action, "toggle_binaural")) {
1575 } else if (!strcasecmp(action, "no_op")) {
1576 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL);
1577 } else if (!strcasecmp(action, "increase_listening_volume")) {
1579 } else if (!strcasecmp(action, "decrease_listening_volume")) {
1581 } else if (!strcasecmp(action, "increase_talking_volume")) {
1583 } else if (!strcasecmp(action, "reset_listening_volume")) {
1585 } else if (!strcasecmp(action, "reset_talking_volume")) {
1587 } else if (!strcasecmp(action, "decrease_talking_volume")) {
1589 } else if (!strcasecmp(action, "admin_toggle_conference_lock")) {
1591 } else if (!strcasecmp(action, "admin_toggle_mute_participants")) {
1593 } else if (!strcasecmp(action, "participant_count")) {
1595 } else if (!strcasecmp(action, "admin_kick_last")) {
1597 } else if (!strcasecmp(action, "leave_conference")) {
1598 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL);
1599 } else if (!strcasecmp(action, "set_as_single_video_src")) {
1601 } else if (!strcasecmp(action, "release_as_single_video_src")) {
1603 } else if (!strncasecmp(action, "dialplan_exec(", 14)) {
1604 ast_copy_string(buf, action, sizeof(buf));
1605 action_args = buf;
1606 if ((action_args = strchr(action, '('))) {
1607 action_args++;
1608 }
1609 /* it is possible that this argument may or may not
1610 * have a closing brace at this point, it all depends on if
1611 * comma delimited arguments were provided */
1612 if ((tmp = strchr(action, ')'))) {
1613 *tmp = '\0';
1614 }
1615 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DIALPLAN_EXEC, action_args);
1616 } else if (action_len >= 21 && !strncasecmp(action, "playback_and_continue(", 22)) {
1617 ast_copy_string(buf, action, sizeof(buf));
1618 action_args = buf;
1619 if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1620 *tmp = '\0';
1621 action_args++;
1622 }
1623 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK_AND_CONTINUE, action_args);
1624 } else if (action_len >= 8 && !strncasecmp(action, "playback(", 9)) {
1625 ast_copy_string(buf, action, sizeof(buf));
1626 action_args = buf;
1627 if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1628 *tmp = '\0';
1629 action_args++;
1630 }
1631 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, action_args);
1632 }
1633 }
1634
1635 /* if adding any of the actions failed, bail */
1636 if (res) {
1637 conf_menu_entry_destroy(menu_entry);
1638 ast_free(menu_entry);
1639 return -1;
1640 }
1641
1642 /* remove any list entry with an identical DTMF sequence for overrides */
1643 AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
1644 if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
1647 ast_free(cur);
1648 break;
1649 }
1650 }
1652
1653 AST_LIST_INSERT_TAIL(&menu->entries, menu_entry, entry);
1654
1655 return 0;
1656}
1657
1658static char *complete_user_profile_name(const char *line, const char *word, int pos, int state)
1659{
1660 int which = 0;
1661 char *res = NULL;
1662 int wordlen = strlen(word);
1663 struct ao2_iterator i;
1664 struct user_profile *u_profile = NULL;
1666
1667 if (!cfg) {
1668 return NULL;
1669 }
1670
1671 i = ao2_iterator_init(cfg->user_profiles, 0);
1672 while ((u_profile = ao2_iterator_next(&i))) {
1673 if (!strncasecmp(u_profile->name, word, wordlen) && ++which > state) {
1674 res = ast_strdup(u_profile->name);
1675 ao2_ref(u_profile, -1);
1676 break;
1677 }
1678 ao2_ref(u_profile, -1);
1679 }
1681
1682 return res;
1683}
1684
1686{
1687 struct ao2_iterator it;
1688 struct user_profile *u_profile;
1689 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1690
1691 switch (cmd) {
1692 case CLI_INIT:
1693 e->command = "confbridge show profile users";
1694 e->usage =
1695 "Usage: confbridge show profile users\n";
1696 return NULL;
1697 case CLI_GENERATE:
1698 return NULL;
1699 }
1700
1701 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1702 return NULL;
1703 }
1704
1705 ast_cli(a->fd,"--------- User Profiles -----------\n");
1706 ao2_lock(cfg->user_profiles);
1707 it = ao2_iterator_init(cfg->user_profiles, 0);
1708 while ((u_profile = ao2_iterator_next(&it))) {
1709 ast_cli(a->fd,"%s\n", u_profile->name);
1710 ao2_ref(u_profile, -1);
1711 }
1713 ao2_unlock(cfg->user_profiles);
1714
1715 return CLI_SUCCESS;
1716}
1718{
1719 struct user_profile u_profile;
1720
1721 switch (cmd) {
1722 case CLI_INIT:
1723 e->command = "confbridge show profile user";
1724 e->usage =
1725 "Usage: confbridge show profile user [<profile name>]\n";
1726 return NULL;
1727 case CLI_GENERATE:
1728 if (a->pos == 4) {
1729 return complete_user_profile_name(a->line, a->word, a->pos, a->n);
1730 }
1731 return NULL;
1732 }
1733
1734 if (a->argc != 5) {
1735 return CLI_SHOWUSAGE;
1736 }
1737
1738 if (!(conf_find_user_profile(NULL, a->argv[4], &u_profile))) {
1739 ast_cli(a->fd, "No conference user profile named '%s' found!\n", a->argv[4]);
1740 return CLI_SUCCESS;
1741 }
1742
1743 ast_cli(a->fd,"--------------------------------------------\n");
1744 ast_cli(a->fd,"Name: %s\n",
1745 u_profile.name);
1746 ast_cli(a->fd,"Admin: %s\n",
1747 u_profile.flags & USER_OPT_ADMIN ?
1748 "true" : "false");
1749 ast_cli(a->fd,"Send Events: %s\n",
1750 u_profile.flags & USER_OPT_SEND_EVENTS ?
1751 "true" : "false");
1752 ast_cli(a->fd,"Echo Events: %s\n",
1753 u_profile.flags & USER_OPT_ECHO_EVENTS ?
1754 "true" : "false");
1755 ast_cli(a->fd,"Marked User: %s\n",
1756 u_profile.flags & USER_OPT_MARKEDUSER ?
1757 "true" : "false");
1758 ast_cli(a->fd,"Start Muted: %s\n",
1759 u_profile.flags & USER_OPT_STARTMUTED?
1760 "true" : "false");
1761 ast_cli(a->fd,"MOH When Empty: %s\n",
1762 u_profile.flags & USER_OPT_MUSICONHOLD ?
1763 "enabled" : "disabled");
1764 ast_cli(a->fd,"MOH Class: %s\n",
1765 ast_strlen_zero(u_profile.moh_class) ?
1766 "default" : u_profile.moh_class);
1767 ast_cli(a->fd,"Announcement: %s\n",
1768 u_profile.announcement);
1769 ast_cli(a->fd,"Quiet: %s\n",
1770 u_profile.flags & USER_OPT_QUIET ?
1771 "enabled" : "disabled");
1772 ast_cli(a->fd,"Hear Join: %s\n",
1774 "enabled" : "disabled");
1775 ast_cli(a->fd,"Wait Marked: %s\n",
1776 u_profile.flags & USER_OPT_WAITMARKED ?
1777 "enabled" : "disabled");
1778 ast_cli(a->fd,"END Marked (All): %s\n",
1779 u_profile.flags & USER_OPT_ENDMARKED ?
1780 "enabled" : "disabled");
1781 ast_cli(a->fd,"END Marked (Any): %s\n",
1782 u_profile.flags & USER_OPT_ENDMARKEDANY ?
1783 "enabled" : "disabled");
1784 ast_cli(a->fd,"Drop_silence: %s\n",
1785 u_profile.flags & USER_OPT_DROP_SILENCE ?
1786 "enabled" : "disabled");
1787 ast_cli(a->fd,"Silence Threshold: %ums\n",
1788 u_profile.silence_threshold);
1789 ast_cli(a->fd,"Talking Threshold: %u\n",
1790 u_profile.talking_threshold);
1791 ast_cli(a->fd,"Denoise: %s\n",
1792 u_profile.flags & USER_OPT_DENOISE ?
1793 "enabled" : "disabled");
1794 ast_cli(a->fd,"Jitterbuffer: %s\n",
1795 u_profile.flags & USER_OPT_JITTERBUFFER ?
1796 "enabled" : "disabled");
1797 ast_cli(a->fd,"Talk Detect Events: %s\n",
1798 u_profile.flags & USER_OPT_TALKER_DETECT ?
1799 "enabled" : "disabled");
1800 ast_cli(a->fd,"DTMF Pass Through: %s\n",
1801 u_profile.flags & USER_OPT_DTMF_PASS ?
1802 "enabled" : "disabled");
1803 ast_cli(a->fd,"PIN: %s\n",
1804 ast_strlen_zero(u_profile.pin) ?
1805 "None" : u_profile.pin);
1806 ast_cli(a->fd,"Announce User Count: %s\n",
1807 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
1808 "enabled" : "disabled");
1809 ast_cli(a->fd,"Announce join/leave: %s\n",
1812 "enabled (with review)" : "enabled" : "disabled");
1813 ast_cli(a->fd,"Announce User Count all: %s\n",
1815 "enabled" : "disabled");
1816 ast_cli(a->fd,"Text Messaging: %s\n",
1817 u_profile.flags & USER_OPT_TEXT_MESSAGING ?
1818 "enabled" : "disabled");
1819 ast_cli(a->fd,"Answer Channel: %s\n",
1820 u_profile.flags & USER_OPT_ANSWER_CHANNEL ?
1821 "true" : "false");
1822 ast_cli(a->fd, "\n");
1823
1824 return CLI_SUCCESS;
1825}
1826
1827static char *complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
1828{
1829 int which = 0;
1830 char *res = NULL;
1831 int wordlen = strlen(word);
1832 struct ao2_iterator i;
1833 struct bridge_profile *b_profile = NULL;
1835
1836 if (!cfg) {
1837 return NULL;
1838 }
1839
1840 i = ao2_iterator_init(cfg->bridge_profiles, 0);
1841 while ((b_profile = ao2_iterator_next(&i))) {
1842 if (!strncasecmp(b_profile->name, word, wordlen) && ++which > state) {
1843 res = ast_strdup(b_profile->name);
1844 ao2_ref(b_profile, -1);
1845 break;
1846 }
1847 ao2_ref(b_profile, -1);
1848 }
1850
1851 return res;
1852}
1853
1855{
1856 struct ao2_iterator it;
1857 struct bridge_profile *b_profile;
1858 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1859
1860 switch (cmd) {
1861 case CLI_INIT:
1862 e->command = "confbridge show profile bridges";
1863 e->usage =
1864 "Usage: confbridge show profile bridges\n";
1865 return NULL;
1866 case CLI_GENERATE:
1867 return NULL;
1868 }
1869
1870 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1871 return NULL;
1872 }
1873
1874 ast_cli(a->fd,"--------- Bridge Profiles -----------\n");
1875 ao2_lock(cfg->bridge_profiles);
1876 it = ao2_iterator_init(cfg->bridge_profiles, 0);
1877 while ((b_profile = ao2_iterator_next(&it))) {
1878 ast_cli(a->fd,"%s\n", b_profile->name);
1879 ao2_ref(b_profile, -1);
1880 }
1882 ao2_unlock(cfg->bridge_profiles);
1883
1884 return CLI_SUCCESS;
1885}
1886
1888{
1889 struct bridge_profile b_profile;
1890 char tmp[64];
1891
1892 switch (cmd) {
1893 case CLI_INIT:
1894 e->command = "confbridge show profile bridge";
1895 e->usage =
1896 "Usage: confbridge show profile bridge <profile name>\n";
1897 return NULL;
1898 case CLI_GENERATE:
1899 if (a->pos == 4) {
1900 return complete_bridge_profile_name(a->line, a->word, a->pos, a->n);
1901 }
1902 return NULL;
1903 }
1904
1905 if (a->argc != 5) {
1906 return CLI_SHOWUSAGE;
1907 }
1908
1909 if (!(conf_find_bridge_profile(NULL, a->argv[4], &b_profile))) {
1910 ast_cli(a->fd, "No conference bridge profile named '%s' found!\n", a->argv[4]);
1911 return CLI_SUCCESS;
1912 }
1913
1914 ast_cli(a->fd,"--------------------------------------------\n");
1915 ast_cli(a->fd,"Name: %s\n", b_profile.name);
1916 ast_cli(a->fd,"Language: %s\n", b_profile.language);
1917
1918 if (b_profile.internal_sample_rate) {
1919 snprintf(tmp, sizeof(tmp), "%u", b_profile.internal_sample_rate);
1920 } else {
1921 ast_copy_string(tmp, "auto", sizeof(tmp));
1922 }
1923 ast_cli(a->fd,"Internal Sample Rate: %s\n", tmp);
1924
1925 if (b_profile.maximum_sample_rate) {
1926 snprintf(tmp, sizeof(tmp), "%u", b_profile.maximum_sample_rate);
1927 } else {
1928 ast_copy_string(tmp, "none", sizeof(tmp));
1929 }
1930 ast_cli(a->fd,"Maximum Sample Rate: %s\n", tmp);
1931
1932 if (b_profile.mix_interval) {
1933 ast_cli(a->fd,"Mixing Interval: %u\n", b_profile.mix_interval);
1934 } else {
1935 ast_cli(a->fd,"Mixing Interval: Default 20ms\n");
1936 }
1937
1938 ast_cli(a->fd,"Record Conference: %s\n",
1940 "yes" : "no");
1941
1942 ast_cli(a->fd,"Record File Append: %s\n",
1944 "yes" : "no");
1945
1946 ast_cli(a->fd,"Record File Timestamp: %s\n",
1948 "yes" : "no");
1949
1950 ast_cli(a->fd,"Record File: %s\n",
1951 ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
1952 b_profile.rec_file);
1953
1954 ast_cli(a->fd,"Record Options: %s\n",
1955 b_profile.rec_options);
1956
1957 ast_cli(a->fd,"Record Command: %s\n",
1958 b_profile.rec_command);
1959
1960 if (b_profile.max_members) {
1961 ast_cli(a->fd,"Max Members: %u\n", b_profile.max_members);
1962 } else {
1963 ast_cli(a->fd,"Max Members: No Limit\n");
1964 }
1965
1966 ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext);
1967
1968 switch (b_profile.flags
1974 ast_cli(a->fd, "Video Mode: last_marked\n");
1975 break;
1977 ast_cli(a->fd, "Video Mode: first_marked\n");
1978 break;
1980 ast_cli(a->fd, "Video Mode: follow_talker\n");
1981 break;
1983 ast_cli(a->fd, "Video Mode: sfu\n");
1984 break;
1985 case 0:
1986 ast_cli(a->fd, "Video Mode: no video\n");
1987 break;
1988 default:
1989 /* Opps. We have more than one video mode flag set. */
1990 ast_assert(0);
1991 break;
1992 }
1993
1994 ast_cli(a->fd,"Video Update Discard: %u\n", b_profile.video_update_discard);
1995 ast_cli(a->fd,"REMB Send Interval: %u\n", b_profile.remb_send_interval);
1996
1997 switch (b_profile.flags
2002 ast_cli(a->fd, "REMB Behavior: average\n");
2003 break;
2005 ast_cli(a->fd, "REMB Behavior: lowest\n");
2006 break;
2008 ast_cli(a->fd, "REMB Behavior: highest\n");
2009 break;
2011 ast_cli(a->fd, "REMB Behavior: average_all\n");
2012 break;
2014 ast_cli(a->fd, "REMB Behavior: lowest_all\n");
2015 break;
2017 ast_cli(a->fd, "REMB Behavior: highest_all\n");
2018 break;
2019 default:
2020 ast_assert(0);
2021 break;
2022 }
2023
2024 ast_cli(a->fd,"Enable Events: %s\n",
2025 b_profile.flags & BRIDGE_OPT_ENABLE_EVENTS ?
2026 "yes" : "no");
2027
2028 ast_cli(a->fd,"sound_only_person: %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds));
2029 ast_cli(a->fd,"sound_only_one: %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds));
2030 ast_cli(a->fd,"sound_has_joined: %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds));
2031 ast_cli(a->fd,"sound_has_left: %s\n", conf_get_sound(CONF_SOUND_HAS_LEFT, b_profile.sounds));
2032 ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
2033 ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
2034 ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
2035 ast_cli(a->fd,"sound_binaural_on: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_ON, b_profile.sounds));
2036 ast_cli(a->fd,"sound_binaural_off: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_OFF, b_profile.sounds));
2037 ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
2038 ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
2039 ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
2040 ast_cli(a->fd,"sound_wait_for_leader: %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
2041 ast_cli(a->fd,"sound_leader_has_left: %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
2042 ast_cli(a->fd,"sound_get_pin: %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
2043 ast_cli(a->fd,"sound_invalid_pin: %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
2044 ast_cli(a->fd,"sound_locked: %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));
2045 ast_cli(a->fd,"sound_unlocked_now: %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds));
2046 ast_cli(a->fd,"sound_lockednow: %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds));
2047 ast_cli(a->fd,"sound_error_menu: %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds));
2048 ast_cli(a->fd,"sound_join: %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds));
2049 ast_cli(a->fd,"sound_leave: %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds));
2050 ast_cli(a->fd,"sound_participants_muted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds));
2051 ast_cli(a->fd,"sound_participants_unmuted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds));
2052 ast_cli(a->fd,"sound_begin: %s\n", conf_get_sound(CONF_SOUND_BEGIN, b_profile.sounds));
2053 ast_cli(a->fd,"\n");
2054
2055 conf_bridge_profile_destroy(&b_profile);
2056 return CLI_SUCCESS;
2057}
2058
2059static char *complete_menu_name(const char *line, const char *word, int pos, int state)
2060{
2061 int which = 0;
2062 char *res = NULL;
2063 int wordlen = strlen(word);
2064 struct ao2_iterator i;
2065 struct conf_menu *menu = NULL;
2067
2068 if (!cfg) {
2069 return NULL;
2070 }
2071
2072 i = ao2_iterator_init(cfg->menus, 0);
2073 while ((menu = ao2_iterator_next(&i))) {
2074 if (!strncasecmp(menu->name, word, wordlen) && ++which > state) {
2075 res = ast_strdup(menu->name);
2076 ao2_ref(menu, -1);
2077 break;
2078 }
2079 ao2_ref(menu, -1);
2080 }
2082
2083 return res;
2084}
2085
2086static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2087{
2088 struct ao2_iterator it;
2089 struct conf_menu *menu;
2090 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
2091
2092 switch (cmd) {
2093 case CLI_INIT:
2094 e->command = "confbridge show menus";
2095 e->usage =
2096 "Usage: confbridge show profile menus\n";
2097 return NULL;
2098 case CLI_GENERATE:
2099 return NULL;
2100 }
2101
2102 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
2103 return NULL;
2104 }
2105
2106 ast_cli(a->fd,"--------- Menus -----------\n");
2107 ao2_lock(cfg->menus);
2108 it = ao2_iterator_init(cfg->menus, 0);
2109 while ((menu = ao2_iterator_next(&it))) {
2110 ast_cli(a->fd,"%s\n", menu->name);
2111 ao2_ref(menu, -1);
2112 }
2114 ao2_unlock(cfg->menus);
2115
2116 return CLI_SUCCESS;
2117}
2118
2119static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2120{
2121 RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2122 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
2123 struct conf_menu_entry *menu_entry = NULL;
2124 struct conf_menu_action *menu_action = NULL;
2125
2126 switch (cmd) {
2127 case CLI_INIT:
2128 e->command = "confbridge show menu";
2129 e->usage =
2130 "Usage: confbridge show menu [<menu name>]\n";
2131 return NULL;
2132 case CLI_GENERATE:
2133 if (a->pos == 3) {
2134 return complete_menu_name(a->line, a->word, a->pos, a->n);
2135 }
2136 return NULL;
2137 }
2138
2139 if (a->argc != 4) {
2140 return CLI_SHOWUSAGE;
2141 }
2142
2143 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
2144 return NULL;
2145 }
2146
2147 if (!(menu = menu_find(cfg->menus, a->argv[3]))) {
2148 ast_cli(a->fd, "No conference menu named '%s' found!\n", a->argv[3]);
2149 return CLI_SUCCESS;
2150 }
2151 ao2_lock(menu);
2152
2153 ast_cli(a->fd,"Name: %s\n", menu->name);
2154 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2155 int action_num = 0;
2156 ast_cli(a->fd, "%s=", menu_entry->dtmf);
2157 AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
2158 if (action_num) {
2159 ast_cli(a->fd, ", ");
2160 }
2161 switch (menu_action->id) {
2163 ast_cli(a->fd, "toggle_mute");
2164 break;
2166 ast_cli(a->fd, "toggle_binaural");
2167 break;
2168 case MENU_ACTION_NOOP:
2169 ast_cli(a->fd, "no_op");
2170 break;
2172 ast_cli(a->fd, "increase_listening_volume");
2173 break;
2175 ast_cli(a->fd, "decrease_listening_volume");
2176 break;
2178 ast_cli(a->fd, "reset_listening_volume");
2179 break;
2181 ast_cli(a->fd, "reset_talking_volume");
2182 break;
2184 ast_cli(a->fd, "increase_talking_volume");
2185 break;
2187 ast_cli(a->fd, "decrease_talking_volume");
2188 break;
2190 ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
2191 break;
2193 ast_cli(a->fd, "playback_and_continue(%s)", menu_action->data.playback_file);
2194 break;
2196 ast_cli(a->fd, "dialplan_exec(%s,%s,%d)",
2197 menu_action->data.dialplan_args.context,
2198 menu_action->data.dialplan_args.exten,
2199 menu_action->data.dialplan_args.priority);
2200 break;
2202 ast_cli(a->fd, "admin_toggle_conference_lock");
2203 break;
2205 ast_cli(a->fd, "admin_toggle_mute_participants");
2206 break;
2208 ast_cli(a->fd, "participant_count");
2209 break;
2211 ast_cli(a->fd, "admin_kick_last");
2212 break;
2213 case MENU_ACTION_LEAVE:
2214 ast_cli(a->fd, "leave_conference");
2215 break;
2217 ast_cli(a->fd, "set_as_single_video_src");
2218 break;
2220 ast_cli(a->fd, "release_as_single_video_src");
2221 break;
2222 }
2223 action_num++;
2224 }
2225 ast_cli(a->fd,"\n");
2226 }
2227
2228
2229 ao2_unlock(menu);
2230 return CLI_SUCCESS;
2231}
2232
2234 AST_CLI_DEFINE(handle_cli_confbridge_show_user_profile, "Show a conference user profile."),
2235 AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profile, "Show a conference bridge profile."),
2236 AST_CLI_DEFINE(handle_cli_confbridge_show_menu, "Show a conference menu"),
2237 AST_CLI_DEFINE(handle_cli_confbridge_show_user_profiles, "Show a list of conference user profiles."),
2238 AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profiles, "Show a list of conference bridge profiles."),
2239 AST_CLI_DEFINE(handle_cli_confbridge_show_menus, "Show a list of conference menus"),
2240
2241};
2242
2243static void confbridge_cfg_destructor(void *obj)
2244{
2245 struct confbridge_cfg *cfg = obj;
2248 ao2_cleanup(cfg->menus);
2249}
2250
2252{
2253 struct confbridge_cfg *cfg;
2254
2255 if (!(cfg = ao2_alloc(sizeof(*cfg), confbridge_cfg_destructor))) {
2256 return NULL;
2257 }
2258
2261 if (!cfg->user_profiles) {
2262 goto error;
2263 }
2264
2267 if (!cfg->bridge_profiles) {
2268 goto error;
2269 }
2270
2273 if (!cfg->menus) {
2274 goto error;
2275 }
2276
2277 return cfg;
2278error:
2279 ao2_ref(cfg, -1);
2280 return NULL;
2281}
2282
2283static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2284{
2285 struct user_profile *u_profile = obj;
2286
2287 if (strcasecmp(var->name, "announce_user_count_all")) {
2288 return -1;
2289 }
2290 if (ast_true(var->value)) {
2291 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2292 } else if (ast_false(var->value)) {
2293 u_profile->flags = u_profile->flags & ~USER_OPT_ANNOUNCEUSERCOUNTALL;
2294 } else if (sscanf(var->value, "%30u", &u_profile->announce_user_count_all_after) == 1) {
2295 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2296 } else {
2297 return -1;
2298 }
2299 return 0;
2300}
2301
2302static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2303{
2304 struct bridge_profile *b_profile = obj;
2305
2306 if (strcasecmp(var->name, "mixing_interval")) {
2307 return -1;
2308 }
2309 if (sscanf(var->value, "%30u", &b_profile->mix_interval) != 1) {
2310 return -1;
2311 }
2312 switch (b_profile->mix_interval) {
2313 case 10:
2314 case 20:
2315 case 40:
2316 case 80:
2317 return 0;
2318 default:
2319 return -1;
2320 }
2321}
2322
2323static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2324{
2325 struct bridge_profile *b_profile = obj;
2326
2327 if (strcasecmp(var->name, "video_mode")) {
2328 return -1;
2329 }
2330 if (!strcasecmp(var->value, "first_marked")) {
2331 ast_set_flags_to(b_profile,
2337 } else if (!strcasecmp(var->value, "last_marked")) {
2338 ast_set_flags_to(b_profile,
2344 } else if (!strcasecmp(var->value, "follow_talker")) {
2345 ast_set_flags_to(b_profile,
2351 } else if (!strcasecmp(var->value, "sfu")) {
2352 ast_set_flags_to(b_profile,
2358 } else if (!strcasecmp(var->value, "none")) {
2359 ast_clear_flag(b_profile,
2364 } else {
2365 return -1;
2366 }
2367 return 0;
2368}
2369
2370static int remb_behavior_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2371{
2372 struct bridge_profile *b_profile = obj;
2373
2374 if (strcasecmp(var->name, "remb_behavior")) {
2375 return -1;
2376 }
2377
2385 );
2386
2387 if (!strcasecmp(var->value, "average")) {
2389 } else if (!strcasecmp(var->value, "lowest")) {
2391 } else if (!strcasecmp(var->value, "highest")) {
2393 } else if (!strcasecmp(var->value, "average_all")) {
2395 } else if (!strcasecmp(var->value, "lowest_all")) {
2397 } else if (!strcasecmp(var->value, "highest_all")) {
2399 } else if (!strcasecmp(var->value, "force")) {
2401 } else {
2402 return -1;
2403 }
2404 return 0;
2405}
2406
2407static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2408{
2409 struct user_profile *u_profile = obj;
2410
2411 return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
2412}
2413
2414static int sample_rate_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2415{
2416 struct bridge_profile *b_profile = obj;
2417 unsigned int *slot;
2418
2419 if (!strcasecmp(var->name, "internal_sample_rate")) {
2420 slot = &b_profile->internal_sample_rate;
2421 if (!strcasecmp(var->value, "auto")) {
2422 *slot = 0;
2423 return 0;
2424 }
2425 } else if (!strcasecmp(var->name, "maximum_sample_rate")) {
2426 slot = &b_profile->maximum_sample_rate;
2427 if (!strcasecmp(var->value, "none")) {
2428 *slot = 0;
2429 return 0;
2430 }
2431 } else {
2432 return -1;
2433 }
2434
2435 return ast_parse_arg(var->value, PARSE_UINT32 | PARSE_IN_RANGE, slot, 8000, 192000);
2436}
2437
2438static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2439{
2440 struct bridge_profile *b_profile = obj;
2442 struct bridge_profile_sounds *oldsounds = b_profile->sounds;
2443
2444 if (!sounds) {
2445 return -1;
2446 }
2447 if (!(conf_find_bridge_profile(NULL, var->value, b_profile))) {
2448 ao2_ref(sounds, -1);
2449 return -1;
2450 }
2451 /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds
2452 * structure of a dynamic profile will need to be altered, a completely new sounds structure must be
2453 * created instead of simply holding a reference to the one built by the config file. */
2454 ast_string_field_set(sounds, onlyperson, b_profile->sounds->onlyperson);
2455 ast_string_field_set(sounds, onlyone, b_profile->sounds->onlyone);
2456 ast_string_field_set(sounds, hasjoin, b_profile->sounds->hasjoin);
2457 ast_string_field_set(sounds, hasleft, b_profile->sounds->hasleft);
2458 ast_string_field_set(sounds, kicked, b_profile->sounds->kicked);
2459 ast_string_field_set(sounds, muted, b_profile->sounds->muted);
2460 ast_string_field_set(sounds, unmuted, b_profile->sounds->unmuted);
2461 ast_string_field_set(sounds, thereare, b_profile->sounds->thereare);
2462 ast_string_field_set(sounds, otherinparty, b_profile->sounds->otherinparty);
2463 ast_string_field_set(sounds, placeintoconf, b_profile->sounds->placeintoconf);
2464 ast_string_field_set(sounds, waitforleader, b_profile->sounds->waitforleader);
2465 ast_string_field_set(sounds, leaderhasleft, b_profile->sounds->leaderhasleft);
2466 ast_string_field_set(sounds, getpin, b_profile->sounds->getpin);
2467 ast_string_field_set(sounds, invalidpin, b_profile->sounds->invalidpin);
2468 ast_string_field_set(sounds, locked, b_profile->sounds->locked);
2469 ast_string_field_set(sounds, unlockednow, b_profile->sounds->unlockednow);
2470 ast_string_field_set(sounds, lockednow, b_profile->sounds->lockednow);
2471 ast_string_field_set(sounds, errormenu, b_profile->sounds->errormenu);
2472 ast_string_field_set(sounds, join, b_profile->sounds->join);
2474 ast_string_field_set(sounds, participantsmuted, b_profile->sounds->participantsmuted);
2475 ast_string_field_set(sounds, participantsunmuted, b_profile->sounds->participantsunmuted);
2476 ast_string_field_set(sounds, begin, b_profile->sounds->begin);
2477
2478 ao2_ref(b_profile->sounds, -1); /* sounds struct copied over to it from the template by reference only. */
2479 ao2_ref(oldsounds, -1); /* original sounds struct we don't need anymore */
2480 b_profile->sounds = sounds; /* the new sounds struct that is a deep copy of the one from the template. */
2481
2482 return 0;
2483}
2484
2485static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
2486{
2487 struct conf_menu_action *menu_action;
2488 struct conf_menu_action *new_menu_action;
2489
2490 ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
2492
2493 AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
2494 if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
2495 return -1;
2496 }
2497 memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
2498 AST_LIST_NEXT(new_menu_action, action) = NULL;
2499 AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
2500 }
2501
2502 return 0;
2503}
2504
2505static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
2506{
2507 /* Copy each menu item to the dst struct */
2508 struct conf_menu_entry *cur;
2509
2510 AST_LIST_TRAVERSE(&src->entries, cur, entry) {
2511 struct conf_menu_entry *cpy;
2512
2513 if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
2514 return -1;
2515 }
2516
2517 if (copy_menu_entry(cpy, cur)) {
2519 ast_free(cpy);
2520 return -1;
2521 }
2522 AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
2523 }
2524
2525 return 0;
2526}
2527
2528static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2529{
2530 struct conf_menu *dst_menu = obj;
2532 RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
2533
2534 if (!cfg) {
2535 return 0;
2536 }
2537
2538 if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
2539 return -1;
2540 }
2541
2542 if (conf_menu_profile_copy(dst_menu, src_menu)) {
2543 return -1;
2544 }
2545
2546 return 0;
2547}
2548
2549static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2550{
2551 set_sound(var->name, var->value, obj);
2552 return 0;
2553}
2554
2555static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2556{
2557 add_menu_entry(obj, var->name, var->value);
2558 return 0;
2559}
2560
2562{
2565 RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
2566 /* We can only be called as a result of an aco_process_config so this is safe */
2567 struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
2568
2569 if (!cfg) {
2570 return 0;
2571 }
2572
2574 if (!bridge_profile) {
2576 if (!bridge_profile) {
2577 return -1;
2578 }
2579 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_BRIDGE_PROFILE);
2582 }
2583
2585 if (!user_profile) {
2587 if (!user_profile) {
2588 return -1;
2589 }
2590 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_USER_PROFILE);
2593 }
2594
2595 menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
2596 if (!menu_profile) {
2597 menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
2598 if (!menu_profile) {
2599 return -1;
2600 }
2601 ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
2603 ao2_link(cfg->menus, menu_profile);
2604 }
2605
2606 return 0;
2607}
2608
2610{
2611 if (aco_info_init(&cfg_info)) {
2612 return -1;
2613 }
2614
2615 /* User options */
2616 aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
2617 aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
2618 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);
2619 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);
2620 aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
2621 aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
2622 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);
2623 aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
2624 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);
2625 aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
2626 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);
2627 /* Negative logic. Defaults to "yes" and evaluates with ast_false(). If !ast_false(), USER_OPT_NOONLYPERSON is cleared */
2628 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);
2629 aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
2630 aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
2631 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);
2632 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);
2633 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);
2634 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);
2635 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);
2637 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));
2638 aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
2639 aco_option_register(&cfg_info, "denoise", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DENOISE);
2640 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);
2641 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));
2642 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));
2643 aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER);
2644 aco_option_register(&cfg_info, "timeout", ACO_EXACT, user_types, "0", OPT_UINT_T, 0, FLDSET(struct user_profile, timeout));
2645 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);
2646 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);
2647
2648 /* This option should only be used with the CONFBRIDGE dialplan function */
2650
2651/* XXX ASTERISK-21271 need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
2652 /* Bridge options */
2653 aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
2654 aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
2655 aco_option_register_custom(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "auto", sample_rate_handler, 0);
2656 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);
2657 aco_option_register_custom(&cfg_info, "maximum_sample_rate", ACO_EXACT, bridge_types, "none", sample_rate_handler, 0);
2658 aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
2659 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);
2661 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);
2662 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);
2663 aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
2664 aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
2665 aco_option_register(&cfg_info, "record_options", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_options));
2666 aco_option_register(&cfg_info, "record_command", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_command));
2670 aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard));
2671 aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval));
2672 aco_option_register_custom(&cfg_info, "remb_behavior", ACO_EXACT, bridge_types, "average", remb_behavior_handler, 0);
2673 aco_option_register(&cfg_info, "remb_estimated_bitrate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_estimated_bitrate));
2674 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);
2675 /* This option should only be used with the CONFBRIDGE dialplan function */
2677
2678 /* Menu options */
2679 aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
2680 /* This option should only be used with the CONFBRIDGE dialplan function */
2682 aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
2683
2684 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
2685 goto error;
2686 }
2687
2689 goto error;
2690 }
2691
2692 return 0;
2693error:
2695 return -1;
2696}
2697
2699{
2700 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2701 /* On a reload, just keep the config we already have in place. */
2702 return -1;
2703 }
2704 return 0;
2705}
2706
2707static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
2708{
2709 *dst = *src;
2710}
2711
2712const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
2713{
2714 struct user_profile *tmp2;
2715 struct ast_datastore *datastore = NULL;
2716 struct func_confbridge_data *b_data = NULL;
2718
2719 if (chan && ast_strlen_zero(user_profile_name)) {
2720 ast_channel_lock(chan);
2722 ast_channel_unlock(chan);
2723 if (datastore) {
2724 b_data = datastore->data;
2725 if (b_data->u_usable) {
2727 return result;
2728 }
2729 }
2730 }
2731
2732 if (!cfg) {
2733 return NULL;
2734 }
2735 if (ast_strlen_zero(user_profile_name)) {
2736 user_profile_name = DEFAULT_USER_PROFILE;
2737 }
2738 if (!(tmp2 = ao2_find(cfg->user_profiles, user_profile_name, OBJ_KEY))) {
2739 return NULL;
2740 }
2741 ao2_lock(tmp2);
2743 ao2_unlock(tmp2);
2744 ao2_ref(tmp2, -1);
2745
2746 return result;
2747}
2748
2750{
2751 *dst = *src;
2752 if (src->sounds) {
2753 ao2_ref(src->sounds, +1);
2754 }
2755}
2756
2758{
2759 if (b_profile->sounds) {
2760 ao2_ref(b_profile->sounds, -1);
2761 b_profile->sounds = NULL;
2762 }
2763}
2764
2765const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
2766{
2767 struct bridge_profile *tmp2;
2768 struct ast_datastore *datastore = NULL;
2769 struct func_confbridge_data *b_data = NULL;
2771
2772 if (chan && ast_strlen_zero(bridge_profile_name)) {
2773 ast_channel_lock(chan);
2775 ast_channel_unlock(chan);
2776 if (datastore) {
2777 b_data = datastore->data;
2778 if (b_data->b_usable) {
2780 return result;
2781 }
2782 }
2783 }
2784
2785 if (!cfg) {
2786 return NULL;
2787 }
2788 if (ast_strlen_zero(bridge_profile_name)) {
2789 bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
2790 }
2791 if (!(tmp2 = ao2_find(cfg->bridge_profiles, bridge_profile_name, OBJ_KEY))) {
2792 return NULL;
2793 }
2794 ao2_lock(tmp2);
2796 ao2_unlock(tmp2);
2797 ao2_ref(tmp2, -1);
2798
2799 return result;
2800}
2801
2806};
2807
2808static void menu_hook_destroy(void *hook_pvt)
2809{
2810 struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2811 struct conf_menu_action *action = NULL;
2812
2813 ao2_cleanup(pvt->menu);
2814
2815 while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
2816 ast_free(action);
2817 }
2818 ast_free(pvt);
2819}
2820
2821static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
2822{
2823 struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2824
2825 return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
2826}
2827
2829{
2830 struct conf_menu_action *menu_action = NULL;
2831 while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
2832 ast_free(menu_action);
2833 }
2834}
2835
2836int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
2837{
2838 struct conf_menu_entry *menu_entry = NULL;
2839
2840 ao2_lock(menu);
2841 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2842 if (!strcasecmp(menu_entry->dtmf, dtmf_sequence)) {
2843 copy_menu_entry(result, menu_entry);
2844 ao2_unlock(menu);
2845 return 1;
2846 }
2847 }
2848 ao2_unlock(menu);
2849
2850 return 0;
2851}
2852
2853static int apply_menu_to_user(struct confbridge_user *user, struct conf_menu *menu)
2854{
2855 struct conf_menu_entry *menu_entry;
2856
2857 SCOPED_AO2LOCK(menu_lock, menu);
2858 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2859 struct dtmf_menu_hook_pvt *pvt;
2860
2861 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
2862 return -1;
2863 }
2864 pvt->user = user;
2865 pvt->menu = ao2_bump(menu);
2866
2867 if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
2868 menu_hook_destroy(pvt);
2869 return -1;
2870 }
2871
2872 if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
2874 menu_hook_destroy(pvt);
2875 }
2876 }
2877 strcpy(user->menu_name, menu->name); /* Safe */
2878
2879 return 0;
2880}
2881
2882int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
2883{
2885 RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2886
2887 if (chan && ast_strlen_zero(menu_profile_name)) {
2888 struct ast_datastore *datastore;
2889 struct func_confbridge_data *b_data;
2890
2891 ast_channel_lock(chan);
2893 ast_channel_unlock(chan);
2894 if (datastore) {
2895 /* If a menu exists in the CONFBRIDGE function datastore, use it. */
2896 b_data = datastore->data;
2897 if (b_data->m_usable) {
2898 menu = ao2_bump(b_data->menu);
2899 return apply_menu_to_user(user, menu);
2900 }
2901 }
2902 }
2903
2904 /* Otherwise, we need to get whatever menu profile is specified to use (or default). */
2905 if (!cfg) {
2906 return -1;
2907 }
2908
2909 if (ast_strlen_zero(menu_profile_name)) {
2910 menu_profile_name = DEFAULT_MENU_PROFILE;
2911 }
2912
2913 if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
2914 return -1;
2915 }
2916
2917 return apply_menu_to_user(user, menu);
2918}
2919
2921{
2923 aco_info_destroy(&cfg_info);
2925}
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:1808
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
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:3251
static int priority
static PGresult * result
Definition: cel_pgsql.c:84
static char regcontext[AST_MAX_CONTEXT]
Definition: chan_iax2.c:349
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:348
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:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
#define ast_channel_lock(chan)
Definition: channel.h:2970
#define ast_channel_unlock(chan)
Definition: channel.h:2971
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:2428
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.
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:4047
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:608
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:531
#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::@92 entry
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
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