summaryrefslogtreecommitdiff
path: root/apps/confbridge/include/confbridge.h
blob: c2f8f9a585f728ecd067be5573323e9cf7c5f145 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 2011, Digium, Inc.
 *
 * David Vossel <dvossel@digium.com>
 * Joshua Colp <jcolp@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */


#ifndef _CONFBRIDGE_H
#define _CONFBRIDGE_H

#include "asterisk.h"
#include "asterisk/app.h"
#include "asterisk/logger.h"
#include "asterisk/linkedlists.h"
#include "asterisk/channel.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_features.h"
#include "conf_state.h"

/*! Maximum length of a conference bridge name */
#define MAX_CONF_NAME AST_MAX_EXTENSION
/*! Maximum length of a conference pin */
#define MAX_PIN     80
/*! Maximum length of bridge/user/menu profile names */
#define MAX_PROFILE_NAME 128

#define DEFAULT_USER_PROFILE "default_user"
#define DEFAULT_BRIDGE_PROFILE "default_bridge"
#define DEFAULT_MENU_PROFILE "default_menu"

/*! Default minimum average magnitude threshold to determine talking by the DSP. */
#define DEFAULT_TALKING_THRESHOLD 160

/*! Default time in ms of silence necessary to declare talking stopped by the bridge. */
#define DEFAULT_SILENCE_THRESHOLD 2500

enum user_profile_flags {
	USER_OPT_ADMIN =        (1 << 0), /*!< Set if the caller is an administrator */
	USER_OPT_NOONLYPERSON = (1 << 1), /*!< Set if the "you are currently the only person in this conference" sound file should not be played */
	USER_OPT_MARKEDUSER =   (1 << 2), /*!< Set if the caller is a marked user */
	USER_OPT_STARTMUTED =   (1 << 3), /*!< Set if the caller should be initially set muted */
	USER_OPT_MUSICONHOLD =  (1 << 4), /*!< Set if music on hold should be played if nobody else is in the conference bridge */
	USER_OPT_QUIET =        (1 << 5), /*!< Set if no audio prompts should be played */
	USER_OPT_ANNOUNCEUSERCOUNT = (1 << 6), /*!< Set if the number of users should be announced to the caller */
	USER_OPT_WAITMARKED =   (1 << 7), /*!< Set if the user must wait for a marked user before starting */
	USER_OPT_ENDMARKED =    (1 << 8), /*!< Set if the user should be kicked after the last Marked user exits */
	USER_OPT_DENOISE =      (1 << 9), /*!< Sets if denoise filter should be used on audio before mixing. */
	USER_OPT_ANNOUNCE_JOIN_LEAVE = (1 << 10), /*!< Sets if the user's name should be recorded and announced on join and leave. */
	USER_OPT_TALKER_DETECT = (1 << 11), /*!< Sets if start and stop talking events should generated for this user over AMI. */
	USER_OPT_DROP_SILENCE =  (1 << 12), /*!< Sets if silence should be dropped from the mix or not. */
	USER_OPT_DTMF_PASS    =  (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
	USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
	USER_OPT_JITTERBUFFER =  (1 << 15), /*!< Places a jitterbuffer on the user. */
	USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW = (1 << 16), /*!< modifies ANNOUNCE_JOIN_LEAVE - user reviews the recording before continuing */
};

enum bridge_profile_flags {
	BRIDGE_OPT_RECORD_CONFERENCE = (1 << 0), /*!< Set if the conference should be recorded */
	BRIDGE_OPT_VIDEO_SRC_LAST_MARKED = (1 << 1), /*!< Set if conference should feed video of last marked user to all participants. */
	BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED = (1 << 2), /*!< Set if conference should feed video of first marked user to all participants. */
	BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER = (1 << 3), /*!< Set if conference set the video feed to follow the loudest talker.  */
	BRIDGE_OPT_RECORD_FILE_APPEND = (1 << 4), /*!< Set if the record file should be appended to between start/stops.  */
	BRIDGE_OPT_RECORD_FILE_TIMESTAMP = (1 << 5), /*!< Set if the record file should have a timestamp appended */
	BRIDGE_OPT_BINAURAL_ACTIVE = (1 << 6), /*!< Set if binaural convolution is activated */
	BRIDGE_OPT_VIDEO_SRC_SFU = (1 << 7), /*!< Selective forwarding unit */
};

enum conf_menu_action_id {
	MENU_ACTION_TOGGLE_MUTE = 1,
	MENU_ACTION_PLAYBACK,
	MENU_ACTION_PLAYBACK_AND_CONTINUE,
	MENU_ACTION_INCREASE_LISTENING,
	MENU_ACTION_DECREASE_LISTENING,
	MENU_ACTION_RESET_LISTENING,
	MENU_ACTION_RESET_TALKING,
	MENU_ACTION_INCREASE_TALKING,
	MENU_ACTION_DECREASE_TALKING,
	MENU_ACTION_DIALPLAN_EXEC,
	MENU_ACTION_ADMIN_TOGGLE_LOCK,
	MENU_ACTION_ADMIN_KICK_LAST,
	MENU_ACTION_LEAVE,
	MENU_ACTION_NOOP,
	MENU_ACTION_SET_SINGLE_VIDEO_SRC,
	MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC,
	MENU_ACTION_PARTICIPANT_COUNT,
	MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS,
	MENU_ACTION_TOGGLE_BINAURAL,
};

/*! The conference menu action contains both
 *  the action id that represents the action that
 *  must take place, along with any data associated
 *  with that action. */
struct conf_menu_action {
	enum conf_menu_action_id id;
	union {
		char playback_file[PATH_MAX];
		struct {
			char context[AST_MAX_CONTEXT];
			char exten[AST_MAX_EXTENSION];
			int priority;
		} dialplan_args;
	} data;
	AST_LIST_ENTRY(conf_menu_action) action;
};

/*! Conference menu entries contain the DTMF sequence
 *  and the list of actions that are associated with that
 *  sequence. */
struct conf_menu_entry {
	/*! the DTMF sequence that triggers the actions */
	char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
	/*! The actions associated with this menu entry. */
	AST_LIST_HEAD_NOLOCK(, conf_menu_action) actions;
	AST_LIST_ENTRY(conf_menu_entry) entry;
};

/*! Conference menu structure.  Contains a list
 * of DTMF sequences coupled with the actions those
 * sequences invoke.*/
struct conf_menu {
	char name[MAX_PROFILE_NAME];
	AST_LIST_HEAD_NOLOCK(, conf_menu_entry) entries;
};

struct user_profile {
	char name[MAX_PROFILE_NAME];
	char pin[MAX_PIN];
	char moh_class[128];
	char announcement[PATH_MAX];
	unsigned int flags;
	unsigned int announce_user_count_all_after;
	/*! Minimum average magnitude threshold to determine talking by the DSP. */
	unsigned int talking_threshold;
	/*! Time in ms of silence necessary to declare talking stopped by the bridge. */
	unsigned int silence_threshold;
	/*! The time in ms the user may stay in the confbridge */
	unsigned int timeout;
};

enum conf_sounds {
	CONF_SOUND_HAS_JOINED,
	CONF_SOUND_HAS_LEFT,
	CONF_SOUND_KICKED,
	CONF_SOUND_MUTED,
	CONF_SOUND_UNMUTED,
	CONF_SOUND_ONLY_ONE,
	CONF_SOUND_THERE_ARE,
	CONF_SOUND_OTHER_IN_PARTY,
	CONF_SOUND_PLACE_IN_CONF,
	CONF_SOUND_WAIT_FOR_LEADER,
	CONF_SOUND_LEADER_HAS_LEFT,
	CONF_SOUND_GET_PIN,
	CONF_SOUND_INVALID_PIN,
	CONF_SOUND_ONLY_PERSON,
	CONF_SOUND_LOCKED,
	CONF_SOUND_LOCKED_NOW,
	CONF_SOUND_UNLOCKED_NOW,
	CONF_SOUND_ERROR_MENU,
	CONF_SOUND_JOIN,
	CONF_SOUND_LEAVE,
	CONF_SOUND_PARTICIPANTS_MUTED,
	CONF_SOUND_PARTICIPANTS_UNMUTED,
	CONF_SOUND_BEGIN,
	CONF_SOUND_BINAURAL_ON,
	CONF_SOUND_BINAURAL_OFF,
};

struct bridge_profile_sounds {
	AST_DECLARE_STRING_FIELDS(
		AST_STRING_FIELD(hasjoin);
		AST_STRING_FIELD(hasleft);
		AST_STRING_FIELD(kicked);
		AST_STRING_FIELD(muted);
		AST_STRING_FIELD(unmuted);
		AST_STRING_FIELD(onlyone);
		AST_STRING_FIELD(thereare);
		AST_STRING_FIELD(otherinparty);
		AST_STRING_FIELD(placeintoconf);
		AST_STRING_FIELD(waitforleader);
		AST_STRING_FIELD(leaderhasleft);
		AST_STRING_FIELD(getpin);
		AST_STRING_FIELD(invalidpin);
		AST_STRING_FIELD(onlyperson);
		AST_STRING_FIELD(locked);
		AST_STRING_FIELD(lockednow);
		AST_STRING_FIELD(unlockednow);
		AST_STRING_FIELD(errormenu);
		AST_STRING_FIELD(leave);
		AST_STRING_FIELD(join);
		AST_STRING_FIELD(participantsmuted);
		AST_STRING_FIELD(participantsunmuted);
		AST_STRING_FIELD(begin);
		AST_STRING_FIELD(binauralon);
		AST_STRING_FIELD(binauraloff);
	);
};

struct bridge_profile {
	char name[MAX_PROFILE_NAME];
	char language[MAX_LANGUAGE];		  /*!< Language used for playback_chan */
	char rec_file[PATH_MAX];
	char rec_options[128];
	char rec_command[128];
	unsigned int flags;
	unsigned int max_members;          /*!< The maximum number of participants allowed in the conference */
	unsigned int internal_sample_rate; /*!< The internal sample rate of the bridge. 0 when set to auto adjust mode. */
	unsigned int mix_interval;  /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */
	struct bridge_profile_sounds *sounds;
	char regcontext[AST_MAX_CONTEXT];
	unsigned int video_update_discard; /*!< Amount of time after sending a video update request that subsequent requests should be discarded */
	unsigned int remb_send_interval; /*!< Interval at which a combined REMB frame is sent to video sources */
};

/*! \brief The structure that represents a conference bridge */
struct confbridge_conference {
	char name[MAX_CONF_NAME];                                         /*!< Name of the conference bridge */
	struct confbridge_state *state;                                   /*!< Conference state information */
	struct ast_bridge *bridge;                                        /*!< Bridge structure doing the mixing */
	struct bridge_profile b_profile;                                  /*!< The Bridge Configuration Profile */
	unsigned int activeusers;                                         /*!< Number of active users present */
	unsigned int markedusers;                                         /*!< Number of marked users present */
	unsigned int waitingusers;                                        /*!< Number of waiting users present */
	unsigned int locked:1;                                            /*!< Is this conference bridge locked? */
	unsigned int muted:1;                                             /*!< Is this conference bridge muted? */
	struct ast_channel *playback_chan;                                /*!< Channel used for playback into the conference bridge */
	struct ast_channel *record_chan;                                  /*!< Channel used for recording the conference */
	struct ast_str *record_filename;                                  /*!< Recording filename. */
	struct ast_str *orig_rec_file;                                    /*!< Previous b_profile.rec_file. */
	AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list;              /*!< List of users participating in the conference bridge */
	AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list;             /*!< List of users waiting to join the conference bridge */
	struct ast_taskprocessor *playback_queue;                         /*!< Queue for playing back bridge announcements and managing the announcer channel */
};

extern struct ao2_container *conference_bridges;

struct post_join_action {
	int (*func)(struct confbridge_user *user);
	AST_LIST_ENTRY(post_join_action) list;
};

/*! \brief The structure that represents a conference bridge user */
struct confbridge_user {
	struct confbridge_conference *conference;    /*!< Conference bridge they are participating in */
	struct bridge_profile b_profile;             /*!< The Bridge Configuration Profile */
	struct user_profile u_profile;               /*!< The User Configuration Profile */
	char menu_name[MAX_PROFILE_NAME];            /*!< The name of the DTMF menu assigned to this user */
	char name_rec_location[PATH_MAX];            /*!< Location of the User's name recorded file if it exists */
	struct ast_channel *chan;                    /*!< Asterisk channel participating */
	struct ast_bridge_features features;         /*!< Bridge features structure */
	struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */
	unsigned int suspended_moh;                  /*!< Count of active suspended MOH actions. */
	unsigned int muted:1;                        /*!< Has the user requested to be muted? */
	unsigned int kicked:1;                       /*!< User has been kicked from the conference */
	unsigned int playing_moh:1;                  /*!< MOH is currently being played to the user */
	AST_LIST_HEAD_NOLOCK(, post_join_action) post_join_list; /*!< List of sounds to play after joining */;
	AST_LIST_ENTRY(confbridge_user) list;        /*!< Linked list information */
};

/*! \brief load confbridge.conf file */
int conf_load_config(void);

/*! \brief reload confbridge.conf file */
int conf_reload_config(void);

/*! \brief destroy the information loaded from the confbridge.conf file*/
void conf_destroy_config(void);

/*!
 * \brief find a user profile given a user profile's name and store
 * that profile in result structure.
 *
 * \param chan channel the user profile is requested for
 * \param user_profile_name name of the profile requested (optional)
 * \param result data contained by the user profile will be copied to this struct pointer
 *
 * \details If user_profile_name is not provided, this function will
 * check for the presence of a user profile set by the CONFBRIDGE
 * function on a channel datastore. If that doesn't exist, the
 * default_user profile is used.
 *
 * \retval user profile on success
 * \retval NULL on failure
 */
const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result);

/*!
 * \brief Find a bridge profile given a bridge profile's name and store
 * that profile in result structure.
 *
 * \param chan channel the bridge profile is requested for
 * \param bridge_profile_name name of the profile requested (optional)
 * \param result data contained by the bridge profile will be copied to this struct pointer
 *
 * \details If bridge_profile_name is not provided, this function will
 * check for the presence of a bridge profile set by the CONFBRIDGE
 * function on a channel datastore. If that doesn't exist, the
 * default_bridge profile is used.
 *
 * \retval bridge profile on success
 * \retval NULL on failure
 */
const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result);

/*!
 * \brief find a menu profile given a menu profile's name and apply
 * the menu in DTMF hooks.
 *
 * \param chan channel the menu profile is requested for
 * \param user user profile the menu is being applied to
 * \param menu_profile_name name of the profile requested (optional)
 *
 * \details If menu_profile_name is not provided, this function will
 * check for the presence of a menu profile set by the CONFBRIDGE
 * function on a channel datastore. If that doesn't exist, the
 * default_menu profile is used.
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name);

/*!
 * \brief Destroy a bridge profile found by 'conf_find_bridge_profile'
 */
void conf_bridge_profile_destroy(struct bridge_profile *b_profile);

/*!
 * \brief copies a bridge profile
 * \note conf_bridge_profile_destroy must be called on the dst structure
 */
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src);

/*!
 * \brief Finds a menu_entry in a menu structure matched by DTMF sequence.
 *
 * \note the menu entry found must be destroyed using conf_menu_entry_destroy()
 *
 * \retval 1 success, entry is found and stored in result
 * \retval 0 failure, no entry found for given DTMF sequence
 */
int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result);

/*!
 * \brief Destroys and frees all the actions stored in a menu_entry structure
 */
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry);

/*!
 * \brief Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get
 * called to perform the menu action.
 *
 * \param bridge_channel Bridged channel this is involving
 * \param user the conference user to perform the action on.
 * \param menu_entry the menu entry that invoked this callback to occur.
 * \param menu an AO2 referenced pointer to the entire menu structure the menu_entry
 *        derived from.
 *
 * \note The menu_entry is a deep copy of the entry found in the menu structure.  This allows
 * for the menu_entry to be accessed without requiring the menu lock.  If the menu must
 * be accessed, the menu lock must be held.  Reference counting of the menu structure is
 * handled outside of the scope of this function.
 *
 * \retval 0 success
 * \retval -1 failure
 */
int conf_handle_dtmf(
	struct ast_bridge_channel *bridge_channel,
	struct confbridge_user *user,
	struct conf_menu_entry *menu_entry,
	struct conf_menu *menu);


/*! \brief Looks to see if sound file is stored in bridge profile sounds, if not
 *  default sound is provided.*/
const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds);

int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value);

/*!
 * \brief Play sound file into conference bridge
 *
 * \param conference The conference bridge to play sound file into
 * \param filename Sound file to play
 *
 * \retval 0 success
 * \retval -1 failure
 */
int play_sound_file(struct confbridge_conference *conference, const char *filename);

/*!
 * \brief Play sound file into conference bridge asynchronously
 *
 * If the initiator parameter is non-NULL, then the playback will wait for
 * that initiator channel to get back in the bridge before playing the sound
 * file. This way, the initiator has no danger of hearing a "clipped" file.
 *
 * \param conference The conference bridge to play sound file into
 * \param filename Sound file to play
 * \param initiator Channel that initiated playback.
 *
 * \retval 0 success
 * \retval -1 failure
 */
int async_play_sound_file(struct confbridge_conference *conference, const char *filename,
	struct ast_channel *initiator);

/*!
 * \brief Indicate the initiator of an async sound file is ready for it to play.
 *
 * When playing an async sound file, the initiator is typically either out of the bridge
 * or not in a position to hear the queued announcement. This function lets the announcement
 * thread know that the initiator is now ready for the sound to play.
 *
 * If an async announcement was queued and no initiator channel was provided, then this is
 * a no-op
 *
 * \param chan The channel that initiated the async announcement
 */
void async_play_sound_ready(struct ast_channel *chan);

/*! \brief Callback to be called when the conference has become empty
 * \param conference The conference bridge
 */
void conf_ended(struct confbridge_conference *conference);

/*!
 * \brief Update the actual mute status of the user and set it on the bridge.
 *
 * \param user User to update the mute status.
 *
 * \return Nothing
 */
void conf_update_user_mute(struct confbridge_user *user);

/*!
 * \brief Stop MOH for the conference user.
 *
 * \param user Conference user to stop MOH on.
 *
 * \return Nothing
 */
void conf_moh_stop(struct confbridge_user *user);

/*!
 * \brief Start MOH for the conference user.
 *
 * \param user Conference user to start MOH on.
 *
 * \return Nothing
 */
void conf_moh_start(struct confbridge_user *user);

/*! \brief Attempt to mute/play MOH to the only user in the conference if they require it
 * \param conference A conference bridge containing a single user
 */
void conf_mute_only_active(struct confbridge_conference *conference);

/*! \brief Callback to execute any time we transition from zero to one active users
 * \param conference The conference bridge with a single active user joined
 * \retval 0 success
 * \retval -1 failure
 */
void conf_handle_first_join(struct confbridge_conference *conference);

/*! \brief Handle actions every time a waitmarked user joins w/o a marked user present
 * \param user The waitmarked user
 * \retval 0 success
 * \retval -1 failure
 */
int conf_handle_inactive_waitmarked(struct confbridge_user *user);

/*! \brief Handle actions whenever an unmarked user joins an inactive conference
 * \note These actions seem like they could apply just as well to a marked user
 * and possibly be made to happen any time transitioning to a single state.
 *
 * \param user The unmarked user
 */
int conf_handle_only_unmarked(struct confbridge_user *user);

/*! \brief Handle when a conference moves to having more than one active participant
 * \param conference The conference bridge with more than one active participant
 */
void conf_handle_second_active(struct confbridge_conference *conference);

/*! \brief Add a conference bridge user as an unmarked active user of the conference
 * \param conference The conference bridge to add the user to
 * \param user The conference bridge user to add to the conference
 */
void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Add a conference bridge user as a marked active user of the conference
 * \param conference The conference bridge to add the user to
 * \param user The conference bridge user to add to the conference
 */
void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Add a conference bridge user as an waiting user of the conference
 * \param conference The conference bridge to add the user to
 * \param user The conference bridge user to add to the conference
 */
void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Remove a conference bridge user from the unmarked active conference users in the conference
 * \param conference The conference bridge to remove the user from
 * \param user The conference bridge user to remove from the conference
 */
void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Remove a conference bridge user from the marked active conference users in the conference
 * \param conference The conference bridge to remove the user from
 * \param user The conference bridge user to remove from the conference
 */
void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Remove a conference bridge user from the waiting conference users in the conference
 * \param conference The conference bridge to remove the user from
 * \param user The conference bridge user to remove from the conference
 */
void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user);

/*! \brief Queue a function to run with the given conference bridge user as an argument once the state transition is complete
 * \param user The conference bridge user to pass to the function
 * \param func The function to queue
 * \retval 0 success
 * \retval non-zero failure
 */
int conf_add_post_join_action(struct confbridge_user *user, int (*func)(struct confbridge_user *user));

/*!
 * \since 12.0
 * \brief get the confbridge start stasis message type
 *
 * \retval stasis message type for confbridge start messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_start_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge end stasis message type
 *
 * \retval stasis message type for confbridge end messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_end_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge join stasis message type
 *
 * \retval stasis message type for confbridge join messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_join_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge leave stasis message type
 *
 * \retval stasis message type for confbridge leave messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_leave_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge start_record stasis message type
 *
 * \retval stasis message type for confbridge start_record messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_start_record_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge stop_record stasis message type
 *
 * \retval stasis message type for confbridge stop_record messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_stop_record_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge mute stasis message type
 *
 * \retval stasis message type for confbridge mute messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_mute_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge unmute stasis message type
 *
 * \retval stasis message type for confbridge unmute messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_unmute_type(void);

/*!
 * \since 12.0
 * \brief get the confbridge talking stasis message type
 *
 * \retval stasis message type for confbridge talking messages if it's available
 * \retval NULL if it isn't
 */
struct stasis_message_type *confbridge_talking_type(void);

/*!
 * \since 12.0
 * \brief register stasis message routers to handle manager events for confbridge messages
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int manager_confbridge_init(void);

/*!
 * \since 12.0
 * \brief unregister stasis message routers to handle manager events for confbridge messages
 */
void manager_confbridge_shutdown(void);

/*!
 * \brief Get ConfBridge record channel technology struct.
 * \since 12.0.0
 *
 * \return ConfBridge record channel technology.
 */
struct ast_channel_tech *conf_record_get_tech(void);

/*!
 * \brief Get ConfBridge announce channel technology struct.
 * \since 12.0.0
 *
 * \return ConfBridge announce channel technology.
 */
struct ast_channel_tech *conf_announce_get_tech(void);

/*!
 * \brief Push the announcer channel into the conference.
 * \since 12.0.0
 *
 * \param ast Either channel in the announcer channel pair.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
int conf_announce_channel_push(struct ast_channel *ast);
#endif