Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
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 allowed 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="announcements" default="yes">
753 <since>
754 <version>20.22.0</version>
755 <version>22.12.0</version>
756 <version>23.6.0</version>
757 </since>
758 <synopsis>Enables announcements played to the conference as a whole</synopsis>
759 <description>
760 <para>When set to <literal>no</literal>, no announcer channel
761 (<literal>CBAnn</literal>) is created for the conference and no
762 announcement is ever played to the conference as a whole. This
763 suppresses the join and leave sounds, recorded name intros, the
764 participant count announced to everyone, and the
765 <literal>sound_begin</literal> and
766 <literal>sound_leader_has_left</literal> prompts. Users are also
767 never prompted to record their name, regardless of the
768 <literal>announce_join_leave</literal> user profile option.</para>
769 <para>Prompts that are played only to the participant that caused
770 them are not affected. <literal>sound_kicked</literal>,
771 <literal>sound_muted</literal>, <literal>sound_unmuted</literal>,
772 the join sound played back by
773 <literal>hear_own_join_sound</literal> and the participant count
774 requested from the DTMF menu are all still played.</para>
775 <para>Disabling announcements saves a channel and a taskprocessor
776 thread per conference and removes a member from the mix, which is
777 worthwhile for systems running many conferences that never play
778 announcements.</para>
779 <para>The value that takes effect is the one from the bridge
780 profile of the channel that creates the conference, since the
781 announcer channel exists for the lifetime of the conference.</para>
782 </description>
783 </configOption>
784 <configOption name="template">
785 <since>
786 <version>11.0.0</version>
787 </since>
788 <synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
789 </configOption>
790 </configObject>
791 <configObject name="menu">
792 <since>
793 <version>12.0.0</version>
794 </since>
795 <synopsis>A conference user menu</synopsis>
796 <description>
797 <para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
798 can have a DTMF menu assigned to their profile when they enter the
799 <literal>ConfBridge</literal> application.</para>
800 </description>
801 <configOption name="type">
802 <since>
803 <version>12.0.0</version>
804 </since>
805 <synopsis>Define this configuration category as a menu</synopsis>
806 <description><para>The type parameter determines how a context in the
807 configuration file is interpreted.</para>
808 <enumlist>
809 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
810 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
811 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
812 </enumlist>
813 </description>
814 </configOption>
815 <configOption name="template">
816 <since>
817 <version>13.0.0</version>
818 </since>
819 <synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
820 </configOption>
821 <configOption name="^[0-9A-D*#]+$">
822 <synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
823 <description>
824 <para>The ConfBridge application also has the ability to apply custom DTMF menus to
825 each channel using the application. Like the User and Bridge profiles a menu
826 is passed in to ConfBridge as an argument in the dialplan.</para>
827 <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
828 <note><para>
829 To have the first DTMF digit in a sequence be the '#' character, you need to
830 escape it. If it is not escaped then normal config file processing will
831 think it is a directive like #include. For example: The mute setting is
832 toggled when <literal>#1</literal> is pressed.</para>
833 <para><literal>\#1=toggle_mute</literal></para>
834 </note>
835 <note><para>
836 A single DTMF sequence can have multiple actions associated with it. This is
837 accomplished by stringing the actions together and using a <literal>,</literal> as the
838 delimiter. Example: Both listening and talking volume is reset when <literal>5</literal> is
839 pressed. <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
840 <enumlist>
841 <enum name="playback(filename&amp;filename2&amp;...)"><para>
842 <literal>playback</literal> will play back an audio file to a channel
843 and then immediately return to the conference.
844 This file can not be interrupted by DTMF.
845 Multiple files can be chained together using the
846 <literal>&amp;</literal> character.</para></enum>
847 <enum name="playback_and_continue(filename&amp;filename2&amp;...)"><para>
848 <literal>playback_and_continue</literal> will
849 play back a prompt while continuing to
850 collect the dtmf sequence. This is useful
851 when using a menu prompt that describes all
852 the menu options. Note however that any DTMF
853 during this action will terminate the prompts
854 playback. Prompt files can be chained together
855 using the <literal>&amp;</literal> character as a delimiter.</para></enum>
856 <enum name="toggle_mute"><para>
857 Toggle turning on and off mute. Mute will make the user silent
858 to everyone else, but the user will still be able to listen in.
859 </para></enum>
860 <enum name="toggle_binaural"><para>
861 Toggle turning on and off binaural audio processing.
862 </para></enum>
863 <enum name="no_op"><para>
864 This action does nothing (No Operation). Its only real purpose exists for
865 being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
866 <enum name="decrease_listening_volume"><para>
867 Decreases the channel's listening volume.</para></enum>
868 <enum name="increase_listening_volume"><para>
869 Increases the channel's listening volume.</para></enum>
870 <enum name="reset_listening_volume"><para>
871 Reset channel's listening volume to default level.</para></enum>
872 <enum name="decrease_talking_volume"><para>
873 Decreases the channel's talking volume.</para></enum>
874 <enum name="increase_talking_volume"><para>
875 Increases the channel's talking volume.</para></enum>
876 <enum name="reset_talking_volume"><para>
877 Reset channel's talking volume to default level.</para></enum>
878 <enum name="dialplan_exec(context,exten,priority)"><para>
879 The <literal>dialplan_exec</literal> action allows a user
880 to escape from the conference and execute
881 commands in the dialplan. Once the dialplan
882 exits the user will be put back into the
883 conference. The possibilities are endless!</para></enum>
884 <enum name="leave_conference"><para>
885 This action allows a user to exit the conference and continue
886 execution in the dialplan.</para></enum>
887 <enum name="admin_kick_last"><para>
888 This action allows an Admin to kick the last participant from the
889 conference. This action will only work for admins which allows
890 a single menu to be used for both users and admins.</para></enum>
891 <enum name="admin_toggle_conference_lock"><para>
892 This action allows an Admin to toggle locking and
893 unlocking the conference. Non admins can not use
894 this action even if it is in their menu.</para></enum>
895 <enum name="set_as_single_video_src"><para>
896 This action allows any user to set themselves as the
897 single video source distributed to all participants.
898 This will make the video feed stick to them regardless
899 of what the <literal>video_mode</literal> is set to.</para></enum>
900 <enum name="release_as_single_video_src"><para>
901 This action allows a user to release themselves as
902 the video source. If <literal>video_mode</literal> is not set to <literal>none</literal>
903 this action will result in the conference returning to
904 whatever video mode the bridge profile is using.</para>
905 <para>Note that this action will have no effect if the user
906 is not currently the video source. Also, the user is
907 not guaranteed by using this action that they will not
908 become the video source again. The bridge will return
909 to whatever operation the <literal>video_mode</literal> option is set to
910 upon release of the video src.</para></enum>
911 <enum name="admin_toggle_mute_participants"><para>
912 This action allows an administrator to toggle the mute
913 state for all non-admins within a conference. All
914 admin users are unaffected by this option. Note that all
915 users, regardless of their admin status, are notified
916 that the conference is muted.</para></enum>
917 <enum name="participant_count"><para>
918 This action plays back the number of participants currently
919 in a conference</para></enum>
920 </enumlist>
921 </description>
922 </configOption>
923 </configObject>
924 </configFile>
925 </configInfo>
926***/
927
933
934static int verify_default_profiles(void);
935static void *bridge_profile_alloc(const char *category);
936static void *bridge_profile_find(struct ao2_container *container, const char *category);
938
939static void bridge_profile_destructor(void *obj)
940{
941 struct bridge_profile *b_profile = obj;
942 ao2_cleanup(b_profile->sounds);
943}
944
945static void *bridge_profile_alloc(const char *category)
946{
947 struct bridge_profile *b_profile;
948
949 if (!(b_profile = ao2_alloc(sizeof(*b_profile), bridge_profile_destructor))) {
950 return NULL;
951 }
952
953 if (!(b_profile->sounds = bridge_profile_sounds_alloc())) {
954 ao2_ref(b_profile, -1);
955 return NULL;
956 }
957
958 ast_copy_string(b_profile->name, category, sizeof(b_profile->name));
959
960 return b_profile;
961}
962
963static void *bridge_profile_find(struct ao2_container *container, const char *category)
964{
965 return ao2_find(container, category, OBJ_KEY);
966}
967
968static struct aco_type bridge_type = {
969 .type = ACO_ITEM,
970 .name = "bridge_profile",
971 .category_match = ACO_BLACKLIST_EXACT,
972 .category = "general",
973 .matchfield = "type",
974 .matchvalue = "bridge",
975 .item_alloc = bridge_profile_alloc,
976 .item_find = bridge_profile_find,
977 .item_offset = offsetof(struct confbridge_cfg, bridge_profiles),
978};
979
980static void *user_profile_alloc(const char *category);
981static void *user_profile_find(struct ao2_container *container, const char *category);
982static void user_profile_destructor(void *obj)
983{
984 return;
985}
986
987static void *user_profile_alloc(const char *category)
988{
989 struct user_profile *u_profile;
990
991 if (!(u_profile = ao2_alloc(sizeof(*u_profile), user_profile_destructor))) {
992 return NULL;
993 }
994
995 ast_copy_string(u_profile->name, category, sizeof(u_profile->name));
996
997 return u_profile;
998}
999
1000static void *user_profile_find(struct ao2_container *container, const char *category)
1001{
1002 return ao2_find(container, category, OBJ_KEY);
1003}
1004
1005static struct aco_type user_type = {
1006 .type = ACO_ITEM,
1007 .name = "user_profile",
1008 .category_match = ACO_BLACKLIST_EXACT,
1009 .category = "general",
1010 .matchfield = "type",
1011 .matchvalue = "user",
1012 .item_alloc = user_profile_alloc,
1013 .item_find = user_profile_find,
1014 .item_offset = offsetof(struct confbridge_cfg, user_profiles),
1015};
1016
1017static void *menu_alloc(const char *category);
1018static void *menu_find(struct ao2_container *container, const char *category);
1019static void menu_destructor(void *obj);
1020
1021static void *menu_alloc(const char *category)
1022{
1023 struct conf_menu *menu;
1024 if (!(menu = ao2_alloc(sizeof(*menu), menu_destructor))) {
1025 return NULL;
1026 }
1027 ast_copy_string(menu->name, category, sizeof(menu->name));
1028 return menu;
1029}
1030
1031static void *menu_find(struct ao2_container *container, const char *category)
1032{
1033 return ao2_find(container, category, OBJ_KEY);
1034}
1035
1036static struct aco_type menu_type = {
1037 .type = ACO_ITEM,
1038 .name = "menu",
1039 .category_match = ACO_BLACKLIST_EXACT,
1040 .category = "general",
1041 .matchfield = "type",
1042 .matchvalue = "menu",
1043 .item_alloc = menu_alloc,
1044 .item_find = menu_find,
1045 .item_offset = offsetof(struct confbridge_cfg, menus),
1046};
1047
1048/* Used to pass to aco_option_register */
1052
1053/* The general category is reserved, but unused */
1054static struct aco_type general_type = {
1055 .type = ACO_GLOBAL,
1056 .name = "global",
1057 .category_match = ACO_WHITELIST_EXACT,
1058 .category = "general",
1059};
1060
1061static struct aco_file confbridge_conf = {
1062 .filename = "confbridge.conf",
1064};
1065
1067
1068static void *confbridge_cfg_alloc(void);
1069
1071 .files = ACO_FILES(&confbridge_conf),
1072 .pre_apply_config = verify_default_profiles,
1073);
1074
1075/*! bridge profile container functions */
1076static int bridge_cmp_cb(void *obj, void *arg, int flags)
1077{
1078 const struct bridge_profile *left = obj;
1079 const struct bridge_profile *right = arg;
1080 const char *right_name = arg;
1081 int cmp;
1082
1083 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1084 default:
1085 case OBJ_POINTER:
1086 right_name = right->name;
1087 /* Fall through */
1088 case OBJ_KEY:
1089 cmp = strcasecmp(left->name, right_name);
1090 break;
1091 case OBJ_PARTIAL_KEY:
1092 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1093 break;
1094 }
1095 return cmp ? 0 : CMP_MATCH;
1096}
1097
1098static int bridge_hash_cb(const void *obj, const int flags)
1099{
1100 const struct bridge_profile *b_profile = obj;
1101 const char *name = obj;
1102 int hash;
1103
1104 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1105 default:
1106 case OBJ_POINTER:
1107 name = b_profile->name;
1108 /* Fall through */
1109 case OBJ_KEY:
1110 hash = ast_str_case_hash(name);
1111 break;
1112 case OBJ_PARTIAL_KEY:
1113 /* Should never happen in hash callback. */
1114 ast_assert(0);
1115 hash = 0;
1116 break;
1117 }
1118 return hash;
1119}
1120
1121/*! menu container functions */
1122static int menu_cmp_cb(void *obj, void *arg, int flags)
1123{
1124 const struct conf_menu *left = obj;
1125 const struct conf_menu *right = arg;
1126 const char *right_name = arg;
1127 int cmp;
1128
1129 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1130 default:
1131 case OBJ_POINTER:
1132 right_name = right->name;
1133 /* Fall through */
1134 case OBJ_KEY:
1135 cmp = strcasecmp(left->name, right_name);
1136 break;
1137 case OBJ_PARTIAL_KEY:
1138 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1139 break;
1140 }
1141 return cmp ? 0 : CMP_MATCH;
1142}
1143
1144static int menu_hash_cb(const void *obj, const int flags)
1145{
1146 const struct conf_menu *menu = obj;
1147 const char *name = obj;
1148 int hash;
1149
1150 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1151 default:
1152 case OBJ_POINTER:
1153 name = menu->name;
1154 /* Fall through */
1155 case OBJ_KEY:
1156 hash = ast_str_case_hash(name);
1157 break;
1158 case OBJ_PARTIAL_KEY:
1159 /* Should never happen in hash callback. */
1160 ast_assert(0);
1161 hash = 0;
1162 break;
1163 }
1164 return hash;
1165}
1166
1167static void menu_destructor(void *obj)
1168{
1169 struct conf_menu *menu = obj;
1170 struct conf_menu_entry *entry = NULL;
1171
1172 while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
1174 ast_free(entry);
1175 }
1176}
1177
1178/*! User profile container functions */
1179static int user_cmp_cb(void *obj, void *arg, int flags)
1180{
1181 const struct user_profile *left = obj;
1182 const struct user_profile *right = arg;
1183 const char *right_name = arg;
1184 int cmp;
1185
1186 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1187 default:
1188 case OBJ_POINTER:
1189 right_name = right->name;
1190 /* Fall through */
1191 case OBJ_KEY:
1192 cmp = strcasecmp(left->name, right_name);
1193 break;
1194 case OBJ_PARTIAL_KEY:
1195 cmp = strncasecmp(left->name, right_name, strlen(right_name));
1196 break;
1197 }
1198 return cmp ? 0 : CMP_MATCH;
1199}
1200
1201static int user_hash_cb(const void *obj, const int flags)
1202{
1203 const struct user_profile *u_profile = obj;
1204 const char *name = obj;
1205 int hash;
1206
1207 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
1208 default:
1209 case OBJ_POINTER:
1210 name = u_profile->name;
1211 /* Fall through */
1212 case OBJ_KEY:
1213 hash = ast_str_case_hash(name);
1214 break;
1215 case OBJ_PARTIAL_KEY:
1216 /* Should never happen in hash callback. */
1217 ast_assert(0);
1218 hash = 0;
1219 break;
1220 }
1221 return hash;
1222}
1223
1224/*! Bridge Profile Sounds functions */
1226{
1227 struct bridge_profile_sounds *sounds = obj;
1229}
1230
1232{
1234
1235 if (!sounds) {
1236 return NULL;
1237 }
1238 if (ast_string_field_init(sounds, 512)) {
1239 ao2_ref(sounds, -1);
1240 return NULL;
1241 }
1242
1243 return sounds;
1244}
1245
1246static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
1247{
1248 struct bridge_profile_sounds *sounds = b_profile->sounds;
1249 if (ast_strlen_zero(sound_file)) {
1250 return -1;
1251 }
1252
1253 if (!strcasecmp(sound_name, "sound_only_person")) {
1255 } else if (!strcasecmp(sound_name, "sound_only_one")) {
1256 ast_string_field_set(sounds, onlyone, sound_file);
1257 } else if (!strcasecmp(sound_name, "sound_has_joined")) {
1258 ast_string_field_set(sounds, hasjoin, sound_file);
1259 } else if (!strcasecmp(sound_name, "sound_has_left")) {
1260 ast_string_field_set(sounds, hasleft, sound_file);
1261 } else if (!strcasecmp(sound_name, "sound_kicked")) {
1262 ast_string_field_set(sounds, kicked, sound_file);
1263 } else if (!strcasecmp(sound_name, "sound_muted")) {
1264 ast_string_field_set(sounds, muted, sound_file);
1265 } else if (!strcasecmp(sound_name, "sound_unmuted")) {
1266 ast_string_field_set(sounds, unmuted, sound_file);
1267 } else if (!strcasecmp(sound_name, "sound_binaural_on")) {
1269 } else if (!strcasecmp(sound_name, "sound_binaural_off")) {
1271 } else if (!strcasecmp(sound_name, "sound_there_are")) {
1272 ast_string_field_set(sounds, thereare, sound_file);
1273 } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
1275 } else if (!strcasecmp(sound_name, "sound_place_into_conference")) {
1276 static int deprecation_warning = 1;
1277 if (deprecation_warning) {
1278 ast_log(LOG_WARNING, "sound_place_into_conference is deprecated"
1279 " and unused. Use sound_begin for similar functionality.");
1280 deprecation_warning = 0;
1281 }
1283 } else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
1285 } else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
1287 } else if (!strcasecmp(sound_name, "sound_get_pin")) {
1288 ast_string_field_set(sounds, getpin, sound_file);
1289 } else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
1291 } else if (!strcasecmp(sound_name, "sound_locked")) {
1292 ast_string_field_set(sounds, locked, sound_file);
1293 } else if (!strcasecmp(sound_name, "sound_unlocked_now")) {
1295 } else if (!strcasecmp(sound_name, "sound_locked_now")) {
1297 } else if (!strcasecmp(sound_name, "sound_error_menu")) {
1299 } else if (!strcasecmp(sound_name, "sound_join")) {
1300 ast_string_field_set(sounds, join, sound_file);
1301 } else if (!strcasecmp(sound_name, "sound_leave")) {
1302 ast_string_field_set(sounds, leave, sound_file);
1303 } else if (!strcasecmp(sound_name, "sound_participants_muted")) {
1305 } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) {
1307 } else if (!strcasecmp(sound_name, "sound_begin")) {
1308 ast_string_field_set(sounds, begin, sound_file);
1309 } else {
1310 return -1;
1311 }
1312
1313 return 0;
1314}
1315
1316/*! CONFBRIDGE dialplan function functions and channel datastore. */
1321 unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
1322 unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
1323 unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
1324};
1325
1327{
1329 ao2_cleanup(b_data->menu);
1330 ast_free(b_data);
1331}
1332
1333static void func_confbridge_destroy_cb(void *data)
1334{
1335 struct func_confbridge_data *b_data = data;
1337};
1338
1340 .type = "confbridge",
1342};
1343
1344int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1345{
1346 struct ast_datastore *datastore;
1347 struct func_confbridge_data *b_data;
1348 char *parse;
1349 struct ast_variable tmpvar = { 0, };
1350 struct ast_variable template = {
1351 .name = "template",
1352 .file = "CONFBRIDGE"
1353 };
1356 AST_APP_ARG(option);
1357 );
1358
1359 if (!chan) {
1360 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1361 return -1;
1362 }
1363
1364 /* parse all the required arguments and make sure they exist. */
1365 if (ast_strlen_zero(data)) {
1366 return -1;
1367 }
1368 parse = ast_strdupa(data);
1370 if (ast_strlen_zero(args.type) || ast_strlen_zero(args.option)) {
1371 return -1;
1372 }
1373
1374 ast_channel_lock(chan);
1376 if (!datastore) {
1378 if (!datastore) {
1379 ast_channel_unlock(chan);
1380 return 0;
1381 }
1382 b_data = ast_calloc(1, sizeof(*b_data));
1383 if (!b_data) {
1384 ast_channel_unlock(chan);
1385 ast_datastore_free(datastore);
1386 return 0;
1387 }
1388 datastore->data = b_data;
1390 if (!b_data->b_profile.sounds) {
1391 ast_channel_unlock(chan);
1392 ast_datastore_free(datastore);
1393 return 0;
1394 }
1395 if (!(b_data->menu = menu_alloc("dialplan"))) {
1396 ast_channel_unlock(chan);
1397 ast_datastore_free(datastore);
1398 return 0;
1399 }
1400 ast_channel_datastore_add(chan, datastore);
1401 } else {
1402 b_data = datastore->data;
1403 }
1404 ast_channel_unlock(chan);
1405
1406 /* SET(CONFBRIDGE(type,option)=value) */
1407 if (!value) {
1408 value = "";
1409 }
1410 tmpvar.name = args.option;
1411 tmpvar.value = value;
1412 tmpvar.file = "CONFBRIDGE";
1413 if (!strcasecmp(args.type, "bridge")) {
1414 if (!strcasecmp(args.option, "clear")) {
1415 b_data->b_usable = 0;
1417 memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
1418 if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
1419 /* If this reallocation fails, the datastore has become unusable and must be destroyed. */
1420 ast_channel_lock(chan);
1421 ast_channel_datastore_remove(chan, datastore);
1422 ast_channel_unlock(chan);
1423 ast_datastore_free(datastore);
1424 }
1425 return 0;
1426 }
1427
1428 if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
1429 template.value = DEFAULT_BRIDGE_PROFILE;
1430 aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
1431 }
1432
1433 if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
1434 b_data->b_usable = 1;
1435 return 0;
1436 }
1437 } else if (!strcasecmp(args.type, "user")) {
1438 if (!strcasecmp(args.option, "clear")) {
1439 b_data->u_usable = 0;
1441 memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
1442 return 0;
1443 }
1444
1445 if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
1446 template.value = DEFAULT_USER_PROFILE;
1447 aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
1448 }
1449
1450 if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
1451 b_data->u_usable = 1;
1452 return 0;
1453 }
1454 } else if (!strcasecmp(args.type, "menu")) {
1455 if (!strcasecmp(args.option, "clear")) {
1456 b_data->m_usable = 0;
1457 ao2_cleanup(b_data->menu);
1458 if (!(b_data->menu = menu_alloc("dialplan"))) {
1459 /* If this reallocation fails, the datastore has become unusable and must be destroyed */
1460 ast_channel_lock(chan);
1461 ast_channel_datastore_remove(chan, datastore);
1462 ast_channel_unlock(chan);
1463 ast_datastore_free(datastore);
1464 }
1465 return 0;
1466 }
1467
1468 if (b_data && !b_data->m_usable && strcasecmp(args.option, "template")) {
1469 template.value = DEFAULT_MENU_PROFILE;
1470 aco_process_var(&menu_type, "dialplan", &template, &b_data->menu);
1471 }
1472
1473 if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
1474 b_data->m_usable = 1;
1475 return 0;
1476 }
1477 }
1478
1479 ast_log(LOG_WARNING, "%s(%s,%s) cannot be set to '%s'. Invalid type, option, or value.\n",
1480 cmd, args.type, args.option, value);
1481 return -1;
1482}
1483
1484static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
1485{
1486 struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
1487
1488 if (!menu_action) {
1489 return -1;
1490 }
1491 menu_action->id = id;
1492
1493 switch (id) {
1494 case MENU_ACTION_NOOP:
1507 case MENU_ACTION_LEAVE:
1510 break;
1513 if (!(ast_strlen_zero(databuf))) {
1514 ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
1515 } else {
1516 ast_free(menu_action);
1517 return -1;
1518 }
1519 break;
1521 if (!(ast_strlen_zero(databuf))) {
1523 AST_APP_ARG(context);
1524 AST_APP_ARG(exten);
1526 );
1527 AST_STANDARD_APP_ARGS(args, databuf);
1528 if (!ast_strlen_zero(args.context)) {
1530 args.context,
1531 sizeof(menu_action->data.dialplan_args.context));
1532 }
1533 if (!ast_strlen_zero(args.exten)) {
1535 args.exten,
1536 sizeof(menu_action->data.dialplan_args.exten));
1537 }
1538 menu_action->data.dialplan_args.priority = 1; /* 1 by default */
1539 if (!ast_strlen_zero(args.priority) &&
1540 (sscanf(args.priority, "%30d", &menu_action->data.dialplan_args.priority) != 1)) {
1541 /* invalid priority */
1542 ast_free(menu_action);
1543 return -1;
1544 }
1545 } else {
1546 ast_free(menu_action);
1547 return -1;
1548 }
1549 };
1550
1551 AST_LIST_INSERT_TAIL(&menu_entry->actions, menu_action, action);
1552
1553 return 0;
1554}
1555
1556static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
1557{
1558 struct conf_menu_entry *menu_entry = NULL, *cur = NULL;
1559 int res = 0;
1560 char *tmp_action_names = ast_strdupa(action_names);
1561 char *action = NULL;
1562 char *action_args;
1563 char *tmp;
1564 char buf[PATH_MAX];
1565 char *delimiter = ",";
1566
1567 if (!(menu_entry = ast_calloc(1, sizeof(*menu_entry)))) {
1568 return -1;
1569 }
1570
1571 for (;;) {
1572 char *comma;
1573 char *startbrace;
1574 char *endbrace;
1575 unsigned int action_len;
1576
1577 if (ast_strlen_zero(tmp_action_names)) {
1578 break;
1579 }
1580 startbrace = strchr(tmp_action_names, '(');
1581 endbrace = strchr(tmp_action_names, ')');
1582 comma = strchr(tmp_action_names, ',');
1583
1584 /* If the next action has brackets with comma delimited arguments in it,
1585 * make the delimeter ')' instead of a comma to preserve the arguments */
1586 if (startbrace && endbrace && comma && (comma > startbrace && comma < endbrace)) {
1587 delimiter = ")";
1588 } else {
1589 delimiter = ",";
1590 }
1591
1592 if (!(action = strsep(&tmp_action_names, delimiter))) {
1593 break;
1594 }
1595
1596 action = ast_strip(action);
1597 if (ast_strlen_zero(action)) {
1598 continue;
1599 }
1600
1601 action_len = strlen(action);
1602 ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
1603 if (!strcasecmp(action, "toggle_mute")) {
1605 } else if (!strcasecmp(action, "toggle_binaural")) {
1607 } else if (!strcasecmp(action, "no_op")) {
1608 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL);
1609 } else if (!strcasecmp(action, "increase_listening_volume")) {
1611 } else if (!strcasecmp(action, "decrease_listening_volume")) {
1613 } else if (!strcasecmp(action, "increase_talking_volume")) {
1615 } else if (!strcasecmp(action, "reset_listening_volume")) {
1617 } else if (!strcasecmp(action, "reset_talking_volume")) {
1619 } else if (!strcasecmp(action, "decrease_talking_volume")) {
1621 } else if (!strcasecmp(action, "admin_toggle_conference_lock")) {
1623 } else if (!strcasecmp(action, "admin_toggle_mute_participants")) {
1625 } else if (!strcasecmp(action, "participant_count")) {
1627 } else if (!strcasecmp(action, "admin_kick_last")) {
1629 } else if (!strcasecmp(action, "leave_conference")) {
1630 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL);
1631 } else if (!strcasecmp(action, "set_as_single_video_src")) {
1633 } else if (!strcasecmp(action, "release_as_single_video_src")) {
1635 } else if (!strncasecmp(action, "dialplan_exec(", 14)) {
1636 ast_copy_string(buf, action, sizeof(buf));
1637 action_args = buf;
1638 if ((action_args = strchr(action, '('))) {
1639 action_args++;
1640 }
1641 /* it is possible that this argument may or may not
1642 * have a closing brace at this point, it all depends on if
1643 * comma delimited arguments were provided */
1644 if ((tmp = strchr(action, ')'))) {
1645 *tmp = '\0';
1646 }
1647 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DIALPLAN_EXEC, action_args);
1648 } else if (action_len >= 21 && !strncasecmp(action, "playback_and_continue(", 22)) {
1649 ast_copy_string(buf, action, sizeof(buf));
1650 action_args = buf;
1651 if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1652 *tmp = '\0';
1653 action_args++;
1654 }
1655 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK_AND_CONTINUE, action_args);
1656 } else if (action_len >= 8 && !strncasecmp(action, "playback(", 9)) {
1657 ast_copy_string(buf, action, sizeof(buf));
1658 action_args = buf;
1659 if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1660 *tmp = '\0';
1661 action_args++;
1662 }
1663 res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, action_args);
1664 }
1665 }
1666
1667 /* if adding any of the actions failed, bail */
1668 if (res) {
1669 conf_menu_entry_destroy(menu_entry);
1670 ast_free(menu_entry);
1671 return -1;
1672 }
1673
1674 /* remove any list entry with an identical DTMF sequence for overrides */
1675 AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
1676 if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
1679 ast_free(cur);
1680 break;
1681 }
1682 }
1684
1685 AST_LIST_INSERT_TAIL(&menu->entries, menu_entry, entry);
1686
1687 return 0;
1688}
1689
1690static char *complete_user_profile_name(const char *line, const char *word, int pos, int state)
1691{
1692 int which = 0;
1693 char *res = NULL;
1694 int wordlen = strlen(word);
1695 struct ao2_iterator i;
1696 struct user_profile *u_profile = NULL;
1698
1699 if (!cfg) {
1700 return NULL;
1701 }
1702
1703 i = ao2_iterator_init(cfg->user_profiles, 0);
1704 while ((u_profile = ao2_iterator_next(&i))) {
1705 if (!strncasecmp(u_profile->name, word, wordlen) && ++which > state) {
1706 res = ast_strdup(u_profile->name);
1707 ao2_ref(u_profile, -1);
1708 break;
1709 }
1710 ao2_ref(u_profile, -1);
1711 }
1713
1714 return res;
1715}
1716
1718{
1719 struct ao2_iterator it;
1720 struct user_profile *u_profile;
1721 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1722
1723 switch (cmd) {
1724 case CLI_INIT:
1725 e->command = "confbridge show profile users";
1726 e->usage =
1727 "Usage: confbridge show profile users\n";
1728 return NULL;
1729 case CLI_GENERATE:
1730 return NULL;
1731 }
1732
1733 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1734 return NULL;
1735 }
1736
1737 ast_cli(a->fd,"--------- User Profiles -----------\n");
1738 ao2_lock(cfg->user_profiles);
1739 it = ao2_iterator_init(cfg->user_profiles, 0);
1740 while ((u_profile = ao2_iterator_next(&it))) {
1741 ast_cli(a->fd,"%s\n", u_profile->name);
1742 ao2_ref(u_profile, -1);
1743 }
1745 ao2_unlock(cfg->user_profiles);
1746
1747 return CLI_SUCCESS;
1748}
1750{
1751 struct user_profile u_profile;
1752
1753 switch (cmd) {
1754 case CLI_INIT:
1755 e->command = "confbridge show profile user";
1756 e->usage =
1757 "Usage: confbridge show profile user [<profile name>]\n";
1758 return NULL;
1759 case CLI_GENERATE:
1760 if (a->pos == 4) {
1761 return complete_user_profile_name(a->line, a->word, a->pos, a->n);
1762 }
1763 return NULL;
1764 }
1765
1766 if (a->argc != 5) {
1767 return CLI_SHOWUSAGE;
1768 }
1769
1770 if (!(conf_find_user_profile(NULL, a->argv[4], &u_profile))) {
1771 ast_cli(a->fd, "No conference user profile named '%s' found!\n", a->argv[4]);
1772 return CLI_SUCCESS;
1773 }
1774
1775 ast_cli(a->fd,"--------------------------------------------\n");
1776 ast_cli(a->fd,"Name: %s\n",
1777 u_profile.name);
1778 ast_cli(a->fd,"Admin: %s\n",
1779 u_profile.flags & USER_OPT_ADMIN ?
1780 "true" : "false");
1781 ast_cli(a->fd,"Send Events: %s\n",
1782 u_profile.flags & USER_OPT_SEND_EVENTS ?
1783 "true" : "false");
1784 ast_cli(a->fd,"Echo Events: %s\n",
1785 u_profile.flags & USER_OPT_ECHO_EVENTS ?
1786 "true" : "false");
1787 ast_cli(a->fd,"Marked User: %s\n",
1788 u_profile.flags & USER_OPT_MARKEDUSER ?
1789 "true" : "false");
1790 ast_cli(a->fd,"Start Muted: %s\n",
1791 u_profile.flags & USER_OPT_STARTMUTED?
1792 "true" : "false");
1793 ast_cli(a->fd,"MOH When Empty: %s\n",
1794 u_profile.flags & USER_OPT_MUSICONHOLD ?
1795 "enabled" : "disabled");
1796 ast_cli(a->fd,"MOH Class: %s\n",
1797 ast_strlen_zero(u_profile.moh_class) ?
1798 "default" : u_profile.moh_class);
1799 ast_cli(a->fd,"Announcement: %s\n",
1800 u_profile.announcement);
1801 ast_cli(a->fd,"Quiet: %s\n",
1802 u_profile.flags & USER_OPT_QUIET ?
1803 "enabled" : "disabled");
1804 ast_cli(a->fd,"Hear Join: %s\n",
1806 "enabled" : "disabled");
1807 ast_cli(a->fd,"Wait Marked: %s\n",
1808 u_profile.flags & USER_OPT_WAITMARKED ?
1809 "enabled" : "disabled");
1810 ast_cli(a->fd,"END Marked (All): %s\n",
1811 u_profile.flags & USER_OPT_ENDMARKED ?
1812 "enabled" : "disabled");
1813 ast_cli(a->fd,"END Marked (Any): %s\n",
1814 u_profile.flags & USER_OPT_ENDMARKEDANY ?
1815 "enabled" : "disabled");
1816 ast_cli(a->fd,"Drop_silence: %s\n",
1817 u_profile.flags & USER_OPT_DROP_SILENCE ?
1818 "enabled" : "disabled");
1819 ast_cli(a->fd,"Silence Threshold: %ums\n",
1820 u_profile.silence_threshold);
1821 ast_cli(a->fd,"Talking Threshold: %u\n",
1822 u_profile.talking_threshold);
1823 ast_cli(a->fd,"Denoise: %s\n",
1824 u_profile.flags & USER_OPT_DENOISE ?
1825 "enabled" : "disabled");
1826 ast_cli(a->fd,"Jitterbuffer: %s\n",
1827 u_profile.flags & USER_OPT_JITTERBUFFER ?
1828 "enabled" : "disabled");
1829 ast_cli(a->fd,"Talk Detect Events: %s\n",
1830 u_profile.flags & USER_OPT_TALKER_DETECT ?
1831 "enabled" : "disabled");
1832 ast_cli(a->fd,"DTMF Pass Through: %s\n",
1833 u_profile.flags & USER_OPT_DTMF_PASS ?
1834 "enabled" : "disabled");
1835 ast_cli(a->fd,"PIN: %s\n",
1836 ast_strlen_zero(u_profile.pin) ?
1837 "None" : u_profile.pin);
1838 ast_cli(a->fd,"Announce User Count: %s\n",
1839 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
1840 "enabled" : "disabled");
1841 ast_cli(a->fd,"Announce join/leave: %s\n",
1844 "enabled (with review)" : "enabled" : "disabled");
1845 ast_cli(a->fd,"Announce User Count all: %s\n",
1847 "enabled" : "disabled");
1848 ast_cli(a->fd,"Text Messaging: %s\n",
1849 u_profile.flags & USER_OPT_TEXT_MESSAGING ?
1850 "enabled" : "disabled");
1851 ast_cli(a->fd,"Answer Channel: %s\n",
1852 u_profile.flags & USER_OPT_ANSWER_CHANNEL ?
1853 "true" : "false");
1854 ast_cli(a->fd, "\n");
1855
1856 return CLI_SUCCESS;
1857}
1858
1859static char *complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
1860{
1861 int which = 0;
1862 char *res = NULL;
1863 int wordlen = strlen(word);
1864 struct ao2_iterator i;
1865 struct bridge_profile *b_profile = NULL;
1867
1868 if (!cfg) {
1869 return NULL;
1870 }
1871
1872 i = ao2_iterator_init(cfg->bridge_profiles, 0);
1873 while ((b_profile = ao2_iterator_next(&i))) {
1874 if (!strncasecmp(b_profile->name, word, wordlen) && ++which > state) {
1875 res = ast_strdup(b_profile->name);
1876 ao2_ref(b_profile, -1);
1877 break;
1878 }
1879 ao2_ref(b_profile, -1);
1880 }
1882
1883 return res;
1884}
1885
1887{
1888 struct ao2_iterator it;
1889 struct bridge_profile *b_profile;
1890 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1891
1892 switch (cmd) {
1893 case CLI_INIT:
1894 e->command = "confbridge show profile bridges";
1895 e->usage =
1896 "Usage: confbridge show profile bridges\n";
1897 return NULL;
1898 case CLI_GENERATE:
1899 return NULL;
1900 }
1901
1902 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1903 return NULL;
1904 }
1905
1906 ast_cli(a->fd,"--------- Bridge Profiles -----------\n");
1907 ao2_lock(cfg->bridge_profiles);
1908 it = ao2_iterator_init(cfg->bridge_profiles, 0);
1909 while ((b_profile = ao2_iterator_next(&it))) {
1910 ast_cli(a->fd,"%s\n", b_profile->name);
1911 ao2_ref(b_profile, -1);
1912 }
1914 ao2_unlock(cfg->bridge_profiles);
1915
1916 return CLI_SUCCESS;
1917}
1918
1920{
1921 struct bridge_profile b_profile;
1922 char tmp[64];
1923
1924 switch (cmd) {
1925 case CLI_INIT:
1926 e->command = "confbridge show profile bridge";
1927 e->usage =
1928 "Usage: confbridge show profile bridge <profile name>\n";
1929 return NULL;
1930 case CLI_GENERATE:
1931 if (a->pos == 4) {
1932 return complete_bridge_profile_name(a->line, a->word, a->pos, a->n);
1933 }
1934 return NULL;
1935 }
1936
1937 if (a->argc != 5) {
1938 return CLI_SHOWUSAGE;
1939 }
1940
1941 if (!(conf_find_bridge_profile(NULL, a->argv[4], &b_profile))) {
1942 ast_cli(a->fd, "No conference bridge profile named '%s' found!\n", a->argv[4]);
1943 return CLI_SUCCESS;
1944 }
1945
1946 ast_cli(a->fd,"--------------------------------------------\n");
1947 ast_cli(a->fd,"Name: %s\n", b_profile.name);
1948 ast_cli(a->fd,"Language: %s\n", b_profile.language);
1949
1950 if (b_profile.internal_sample_rate) {
1951 snprintf(tmp, sizeof(tmp), "%u", b_profile.internal_sample_rate);
1952 } else {
1953 ast_copy_string(tmp, "auto", sizeof(tmp));
1954 }
1955 ast_cli(a->fd,"Internal Sample Rate: %s\n", tmp);
1956
1957 if (b_profile.maximum_sample_rate) {
1958 snprintf(tmp, sizeof(tmp), "%u", b_profile.maximum_sample_rate);
1959 } else {
1960 ast_copy_string(tmp, "none", sizeof(tmp));
1961 }
1962 ast_cli(a->fd,"Maximum Sample Rate: %s\n", tmp);
1963
1964 if (b_profile.mix_interval) {
1965 ast_cli(a->fd,"Mixing Interval: %u\n", b_profile.mix_interval);
1966 } else {
1967 ast_cli(a->fd,"Mixing Interval: Default 20ms\n");
1968 }
1969
1970 ast_cli(a->fd,"Record Conference: %s\n",
1972 "yes" : "no");
1973
1974 ast_cli(a->fd,"Record File Append: %s\n",
1976 "yes" : "no");
1977
1978 ast_cli(a->fd,"Record File Timestamp: %s\n",
1980 "yes" : "no");
1981
1982 ast_cli(a->fd,"Record File: %s\n",
1983 ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
1984 b_profile.rec_file);
1985
1986 ast_cli(a->fd,"Record Options: %s\n",
1987 b_profile.rec_options);
1988
1989 ast_cli(a->fd,"Record Command: %s\n",
1990 b_profile.rec_command);
1991
1992 if (b_profile.max_members) {
1993 ast_cli(a->fd,"Max Members: %u\n", b_profile.max_members);
1994 } else {
1995 ast_cli(a->fd,"Max Members: No Limit\n");
1996 }
1997
1998 ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext);
1999
2000 switch (b_profile.flags
2006 ast_cli(a->fd, "Video Mode: last_marked\n");
2007 break;
2009 ast_cli(a->fd, "Video Mode: first_marked\n");
2010 break;
2012 ast_cli(a->fd, "Video Mode: follow_talker\n");
2013 break;
2015 ast_cli(a->fd, "Video Mode: sfu\n");
2016 break;
2017 case 0:
2018 ast_cli(a->fd, "Video Mode: no video\n");
2019 break;
2020 default:
2021 /* Opps. We have more than one video mode flag set. */
2022 ast_assert(0);
2023 break;
2024 }
2025
2026 ast_cli(a->fd,"Video Update Discard: %u\n", b_profile.video_update_discard);
2027 ast_cli(a->fd,"REMB Send Interval: %u\n", b_profile.remb_send_interval);
2028
2029 switch (b_profile.flags
2034 ast_cli(a->fd, "REMB Behavior: average\n");
2035 break;
2037 ast_cli(a->fd, "REMB Behavior: lowest\n");
2038 break;
2040 ast_cli(a->fd, "REMB Behavior: highest\n");
2041 break;
2043 ast_cli(a->fd, "REMB Behavior: average_all\n");
2044 break;
2046 ast_cli(a->fd, "REMB Behavior: lowest_all\n");
2047 break;
2049 ast_cli(a->fd, "REMB Behavior: highest_all\n");
2050 break;
2051 default:
2052 ast_assert(0);
2053 break;
2054 }
2055
2056 ast_cli(a->fd,"Enable Events: %s\n",
2057 b_profile.flags & BRIDGE_OPT_ENABLE_EVENTS ?
2058 "yes" : "no");
2059
2060 ast_cli(a->fd,"Announcements: %s\n",
2061 b_profile.flags & BRIDGE_OPT_ANNOUNCEMENTS ?
2062 "yes" : "no");
2063
2064 ast_cli(a->fd,"sound_only_person: %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds));
2065 ast_cli(a->fd,"sound_only_one: %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds));
2066 ast_cli(a->fd,"sound_has_joined: %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds));
2067 ast_cli(a->fd,"sound_has_left: %s\n", conf_get_sound(CONF_SOUND_HAS_LEFT, b_profile.sounds));
2068 ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
2069 ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
2070 ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
2071 ast_cli(a->fd,"sound_binaural_on: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_ON, b_profile.sounds));
2072 ast_cli(a->fd,"sound_binaural_off: %s\n", conf_get_sound(CONF_SOUND_BINAURAL_OFF, b_profile.sounds));
2073 ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
2074 ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
2075 ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
2076 ast_cli(a->fd,"sound_wait_for_leader: %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
2077 ast_cli(a->fd,"sound_leader_has_left: %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
2078 ast_cli(a->fd,"sound_get_pin: %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
2079 ast_cli(a->fd,"sound_invalid_pin: %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
2080 ast_cli(a->fd,"sound_locked: %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));
2081 ast_cli(a->fd,"sound_unlocked_now: %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds));
2082 ast_cli(a->fd,"sound_lockednow: %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds));
2083 ast_cli(a->fd,"sound_error_menu: %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds));
2084 ast_cli(a->fd,"sound_join: %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds));
2085 ast_cli(a->fd,"sound_leave: %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds));
2086 ast_cli(a->fd,"sound_participants_muted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds));
2087 ast_cli(a->fd,"sound_participants_unmuted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds));
2088 ast_cli(a->fd,"sound_begin: %s\n", conf_get_sound(CONF_SOUND_BEGIN, b_profile.sounds));
2089 ast_cli(a->fd,"\n");
2090
2091 conf_bridge_profile_destroy(&b_profile);
2092 return CLI_SUCCESS;
2093}
2094
2095static char *complete_menu_name(const char *line, const char *word, int pos, int state)
2096{
2097 int which = 0;
2098 char *res = NULL;
2099 int wordlen = strlen(word);
2100 struct ao2_iterator i;
2101 struct conf_menu *menu = NULL;
2103
2104 if (!cfg) {
2105 return NULL;
2106 }
2107
2108 i = ao2_iterator_init(cfg->menus, 0);
2109 while ((menu = ao2_iterator_next(&i))) {
2110 if (!strncasecmp(menu->name, word, wordlen) && ++which > state) {
2111 res = ast_strdup(menu->name);
2112 ao2_ref(menu, -1);
2113 break;
2114 }
2115 ao2_ref(menu, -1);
2116 }
2118
2119 return res;
2120}
2121
2122static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2123{
2124 struct ao2_iterator it;
2125 struct conf_menu *menu;
2126 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
2127
2128 switch (cmd) {
2129 case CLI_INIT:
2130 e->command = "confbridge show menus";
2131 e->usage =
2132 "Usage: confbridge show profile menus\n";
2133 return NULL;
2134 case CLI_GENERATE:
2135 return NULL;
2136 }
2137
2138 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
2139 return NULL;
2140 }
2141
2142 ast_cli(a->fd,"--------- Menus -----------\n");
2143 ao2_lock(cfg->menus);
2144 it = ao2_iterator_init(cfg->menus, 0);
2145 while ((menu = ao2_iterator_next(&it))) {
2146 ast_cli(a->fd,"%s\n", menu->name);
2147 ao2_ref(menu, -1);
2148 }
2150 ao2_unlock(cfg->menus);
2151
2152 return CLI_SUCCESS;
2153}
2154
2155static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2156{
2157 RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2158 RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
2159 struct conf_menu_entry *menu_entry = NULL;
2160 struct conf_menu_action *menu_action = NULL;
2161
2162 switch (cmd) {
2163 case CLI_INIT:
2164 e->command = "confbridge show menu";
2165 e->usage =
2166 "Usage: confbridge show menu [<menu name>]\n";
2167 return NULL;
2168 case CLI_GENERATE:
2169 if (a->pos == 3) {
2170 return complete_menu_name(a->line, a->word, a->pos, a->n);
2171 }
2172 return NULL;
2173 }
2174
2175 if (a->argc != 4) {
2176 return CLI_SHOWUSAGE;
2177 }
2178
2179 if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
2180 return NULL;
2181 }
2182
2183 if (!(menu = menu_find(cfg->menus, a->argv[3]))) {
2184 ast_cli(a->fd, "No conference menu named '%s' found!\n", a->argv[3]);
2185 return CLI_SUCCESS;
2186 }
2187 ao2_lock(menu);
2188
2189 ast_cli(a->fd,"Name: %s\n", menu->name);
2190 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2191 int action_num = 0;
2192 ast_cli(a->fd, "%s=", menu_entry->dtmf);
2193 AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
2194 if (action_num) {
2195 ast_cli(a->fd, ", ");
2196 }
2197 switch (menu_action->id) {
2199 ast_cli(a->fd, "toggle_mute");
2200 break;
2202 ast_cli(a->fd, "toggle_binaural");
2203 break;
2204 case MENU_ACTION_NOOP:
2205 ast_cli(a->fd, "no_op");
2206 break;
2208 ast_cli(a->fd, "increase_listening_volume");
2209 break;
2211 ast_cli(a->fd, "decrease_listening_volume");
2212 break;
2214 ast_cli(a->fd, "reset_listening_volume");
2215 break;
2217 ast_cli(a->fd, "reset_talking_volume");
2218 break;
2220 ast_cli(a->fd, "increase_talking_volume");
2221 break;
2223 ast_cli(a->fd, "decrease_talking_volume");
2224 break;
2226 ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
2227 break;
2229 ast_cli(a->fd, "playback_and_continue(%s)", menu_action->data.playback_file);
2230 break;
2232 ast_cli(a->fd, "dialplan_exec(%s,%s,%d)",
2233 menu_action->data.dialplan_args.context,
2234 menu_action->data.dialplan_args.exten,
2235 menu_action->data.dialplan_args.priority);
2236 break;
2238 ast_cli(a->fd, "admin_toggle_conference_lock");
2239 break;
2241 ast_cli(a->fd, "admin_toggle_mute_participants");
2242 break;
2244 ast_cli(a->fd, "participant_count");
2245 break;
2247 ast_cli(a->fd, "admin_kick_last");
2248 break;
2249 case MENU_ACTION_LEAVE:
2250 ast_cli(a->fd, "leave_conference");
2251 break;
2253 ast_cli(a->fd, "set_as_single_video_src");
2254 break;
2256 ast_cli(a->fd, "release_as_single_video_src");
2257 break;
2258 }
2259 action_num++;
2260 }
2261 ast_cli(a->fd,"\n");
2262 }
2263
2264
2265 ao2_unlock(menu);
2266 return CLI_SUCCESS;
2267}
2268
2270 AST_CLI_DEFINE(handle_cli_confbridge_show_user_profile, "Show a conference user profile."),
2271 AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profile, "Show a conference bridge profile."),
2272 AST_CLI_DEFINE(handle_cli_confbridge_show_menu, "Show a conference menu"),
2273 AST_CLI_DEFINE(handle_cli_confbridge_show_user_profiles, "Show a list of conference user profiles."),
2274 AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profiles, "Show a list of conference bridge profiles."),
2275 AST_CLI_DEFINE(handle_cli_confbridge_show_menus, "Show a list of conference menus"),
2276
2277};
2278
2279static void confbridge_cfg_destructor(void *obj)
2280{
2281 struct confbridge_cfg *cfg = obj;
2284 ao2_cleanup(cfg->menus);
2285}
2286
2288{
2289 struct confbridge_cfg *cfg;
2290
2291 if (!(cfg = ao2_alloc(sizeof(*cfg), confbridge_cfg_destructor))) {
2292 return NULL;
2293 }
2294
2297 if (!cfg->user_profiles) {
2298 goto error;
2299 }
2300
2303 if (!cfg->bridge_profiles) {
2304 goto error;
2305 }
2306
2309 if (!cfg->menus) {
2310 goto error;
2311 }
2312
2313 return cfg;
2314error:
2315 ao2_ref(cfg, -1);
2316 return NULL;
2317}
2318
2319static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2320{
2321 struct user_profile *u_profile = obj;
2322
2323 if (strcasecmp(var->name, "announce_user_count_all")) {
2324 return -1;
2325 }
2326 if (ast_true(var->value)) {
2327 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2328 } else if (ast_false(var->value)) {
2329 u_profile->flags = u_profile->flags & ~USER_OPT_ANNOUNCEUSERCOUNTALL;
2330 } else if (sscanf(var->value, "%30u", &u_profile->announce_user_count_all_after) == 1) {
2331 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
2332 } else {
2333 return -1;
2334 }
2335 return 0;
2336}
2337
2338static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2339{
2340 struct bridge_profile *b_profile = obj;
2341
2342 if (strcasecmp(var->name, "mixing_interval")) {
2343 return -1;
2344 }
2345 if (sscanf(var->value, "%30u", &b_profile->mix_interval) != 1) {
2346 return -1;
2347 }
2348 switch (b_profile->mix_interval) {
2349 case 10:
2350 case 20:
2351 case 40:
2352 case 80:
2353 return 0;
2354 default:
2355 return -1;
2356 }
2357}
2358
2359static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2360{
2361 struct bridge_profile *b_profile = obj;
2362
2363 if (strcasecmp(var->name, "video_mode")) {
2364 return -1;
2365 }
2366 if (!strcasecmp(var->value, "first_marked")) {
2367 ast_set_flags_to(b_profile,
2373 } else if (!strcasecmp(var->value, "last_marked")) {
2374 ast_set_flags_to(b_profile,
2380 } else if (!strcasecmp(var->value, "follow_talker")) {
2381 ast_set_flags_to(b_profile,
2387 } else if (!strcasecmp(var->value, "sfu")) {
2388 ast_set_flags_to(b_profile,
2394 } else if (!strcasecmp(var->value, "none")) {
2395 ast_clear_flag(b_profile,
2400 } else {
2401 return -1;
2402 }
2403 return 0;
2404}
2405
2406static int remb_behavior_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2407{
2408 struct bridge_profile *b_profile = obj;
2409
2410 if (strcasecmp(var->name, "remb_behavior")) {
2411 return -1;
2412 }
2413
2421 );
2422
2423 if (!strcasecmp(var->value, "average")) {
2425 } else if (!strcasecmp(var->value, "lowest")) {
2427 } else if (!strcasecmp(var->value, "highest")) {
2429 } else if (!strcasecmp(var->value, "average_all")) {
2431 } else if (!strcasecmp(var->value, "lowest_all")) {
2433 } else if (!strcasecmp(var->value, "highest_all")) {
2435 } else if (!strcasecmp(var->value, "force")) {
2437 } else {
2438 return -1;
2439 }
2440 return 0;
2441}
2442
2443static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2444{
2445 struct user_profile *u_profile = obj;
2446
2447 return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
2448}
2449
2450static int sample_rate_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2451{
2452 struct bridge_profile *b_profile = obj;
2453 unsigned int *slot;
2454
2455 if (!strcasecmp(var->name, "internal_sample_rate")) {
2456 slot = &b_profile->internal_sample_rate;
2457 if (!strcasecmp(var->value, "auto")) {
2458 *slot = 0;
2459 return 0;
2460 }
2461 } else if (!strcasecmp(var->name, "maximum_sample_rate")) {
2462 slot = &b_profile->maximum_sample_rate;
2463 if (!strcasecmp(var->value, "none")) {
2464 *slot = 0;
2465 return 0;
2466 }
2467 } else {
2468 return -1;
2469 }
2470
2471 return ast_parse_arg(var->value, PARSE_UINT32 | PARSE_IN_RANGE, slot, 8000, 192000);
2472}
2473
2474static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2475{
2476 struct bridge_profile *b_profile = obj;
2478 struct bridge_profile_sounds *oldsounds = b_profile->sounds;
2479
2480 if (!sounds) {
2481 return -1;
2482 }
2483 if (!(conf_find_bridge_profile(NULL, var->value, b_profile))) {
2484 ao2_ref(sounds, -1);
2485 return -1;
2486 }
2487 /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds
2488 * structure of a dynamic profile will need to be altered, a completely new sounds structure must be
2489 * created instead of simply holding a reference to the one built by the config file. */
2490 ast_string_field_set(sounds, onlyperson, b_profile->sounds->onlyperson);
2491 ast_string_field_set(sounds, onlyone, b_profile->sounds->onlyone);
2492 ast_string_field_set(sounds, hasjoin, b_profile->sounds->hasjoin);
2493 ast_string_field_set(sounds, hasleft, b_profile->sounds->hasleft);
2494 ast_string_field_set(sounds, kicked, b_profile->sounds->kicked);
2495 ast_string_field_set(sounds, muted, b_profile->sounds->muted);
2496 ast_string_field_set(sounds, unmuted, b_profile->sounds->unmuted);
2497 ast_string_field_set(sounds, thereare, b_profile->sounds->thereare);
2498 ast_string_field_set(sounds, otherinparty, b_profile->sounds->otherinparty);
2499 ast_string_field_set(sounds, placeintoconf, b_profile->sounds->placeintoconf);
2500 ast_string_field_set(sounds, waitforleader, b_profile->sounds->waitforleader);
2501 ast_string_field_set(sounds, leaderhasleft, b_profile->sounds->leaderhasleft);
2502 ast_string_field_set(sounds, getpin, b_profile->sounds->getpin);
2503 ast_string_field_set(sounds, invalidpin, b_profile->sounds->invalidpin);
2504 ast_string_field_set(sounds, locked, b_profile->sounds->locked);
2505 ast_string_field_set(sounds, unlockednow, b_profile->sounds->unlockednow);
2506 ast_string_field_set(sounds, lockednow, b_profile->sounds->lockednow);
2507 ast_string_field_set(sounds, errormenu, b_profile->sounds->errormenu);
2508 ast_string_field_set(sounds, join, b_profile->sounds->join);
2510 ast_string_field_set(sounds, participantsmuted, b_profile->sounds->participantsmuted);
2511 ast_string_field_set(sounds, participantsunmuted, b_profile->sounds->participantsunmuted);
2512 ast_string_field_set(sounds, begin, b_profile->sounds->begin);
2513
2514 ao2_ref(b_profile->sounds, -1); /* sounds struct copied over to it from the template by reference only. */
2515 ao2_ref(oldsounds, -1); /* original sounds struct we don't need anymore */
2516 b_profile->sounds = sounds; /* the new sounds struct that is a deep copy of the one from the template. */
2517
2518 return 0;
2519}
2520
2521static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
2522{
2523 struct conf_menu_action *menu_action;
2524 struct conf_menu_action *new_menu_action;
2525
2526 ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
2528
2529 AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
2530 if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
2531 return -1;
2532 }
2533 memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
2534 AST_LIST_NEXT(new_menu_action, action) = NULL;
2535 AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
2536 }
2537
2538 return 0;
2539}
2540
2541static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
2542{
2543 /* Copy each menu item to the dst struct */
2544 struct conf_menu_entry *cur;
2545
2546 AST_LIST_TRAVERSE(&src->entries, cur, entry) {
2547 struct conf_menu_entry *cpy;
2548
2549 if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
2550 return -1;
2551 }
2552
2553 if (copy_menu_entry(cpy, cur)) {
2555 ast_free(cpy);
2556 return -1;
2557 }
2558 AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
2559 }
2560
2561 return 0;
2562}
2563
2564static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2565{
2566 struct conf_menu *dst_menu = obj;
2568 RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
2569
2570 if (!cfg) {
2571 return 0;
2572 }
2573
2574 if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
2575 return -1;
2576 }
2577
2578 if (conf_menu_profile_copy(dst_menu, src_menu)) {
2579 return -1;
2580 }
2581
2582 return 0;
2583}
2584
2585static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2586{
2587 set_sound(var->name, var->value, obj);
2588 return 0;
2589}
2590
2591static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2592{
2593 add_menu_entry(obj, var->name, var->value);
2594 return 0;
2595}
2596
2598{
2601 RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
2602 /* We can only be called as a result of an aco_process_config so this is safe */
2603 struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
2604
2605 if (!cfg) {
2606 return 0;
2607 }
2608
2610 if (!bridge_profile) {
2612 if (!bridge_profile) {
2613 return -1;
2614 }
2615 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_BRIDGE_PROFILE);
2618 }
2619
2621 if (!user_profile) {
2623 if (!user_profile) {
2624 return -1;
2625 }
2626 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_USER_PROFILE);
2629 }
2630
2631 menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
2632 if (!menu_profile) {
2633 menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
2634 if (!menu_profile) {
2635 return -1;
2636 }
2637 ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
2639 ao2_link(cfg->menus, menu_profile);
2640 }
2641
2642 return 0;
2643}
2644
2646{
2647 if (aco_info_init(&cfg_info)) {
2648 return -1;
2649 }
2650
2651 /* User options */
2652 aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
2653 aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
2654 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);
2655 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);
2656 aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
2657 aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
2658 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);
2659 aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
2660 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);
2661 aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
2662 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);
2663 /* Negative logic. Defaults to "yes" and evaluates with ast_false(). If !ast_false(), USER_OPT_NOONLYPERSON is cleared */
2664 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);
2665 aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
2666 aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
2667 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);
2668 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);
2669 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);
2670 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);
2671 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);
2673 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));
2674 aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
2675 aco_option_register(&cfg_info, "denoise", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DENOISE);
2676 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);
2677 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));
2678 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));
2679 aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER);
2680 aco_option_register(&cfg_info, "timeout", ACO_EXACT, user_types, "0", OPT_UINT_T, 0, FLDSET(struct user_profile, timeout));
2681 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);
2682 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);
2683
2684 /* This option should only be used with the CONFBRIDGE dialplan function */
2686
2687/* XXX ASTERISK-21271 need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
2688 /* Bridge options */
2689 aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
2690 aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
2691 aco_option_register_custom(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "auto", sample_rate_handler, 0);
2692 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);
2693 aco_option_register_custom(&cfg_info, "maximum_sample_rate", ACO_EXACT, bridge_types, "none", sample_rate_handler, 0);
2694 aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
2695 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);
2697 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);
2698 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);
2699 aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
2700 aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
2701 aco_option_register(&cfg_info, "record_options", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_options));
2702 aco_option_register(&cfg_info, "record_command", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_command));
2706 aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard));
2707 aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval));
2708 aco_option_register_custom(&cfg_info, "remb_behavior", ACO_EXACT, bridge_types, "average", remb_behavior_handler, 0);
2709 aco_option_register(&cfg_info, "remb_estimated_bitrate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_estimated_bitrate));
2710 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);
2711 aco_option_register(&cfg_info, "announcements", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_ANNOUNCEMENTS);
2712 /* This option should only be used with the CONFBRIDGE dialplan function */
2714
2715 /* Menu options */
2716 aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
2717 /* This option should only be used with the CONFBRIDGE dialplan function */
2719 aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
2720
2721 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
2722 goto error;
2723 }
2724
2726 goto error;
2727 }
2728
2729 return 0;
2730error:
2732 return -1;
2733}
2734
2736{
2737 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2738 /* On a reload, just keep the config we already have in place. */
2739 return -1;
2740 }
2741 return 0;
2742}
2743
2744static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
2745{
2746 *dst = *src;
2747}
2748
2749const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
2750{
2751 struct user_profile *tmp2;
2752 struct ast_datastore *datastore = NULL;
2753 struct func_confbridge_data *b_data = NULL;
2755
2756 if (chan && ast_strlen_zero(user_profile_name)) {
2757 ast_channel_lock(chan);
2759 ast_channel_unlock(chan);
2760 if (datastore) {
2761 b_data = datastore->data;
2762 if (b_data->u_usable) {
2764 return result;
2765 }
2766 }
2767 }
2768
2769 if (!cfg) {
2770 return NULL;
2771 }
2772 if (ast_strlen_zero(user_profile_name)) {
2773 user_profile_name = DEFAULT_USER_PROFILE;
2774 }
2775 if (!(tmp2 = ao2_find(cfg->user_profiles, user_profile_name, OBJ_KEY))) {
2776 return NULL;
2777 }
2778 ao2_lock(tmp2);
2780 ao2_unlock(tmp2);
2781 ao2_ref(tmp2, -1);
2782
2783 return result;
2784}
2785
2787{
2788 *dst = *src;
2789 if (src->sounds) {
2790 ao2_ref(src->sounds, +1);
2791 }
2792}
2793
2795{
2796 if (b_profile->sounds) {
2797 ao2_ref(b_profile->sounds, -1);
2798 b_profile->sounds = NULL;
2799 }
2800}
2801
2802const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
2803{
2804 struct bridge_profile *tmp2;
2805 struct ast_datastore *datastore = NULL;
2806 struct func_confbridge_data *b_data = NULL;
2808
2809 if (chan && ast_strlen_zero(bridge_profile_name)) {
2810 ast_channel_lock(chan);
2812 ast_channel_unlock(chan);
2813 if (datastore) {
2814 b_data = datastore->data;
2815 if (b_data->b_usable) {
2817 return result;
2818 }
2819 }
2820 }
2821
2822 if (!cfg) {
2823 return NULL;
2824 }
2825 if (ast_strlen_zero(bridge_profile_name)) {
2826 bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
2827 }
2828 if (!(tmp2 = ao2_find(cfg->bridge_profiles, bridge_profile_name, OBJ_KEY))) {
2829 return NULL;
2830 }
2831 ao2_lock(tmp2);
2833 ao2_unlock(tmp2);
2834 ao2_ref(tmp2, -1);
2835
2836 return result;
2837}
2838
2844
2845static void menu_hook_destroy(void *hook_pvt)
2846{
2847 struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2848 struct conf_menu_action *action = NULL;
2849
2850 ao2_cleanup(pvt->menu);
2851
2852 while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
2853 ast_free(action);
2854 }
2855 ast_free(pvt);
2856}
2857
2858static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
2859{
2860 struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2861
2862 return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
2863}
2864
2866{
2867 struct conf_menu_action *menu_action = NULL;
2868 while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
2869 ast_free(menu_action);
2870 }
2871}
2872
2873int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
2874{
2875 struct conf_menu_entry *menu_entry = NULL;
2876
2877 ao2_lock(menu);
2878 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2879 if (!strcasecmp(menu_entry->dtmf, dtmf_sequence)) {
2880 copy_menu_entry(result, menu_entry);
2881 ao2_unlock(menu);
2882 return 1;
2883 }
2884 }
2885 ao2_unlock(menu);
2886
2887 return 0;
2888}
2889
2890static int apply_menu_to_user(struct confbridge_user *user, struct conf_menu *menu)
2891{
2892 struct conf_menu_entry *menu_entry;
2893
2894 SCOPED_AO2LOCK(menu_lock, menu);
2895 AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2896 struct dtmf_menu_hook_pvt *pvt;
2897
2898 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
2899 return -1;
2900 }
2901 pvt->user = user;
2902 pvt->menu = ao2_bump(menu);
2903
2904 if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
2905 menu_hook_destroy(pvt);
2906 return -1;
2907 }
2908
2909 if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
2911 menu_hook_destroy(pvt);
2912 }
2913 }
2914 strcpy(user->menu_name, menu->name); /* Safe */
2915
2916 return 0;
2917}
2918
2919int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
2920{
2922 RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2923
2924 if (chan && ast_strlen_zero(menu_profile_name)) {
2925 struct ast_datastore *datastore;
2926 struct func_confbridge_data *b_data;
2927
2928 ast_channel_lock(chan);
2930 ast_channel_unlock(chan);
2931 if (datastore) {
2932 /* If a menu exists in the CONFBRIDGE function datastore, use it. */
2933 b_data = datastore->data;
2934 if (b_data->m_usable) {
2935 menu = ao2_bump(b_data->menu);
2936 return apply_menu_to_user(user, menu);
2937 }
2938 }
2939 }
2940
2941 /* Otherwise, we need to get whatever menu profile is specified to use (or default). */
2942 if (!cfg) {
2943 return -1;
2944 }
2945
2946 if (ast_strlen_zero(menu_profile_name)) {
2947 menu_profile_name = DEFAULT_MENU_PROFILE;
2948 }
2949
2950 if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
2951 return -1;
2952 }
2953
2954 return apply_menu_to_user(user, menu);
2955}
2956
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
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:1790
#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_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Definition astobj2.h:847
#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:3391
static int priority
static PGresult * result
Definition cel_pgsql.c:84
static char regcontext[AST_MAX_CONTEXT]
Definition chan_iax2.c:362
static char language[MAX_LANGUAGE]
Definition chan_iax2.c:361
static const char type[]
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2385
#define ast_channel_lock(chan)
Definition channel.h:2983
#define ast_channel_unlock(chan)
Definition channel.h:2984
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:2390
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#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)
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 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:189
@ CONF_SOUND_OTHER_IN_PARTY
Definition confbridge.h:178
@ CONF_SOUND_INVALID_PIN
Definition confbridge.h:183
@ CONF_SOUND_LOCKED_NOW
Definition confbridge.h:186
@ CONF_SOUND_THERE_ARE
Definition confbridge.h:177
@ CONF_SOUND_ONLY_ONE
Definition confbridge.h:176
@ CONF_SOUND_GET_PIN
Definition confbridge.h:182
@ CONF_SOUND_ERROR_MENU
Definition confbridge.h:188
@ CONF_SOUND_PARTICIPANTS_UNMUTED
Definition confbridge.h:192
@ CONF_SOUND_BINAURAL_ON
Definition confbridge.h:194
@ CONF_SOUND_ONLY_PERSON
Definition confbridge.h:184
@ CONF_SOUND_BEGIN
Definition confbridge.h:193
@ CONF_SOUND_PARTICIPANTS_MUTED
Definition confbridge.h:191
@ CONF_SOUND_WAIT_FOR_LEADER
Definition confbridge.h:180
@ CONF_SOUND_HAS_LEFT
Definition confbridge.h:172
@ CONF_SOUND_BINAURAL_OFF
Definition confbridge.h:195
@ CONF_SOUND_LEAVE
Definition confbridge.h:190
@ CONF_SOUND_LEADER_HAS_LEFT
Definition confbridge.h:181
@ CONF_SOUND_PLACE_IN_CONF
Definition confbridge.h:179
@ CONF_SOUND_HAS_JOINED
Definition confbridge.h:171
@ CONF_SOUND_UNLOCKED_NOW
Definition confbridge.h:187
@ CONF_SOUND_UNMUTED
Definition confbridge.h:175
@ CONF_SOUND_MUTED
Definition confbridge.h:174
@ CONF_SOUND_LOCKED
Definition confbridge.h:185
@ CONF_SOUND_KICKED
Definition confbridge.h:173
#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_ANNOUNCEMENTS
Definition confbridge.h:94
@ 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:97
@ MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC
Definition confbridge.h:113
@ MENU_ACTION_SET_SINGLE_VIDEO_SRC
Definition confbridge.h:112
@ MENU_ACTION_ADMIN_KICK_LAST
Definition confbridge.h:109
@ MENU_ACTION_TOGGLE_BINAURAL
Definition confbridge.h:116
@ MENU_ACTION_PLAYBACK
Definition confbridge.h:99
@ MENU_ACTION_LEAVE
Definition confbridge.h:110
@ MENU_ACTION_RESET_LISTENING
Definition confbridge.h:103
@ MENU_ACTION_INCREASE_TALKING
Definition confbridge.h:105
@ MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS
Definition confbridge.h:115
@ MENU_ACTION_INCREASE_LISTENING
Definition confbridge.h:101
@ MENU_ACTION_DIALPLAN_EXEC
Definition confbridge.h:107
@ MENU_ACTION_DECREASE_LISTENING
Definition confbridge.h:102
@ MENU_ACTION_PLAYBACK_AND_CONTINUE
Definition confbridge.h:100
@ MENU_ACTION_ADMIN_TOGGLE_LOCK
Definition confbridge.h:108
@ MENU_ACTION_DECREASE_TALKING
Definition confbridge.h:106
@ MENU_ACTION_PARTICIPANT_COUNT
Definition confbridge.h:114
@ MENU_ACTION_TOGGLE_MUTE
Definition confbridge.h:98
@ MENU_ACTION_NOOP
Definition confbridge.h:111
@ MENU_ACTION_RESET_TALKING
Definition confbridge.h:104
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
#define CONFIG_INFO_STANDARD(name, arr, alloc,...)
Declare an aco_info struct with default module and preload values.
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.
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.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
Core PBX routines and definitions.
static struct stasis_rest_handlers sounds
REST handler for /api-docs/sounds.json.
static corosync_cfg_handle_t cfg_handle
struct ao2_container * container
Definition res_fax.c:603
static struct @523 args
#define NULL
Definition resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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:2233
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:2250
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:225
const ast_string_field invalidpin
Definition confbridge.h:225
const ast_string_field placeintoconf
Definition confbridge.h:225
const ast_string_field onlyone
Definition confbridge.h:225
const ast_string_field otherinparty
Definition confbridge.h:225
const ast_string_field unlockednow
Definition confbridge.h:225
const ast_string_field binauralon
Definition confbridge.h:225
const ast_string_field getpin
Definition confbridge.h:225
const ast_string_field errormenu
Definition confbridge.h:225
const ast_string_field participantsunmuted
Definition confbridge.h:225
const ast_string_field participantsmuted
Definition confbridge.h:225
const ast_string_field leave
Definition confbridge.h:225
const ast_string_field locked
Definition confbridge.h:225
const ast_string_field join
Definition confbridge.h:225
const ast_string_field kicked
Definition confbridge.h:225
const ast_string_field hasleft
Definition confbridge.h:225
const ast_string_field unmuted
Definition confbridge.h:225
const ast_string_field leaderhasleft
Definition confbridge.h:225
const ast_string_field lockednow
Definition confbridge.h:225
const ast_string_field hasjoin
Definition confbridge.h:225
const ast_string_field binauraloff
Definition confbridge.h:225
const ast_string_field onlyperson
Definition confbridge.h:225
const ast_string_field thereare
Definition confbridge.h:225
const ast_string_field muted
Definition confbridge.h:225
const ast_string_field begin
Definition confbridge.h:225
char rec_options[128]
Definition confbridge.h:232
unsigned int remb_send_interval
Definition confbridge.h:242
unsigned int maximum_sample_rate
Definition confbridge.h:237
char regcontext[AST_MAX_CONTEXT]
Definition confbridge.h:240
char rec_command[128]
Definition confbridge.h:233
unsigned int mix_interval
Definition confbridge.h:238
unsigned int video_update_discard
Definition confbridge.h:241
unsigned int internal_sample_rate
Definition confbridge.h:236
unsigned int flags
Definition confbridge.h:234
char rec_file[PATH_MAX]
Definition confbridge.h:231
char language[MAX_LANGUAGE]
Definition confbridge.h:230
unsigned int max_members
Definition confbridge.h:235
char name[MAX_PROFILE_NAME]
Definition confbridge.h:229
struct bridge_profile_sounds * sounds
Definition confbridge.h:239
enum conf_menu_action_id id
Definition confbridge.h:124
char exten[AST_MAX_EXTENSION]
Definition confbridge.h:129
struct conf_menu_action::@88::@90 dialplan_args
char playback_file[PATH_MAX]
Definition confbridge.h:126
char context[AST_MAX_CONTEXT]
Definition confbridge.h:128
union conf_menu_action::@88 data
Definition confbridge.h:139
char dtmf[MAXIMUM_DTMF_FEATURE_STRING]
Definition confbridge.h:141
struct conf_menu_entry::@92 entry
struct conf_menu_entry::@91 actions
char name[MAX_PROFILE_NAME]
Definition confbridge.h:151
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:274
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:165
char announcement[PATH_MAX]
Definition confbridge.h:159
char moh_class[128]
Definition confbridge.h:158
unsigned int talking_threshold
Definition confbridge.h:163
unsigned int flags
Definition confbridge.h:160
char pin[MAX_PIN]
Definition confbridge.h:157
unsigned int announce_user_count_all_after
Definition confbridge.h:161
char name[MAX_PROFILE_NAME]
Definition confbridge.h:156
structure to hold users read from phoneprov_users.conf
int value
Definition syslog.c:37
static struct test_val a
int error(const char *format,...)
#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:981
#define ast_assert(a)
Definition utils.h:779
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ARRAY_LEN(a)
Definition utils.h:706
#define ast_set_flags_to(p, flag, value)
Definition utils.h:105