1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Neal Horman <neal at wanlink dot com>
28  * Bret McDanel <trixter at 0xdecafbad dot com>
29  * Dale Thatcher <freeswitch at dalethatcher dot com>
30  * Chris Danielson <chris at maxpowersoft dot com>
31  * Rupa Schomaker <rupa@rupa.com>
32  * David Weekly <david@weekly.org>
33  * Joao Mesquita <jmesquita@gmail.com>
34  * Raymond Chandler <intralanman@freeswitch.org>
35  * Seven Du <dujinfang@gmail.com>
36  * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
37  * William King <william.king@quentustech.com>
38  *
39  * mod_conference.c -- Software Conference Bridge
40  *
41  */
42 #include <mod_conference.h>
43 
44 struct _mapping control_mappings[] = {
45 	{"mute", conference_loop_mute_toggle},
46 	{"mute on", conference_loop_mute_on},
47 	{"mute off", conference_loop_mute_off},
48 	{"moh toggle", conference_loop_moh_toggle},
49 	{"border", conference_loop_border},
50 	{"vmute", conference_loop_vmute_toggle},
51 	{"vmute on", conference_loop_vmute_on},
52 	{"vmute off", conference_loop_vmute_off},
53 	{"vmute snap", conference_loop_conference_video_vmute_snap},
54 	{"vmute snapoff", conference_loop_conference_video_vmute_snapoff},
55 	{"deaf mute", conference_loop_deafmute_toggle},
56 	{"energy up", conference_loop_energy_up},
57 	{"energy equ", conference_loop_energy_equ_conf},
58 	{"energy dn", conference_loop_energy_dn},
59 	{"vol talk up", conference_loop_volume_talk_up},
60 	{"vol talk zero", conference_loop_volume_talk_zero},
61 	{"vol talk dn", conference_loop_volume_talk_dn},
62 	{"vol listen up", conference_loop_volume_listen_up},
63 	{"vol listen zero", conference_loop_volume_listen_zero},
64 	{"vol listen dn", conference_loop_volume_listen_dn},
65 	{"hangup", conference_loop_hangup},
66 	{"event", conference_loop_event},
67 	{"lock", conference_loop_lock_toggle},
68 	{"transfer", conference_loop_transfer},
69 	{"execute_application", conference_loop_exec_app},
70 	{"floor", conference_loop_floor_toggle},
71 	{"vid-floor", conference_loop_vid_floor_toggle},
72 	{"vid-floor-force", conference_loop_vid_floor_force},
73 	{"deaf", conference_loop_deaf_toggle},
74 	{"deaf on", conference_loop_deaf_on},
75 	{"deaf off", conference_loop_deaf_off}
76 };
77 
conference_loop_mapping_len()78 int conference_loop_mapping_len()
79 {
80 	return (sizeof(control_mappings)/sizeof(control_mappings[0]));
81 }
82 
conference_loop_dmachine_dispatcher(switch_ivr_dmachine_match_t * match)83 switch_status_t conference_loop_dmachine_dispatcher(switch_ivr_dmachine_match_t *match)
84 {
85 	key_binding_t *binding = match->user_data;
86 	switch_channel_t *channel;
87 
88 	if (!binding) return SWITCH_STATUS_FALSE;
89 
90 	channel = switch_core_session_get_channel(binding->member->session);
91 	switch_channel_set_variable(channel, "conference_last_matching_digits", match->match_digits);
92 
93 	if (binding->action.data) {
94 		binding->action.expanded_data = switch_channel_expand_variables(channel, binding->action.data);
95 	}
96 
97 	binding->handler(binding->member, &binding->action);
98 
99 	if (binding->action.expanded_data != binding->action.data) {
100 		free(binding->action.expanded_data);
101 		binding->action.expanded_data = NULL;
102 	}
103 
104 	conference_utils_member_set_flag_locked(binding->member, MFLAG_FLUSH_BUFFER);
105 
106 	return SWITCH_STATUS_SUCCESS;
107 }
108 
conference_loop_floor_toggle(conference_member_t * member,caller_control_action_t * action)109 void conference_loop_floor_toggle(conference_member_t *member, caller_control_action_t *action)
110 {
111 	if (member == NULL) return;
112 
113 	conference_api_sub_floor(member, NULL, NULL);
114 }
115 
conference_loop_vid_floor_toggle(conference_member_t * member,caller_control_action_t * action)116 void conference_loop_vid_floor_toggle(conference_member_t *member, caller_control_action_t *action)
117 {
118 	if (member == NULL) return;
119 
120 	conference_api_sub_vid_floor(member, NULL, NULL);
121 }
122 
conference_loop_vid_floor_force(conference_member_t * member,caller_control_action_t * action)123 void conference_loop_vid_floor_force(conference_member_t *member, caller_control_action_t *action)
124 {
125 	if (member == NULL) return;
126 
127 	conference_api_sub_vid_floor(member, NULL, "force");
128 }
129 
conference_loop_mute_toggle(conference_member_t * member,caller_control_action_t * action)130 void conference_loop_mute_toggle(conference_member_t *member, caller_control_action_t *action)
131 {
132 	if (member == NULL)
133 		return;
134 
135 	if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return;
136 
137 	if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
138 		conference_api_sub_mute(member, NULL, NULL);
139 	} else {
140 		conference_api_sub_unmute(member, NULL, NULL);
141 		if (!conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
142 			conference_api_sub_undeaf(member, NULL, NULL);
143 		}
144 	}
145 }
146 
conference_loop_mute_on(conference_member_t * member,caller_control_action_t * action)147 void conference_loop_mute_on(conference_member_t *member, caller_control_action_t *action)
148 {
149 	if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return;
150 
151 	if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
152 		conference_api_sub_mute(member, NULL, NULL);
153 	}
154 }
155 
conference_loop_mute_off(conference_member_t * member,caller_control_action_t * action)156 void conference_loop_mute_off(conference_member_t *member, caller_control_action_t *action)
157 {
158 	if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return;
159 
160 	if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
161 		conference_api_sub_unmute(member, NULL, NULL);
162 		if (!conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
163 			conference_api_sub_undeaf(member, NULL, NULL);
164 		}
165 	}
166 }
167 
conference_loop_conference_video_vmute_snap(conference_member_t * member,caller_control_action_t * action)168 void conference_loop_conference_video_vmute_snap(conference_member_t *member, caller_control_action_t *action)
169 {
170 	conference_video_vmute_snap(member, SWITCH_FALSE);
171 }
172 
conference_loop_conference_video_vmute_snapoff(conference_member_t * member,caller_control_action_t * action)173 void conference_loop_conference_video_vmute_snapoff(conference_member_t *member, caller_control_action_t *action)
174 {
175 	conference_video_vmute_snap(member, SWITCH_TRUE);
176 }
177 
conference_loop_moh_toggle(conference_member_t * member,caller_control_action_t * action)178 void conference_loop_moh_toggle(conference_member_t *member, caller_control_action_t *action)
179 {
180 	conference_api_set_moh(member->conference, "toggle");
181 }
182 
conference_loop_border(conference_member_t * member,caller_control_action_t * action)183 void conference_loop_border(conference_member_t *member, caller_control_action_t *action)
184 {
185 	conference_api_sub_vid_border(member, NULL, action->expanded_data);
186 }
187 
conference_loop_vmute_toggle(conference_member_t * member,caller_control_action_t * action)188 void conference_loop_vmute_toggle(conference_member_t *member, caller_control_action_t *action)
189 {
190 	if (member == NULL)
191 		return;
192 
193 	if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) {
194 		conference_api_sub_vmute(member, NULL, NULL);
195 	} else {
196 		conference_api_sub_unvmute(member, NULL, NULL);
197 	}
198 }
199 
conference_loop_vmute_on(conference_member_t * member,caller_control_action_t * action)200 void conference_loop_vmute_on(conference_member_t *member, caller_control_action_t *action)
201 {
202 	if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) {
203 		conference_api_sub_vmute(member, NULL, NULL);
204 	}
205 }
206 
conference_loop_vmute_off(conference_member_t * member,caller_control_action_t * action)207 void conference_loop_vmute_off(conference_member_t *member, caller_control_action_t *action)
208 {
209 	if (!conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) {
210 		conference_api_sub_unvmute(member, NULL, NULL);
211 	}
212 }
213 
conference_loop_lock_toggle(conference_member_t * member,caller_control_action_t * action)214 void conference_loop_lock_toggle(conference_member_t *member, caller_control_action_t *action)
215 {
216 	switch_event_t *event;
217 
218 	if (member == NULL)
219 		return;
220 
221 	if (conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD) && !conference_utils_member_test_flag(member, MFLAG_MOD) )
222 		return;
223 
224 	if (!conference_utils_test_flag(member->conference, CFLAG_LOCKED)) {
225 		if (member->conference->is_locked_sound) {
226 			conference_file_play(member->conference, member->conference->is_locked_sound, CONF_DEFAULT_LEADIN, NULL, 0);
227 		}
228 
229 		conference_utils_set_flag_locked(member->conference, CFLAG_LOCKED);
230 		if (test_eflag(member->conference, EFLAG_LOCK) &&
231 			switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
232 			conference_event_add_data(member->conference, event);
233 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "lock");
234 			switch_event_fire(&event);
235 		}
236 	} else {
237 		if (member->conference->is_unlocked_sound) {
238 			conference_file_play(member->conference, member->conference->is_unlocked_sound, CONF_DEFAULT_LEADIN, NULL, 0);
239 		}
240 
241 		conference_utils_clear_flag_locked(member->conference, CFLAG_LOCKED);
242 		if (test_eflag(member->conference, EFLAG_UNLOCK) &&
243 			switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
244 			conference_event_add_data(member->conference, event);
245 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "unlock");
246 			switch_event_fire(&event);
247 		}
248 	}
249 
250 }
251 
conference_loop_deaf_toggle(conference_member_t * member,caller_control_action_t * action)252 void conference_loop_deaf_toggle(conference_member_t *member, caller_control_action_t *action)
253 {
254 	if (member == NULL)
255 		return;
256 
257 	if (conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
258 		conference_api_sub_deaf(member, NULL, NULL);
259 	} else {
260 		conference_api_sub_undeaf(member, NULL, NULL);
261 	}
262 }
263 
conference_loop_deaf_on(conference_member_t * member,caller_control_action_t * action)264 void conference_loop_deaf_on(conference_member_t *member, caller_control_action_t *action)
265 {
266 	if (member == NULL)
267 		return;
268 
269 	if (conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
270 		conference_api_sub_deaf(member, NULL, NULL);
271 	}
272 }
273 
conference_loop_deaf_off(conference_member_t * member,caller_control_action_t * action)274 void conference_loop_deaf_off(conference_member_t *member, caller_control_action_t *action)
275 {
276 	if (member == NULL)
277 		return;
278 
279 	if (!conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
280 		conference_api_sub_undeaf(member, NULL, NULL);
281 	}
282 }
283 
conference_loop_deafmute_toggle(conference_member_t * member,caller_control_action_t * action)284 void conference_loop_deafmute_toggle(conference_member_t *member, caller_control_action_t *action)
285 {
286 	if (member == NULL)
287 		return;
288 
289 	if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return;
290 
291 	if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
292 		conference_api_sub_mute(member, NULL, NULL);
293 		if (conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
294 			conference_api_sub_deaf(member, NULL, NULL);
295 		}
296 	} else {
297 		conference_api_sub_unmute(member, NULL, NULL);
298 		if (!conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
299 			conference_api_sub_undeaf(member, NULL, NULL);
300 		}
301 	}
302 }
303 
conference_loop_energy_up(conference_member_t * member,caller_control_action_t * action)304 void conference_loop_energy_up(conference_member_t *member, caller_control_action_t *action)
305 {
306 	char msg[512], str[30] = "";
307 	switch_event_t *event;
308 	char *p;
309 
310 	if (member == NULL)
311 		return;
312 
313 
314 	member->energy_level += 200;
315 	if (member->energy_level > 1800) {
316 		member->energy_level = 1800;
317 	}
318 
319 	if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
320 		member->auto_energy_level = 0;
321 	}
322 
323 	if (member->max_energy_level && member->energy_level > member->max_energy_level) {
324 		member->max_energy_level = 0;
325 	}
326 
327 
328 	if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
329 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
330 		conference_member_add_event_data(member, event);
331 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "energy-level");
332 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
333 		switch_event_fire(&event);
334 	}
335 
336 	//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
337 	//conference_member_say(member, msg, 0);
338 
339 	switch_snprintf(str, sizeof(str), "%d", abs(member->energy_level) / 200);
340 	for (p = str; p && *p; p++) {
341 		switch_snprintf(msg, sizeof(msg), "digits/%c.wav", *p);
342 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
343 	}
344 
345 
346 
347 
348 }
349 
conference_loop_energy_equ_conf(conference_member_t * member,caller_control_action_t * action)350 void conference_loop_energy_equ_conf(conference_member_t *member, caller_control_action_t *action)
351 {
352 	char msg[512], str[30] = "", *p;
353 	switch_event_t *event;
354 
355 	if (member == NULL)
356 		return;
357 
358 	member->energy_level = member->conference->energy_level;
359 
360 
361 	if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
362 		member->auto_energy_level = 0;
363 	}
364 
365 	if (member->max_energy_level && member->energy_level > member->max_energy_level) {
366 		member->max_energy_level = 0;
367 	}
368 
369 	if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
370 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
371 		conference_member_add_event_data(member, event);
372 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "energy-level");
373 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
374 		switch_event_fire(&event);
375 	}
376 
377 	//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
378 	//conference_member_say(member, msg, 0);
379 
380 	switch_snprintf(str, sizeof(str), "%d", abs(member->energy_level) / 200);
381 	for (p = str; p && *p; p++) {
382 		switch_snprintf(msg, sizeof(msg), "digits/%c.wav", *p);
383 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
384 	}
385 
386 }
387 
conference_loop_energy_dn(conference_member_t * member,caller_control_action_t * action)388 void conference_loop_energy_dn(conference_member_t *member, caller_control_action_t *action)
389 {
390 	char msg[512], str[30] = "", *p;
391 	switch_event_t *event;
392 
393 	if (member == NULL)
394 		return;
395 
396 	member->energy_level -= 200;
397 	if (member->energy_level < 0) {
398 		member->energy_level = 0;
399 	}
400 
401 	if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
402 		member->auto_energy_level = 0;
403 	}
404 
405 	if (member->max_energy_level && member->energy_level > member->max_energy_level) {
406 		member->max_energy_level = 0;
407 	}
408 
409 	if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
410 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
411 		conference_member_add_event_data(member, event);
412 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "energy-level");
413 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->energy_level);
414 		switch_event_fire(&event);
415 	}
416 
417 	//switch_snprintf(msg, sizeof(msg), "Energy level %d", member->energy_level);
418 	//conference_member_say(member, msg, 0);
419 
420 	switch_snprintf(str, sizeof(str), "%d", abs(member->energy_level) / 200);
421 	for (p = str; p && *p; p++) {
422 		switch_snprintf(msg, sizeof(msg), "digits/%c.wav", *p);
423 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
424 	}
425 
426 }
427 
conference_loop_volume_talk_up(conference_member_t * member,caller_control_action_t * action)428 void conference_loop_volume_talk_up(conference_member_t *member, caller_control_action_t *action)
429 {
430 	char msg[512];
431 	switch_event_t *event;
432 
433 	if (member == NULL)
434 		return;
435 
436 	member->volume_out_level++;
437 	switch_normalize_volume(member->volume_out_level);
438 
439 	if (test_eflag(member->conference, EFLAG_VOLUME_LEVEL) &&
440 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
441 		conference_member_add_event_data(member, event);
442 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-level");
443 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
444 		switch_event_fire(&event);
445 	}
446 
447 	//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
448 	//conference_member_say(member, msg, 0);
449 
450 	if (member->volume_out_level < 0) {
451 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_out_level);
452 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
453 	}
454 
455 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_out_level));
456 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
457 
458 }
459 
conference_loop_volume_talk_zero(conference_member_t * member,caller_control_action_t * action)460 void conference_loop_volume_talk_zero(conference_member_t *member, caller_control_action_t *action)
461 {
462 	char msg[512];
463 	switch_event_t *event;
464 
465 	if (member == NULL)
466 		return;
467 
468 	member->volume_out_level = 0;
469 
470 	if (test_eflag(member->conference, EFLAG_VOLUME_LEVEL) &&
471 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
472 		conference_member_add_event_data(member, event);
473 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-level");
474 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
475 		switch_event_fire(&event);
476 	}
477 
478 	//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
479 	//conference_member_say(member, msg, 0);
480 
481 
482 	if (member->volume_out_level < 0) {
483 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_out_level);
484 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
485 	}
486 
487 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_out_level));
488 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
489 }
490 
conference_loop_volume_talk_dn(conference_member_t * member,caller_control_action_t * action)491 void conference_loop_volume_talk_dn(conference_member_t *member, caller_control_action_t *action)
492 {
493 	char msg[512];
494 	switch_event_t *event;
495 
496 	if (member == NULL)
497 		return;
498 
499 	member->volume_out_level--;
500 	switch_normalize_volume(member->volume_out_level);
501 
502 	if (test_eflag(member->conference, EFLAG_VOLUME_LEVEL) &&
503 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
504 		conference_member_add_event_data(member, event);
505 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-level");
506 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_out_level);
507 		switch_event_fire(&event);
508 	}
509 
510 	//switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
511 	//conference_member_say(member, msg, 0);
512 
513 	if (member->volume_out_level < 0) {
514 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_out_level);
515 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
516 	}
517 
518 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_out_level));
519 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
520 }
521 
conference_loop_volume_listen_up(conference_member_t * member,caller_control_action_t * action)522 void conference_loop_volume_listen_up(conference_member_t *member, caller_control_action_t *action)
523 {
524 	char msg[512];
525 	switch_event_t *event;
526 
527 	if (member == NULL)
528 		return;
529 
530 	member->volume_in_level++;
531 	switch_normalize_volume(member->volume_in_level);
532 
533 	if (test_eflag(member->conference, EFLAG_GAIN_LEVEL) &&
534 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
535 		conference_member_add_event_data(member, event);
536 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "gain-level");
537 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
538 		switch_event_fire(&event);
539 	}
540 
541 	//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
542 	//conference_member_say(member, msg, 0);
543 
544 	if (member->volume_in_level < 0) {
545 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_in_level);
546 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
547 	}
548 
549 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_in_level));
550 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
551 
552 }
553 
conference_loop_volume_listen_zero(conference_member_t * member,caller_control_action_t * action)554 void conference_loop_volume_listen_zero(conference_member_t *member, caller_control_action_t *action)
555 {
556 	char msg[512];
557 	switch_event_t *event;
558 
559 	if (member == NULL)
560 		return;
561 
562 	member->volume_in_level = 0;
563 
564 	if (test_eflag(member->conference, EFLAG_GAIN_LEVEL) &&
565 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
566 		conference_member_add_event_data(member, event);
567 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "gain-level");
568 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
569 		switch_event_fire(&event);
570 	}
571 
572 	//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
573 	//conference_member_say(member, msg, 0);
574 
575 	if (member->volume_in_level < 0) {
576 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_in_level);
577 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
578 	}
579 
580 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_in_level));
581 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
582 
583 }
584 
conference_loop_volume_listen_dn(conference_member_t * member,caller_control_action_t * action)585 void conference_loop_volume_listen_dn(conference_member_t *member, caller_control_action_t *action)
586 {
587 	char msg[512];
588 	switch_event_t *event;
589 
590 	if (member == NULL)
591 		return;
592 
593 	member->volume_in_level--;
594 	switch_normalize_volume(member->volume_in_level);
595 
596 	if (test_eflag(member->conference, EFLAG_GAIN_LEVEL) &&
597 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
598 		conference_member_add_event_data(member, event);
599 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "gain-level");
600 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-Level", "%d", member->volume_in_level);
601 		switch_event_fire(&event);
602 	}
603 
604 	//switch_snprintf(msg, sizeof(msg), "Gain level %d", member->volume_in_level);
605 	//conference_member_say(member, msg, 0);
606 
607 	if (member->volume_in_level < 0) {
608 		switch_snprintf(msg, sizeof(msg), "currency/negative.wav", member->volume_in_level);
609 		conference_member_play_file(member, msg, 0, SWITCH_TRUE);
610 	}
611 
612 	switch_snprintf(msg, sizeof(msg), "digits/%d.wav", abs(member->volume_in_level));
613 	conference_member_play_file(member, msg, 0, SWITCH_TRUE);
614 }
615 
conference_loop_event(conference_member_t * member,caller_control_action_t * action)616 void conference_loop_event(conference_member_t *member, caller_control_action_t *action)
617 {
618 	switch_event_t *event;
619 	if (test_eflag(member->conference, EFLAG_DTMF) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
620 		conference_member_add_event_data(member, event);
621 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "dtmf");
622 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Key", action->binded_dtmf);
623 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Data", action->expanded_data);
624 		switch_event_fire(&event);
625 	}
626 }
627 
conference_loop_transfer(conference_member_t * member,caller_control_action_t * action)628 void conference_loop_transfer(conference_member_t *member, caller_control_action_t *action)
629 {
630 	char *exten = NULL;
631 	char *dialplan = "XML";
632 	char *context = "default";
633 
634 	char *argv[3] = { 0 };
635 	int argc;
636 	char *mydata = NULL;
637 	switch_event_t *event;
638 
639 	if (test_eflag(member->conference, EFLAG_DTMF) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
640 		conference_member_add_event_data(member, event);
641 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "transfer");
642 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Dialplan", action->expanded_data);
643 		switch_event_fire(&event);
644 	}
645 	conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);
646 
647 	if ((mydata = switch_core_session_strdup(member->session, action->expanded_data))) {
648 		if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
649 			if (argc > 0) {
650 				exten = argv[0];
651 			}
652 			if (argc > 1) {
653 				dialplan = argv[1];
654 			}
655 			if (argc > 2) {
656 				context = argv[2];
657 			}
658 
659 		} else {
660 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty transfer string [%s]\n", (char *) action->expanded_data);
661 			goto done;
662 		}
663 	} else {
664 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Unable to allocate memory to duplicate transfer data.\n");
665 		goto done;
666 	}
667 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_INFO, "Transfering to: %s, %s, %s\n", exten, dialplan, context);
668 
669 	switch_ivr_session_transfer(member->session, exten, dialplan, context);
670 
671  done:
672 	return;
673 }
674 
conference_loop_exec_app(conference_member_t * member,caller_control_action_t * action)675 void conference_loop_exec_app(conference_member_t *member, caller_control_action_t *action)
676 {
677 	char *app = NULL;
678 	char *arg = "";
679 
680 	char *argv[2] = { 0 };
681 	int argc;
682 	char *mydata = NULL;
683 	switch_event_t *event = NULL;
684 	switch_channel_t *channel = NULL;
685 
686 	if (!action->expanded_data) return;
687 
688 	if (test_eflag(member->conference, EFLAG_DTMF) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
689 		conference_member_add_event_data(member, event);
690 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "execute_app");
691 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application", action->expanded_data);
692 		switch_event_fire(&event);
693 	}
694 
695 	mydata = strdup(action->expanded_data);
696 	switch_assert(mydata);
697 
698 	if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
699 		if (argc > 0) {
700 			app = argv[0];
701 		}
702 		if (argc > 1) {
703 			arg = argv[1];
704 		}
705 
706 	} else {
707 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty execute app string [%s]\n",
708 						  (char *) action->expanded_data);
709 		goto done;
710 	}
711 
712 	if (!app) {
713 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Unable to find application.\n");
714 		goto done;
715 	}
716 
717 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_INFO, "Execute app: %s, %s\n", app, arg);
718 
719 	channel = switch_core_session_get_channel(member->session);
720 
721 	switch_channel_set_app_flag(channel, CF_APP_TAGGED);
722 	switch_core_session_set_read_codec(member->session, NULL);
723 	switch_core_session_execute_application(member->session, app, arg);
724 	switch_core_session_set_read_codec(member->session, &member->read_codec);
725 	switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
726 
727  done:
728 
729 	switch_safe_free(mydata);
730 
731 	return;
732 }
733 
conference_loop_hangup(conference_member_t * member,caller_control_action_t * action)734 void conference_loop_hangup(conference_member_t *member, caller_control_action_t *action)
735 {
736 	conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);
737 }
738 
stop_talking_handler(conference_member_t * member)739 static void stop_talking_handler(conference_member_t *member)
740 {
741 	switch_event_t *event;
742 	double avg = 0, avg2 = 0, gcp = 0, ngcp = 0, pct = 0;
743 
744 	member->auto_energy_track = 0;
745 
746 	if (member->score_count && member->talking_count) {
747 		int duration_ms = member->talking_count * member->conference->interval;
748 		avg = (double)member->score_delta_accum / member->score_count;
749 		avg2 = (double)member->score_accum / member->score_count;
750 
751 
752 		if (!member->nogate_count) member->nogate_count = 1;
753 		if (!member->gate_count) member->gate_count = 1;
754 
755 		pct = ((float)member->nogate_count / (float)member->gate_count) * 100;
756 		gcp = ((double)member->gate_count / member->talking_count) * 100;
757 		ngcp = ((double)member->nogate_count / member->talking_count) * 100;
758 
759 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "SCORE AVG %f/%f %d GC %d NGC %d GC %% %f NGC %% %f DIFF %f EL %d MS %d PCT %f\n",
760 			   avg2, avg, member->score_count, member->gate_count,
761 			   member->nogate_count,
762 			   gcp, ngcp, gcp - ngcp, member->energy_level, duration_ms, pct);
763 
764 
765 		if (member->auto_energy_level) {
766 			if (duration_ms > 2000 && pct > 1) {
767 				int new_level = (int)(avg2 *.75);
768 				if (new_level > member->auto_energy_level) {
769 					new_level = member->auto_energy_level;
770 				}
771 				member->energy_level = new_level;
772 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "SET ENERGY %d\n", new_level);
773 			}
774 		}
775 
776 	}
777 
778 	member->gate_open = 0;
779 	member->nogate_count = 0;
780 	member->gate_count = 0;
781 
782 	if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
783 		switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
784 		conference_member_add_event_data(member, event);
785 		if (avg) {
786 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-gate-hits", "%u", member->score_count);
787 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-total-packets", "%u", member->talking_count);
788 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-duration-ms", "%u", member->talking_count * member->conference->interval);
789 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-average-energy", "%f", avg2);
790 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-delta-average", "%f", avg);
791 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-on-percent", "%f", gcp);
792 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-non-hit-ratio", "%f", pct);
793 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-off-percent", "%f", ngcp);
794 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-off-differential", "%f", gcp - ngcp);
795 		}
796 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
797 		switch_event_fire(&event);
798 	}
799 
800 
801 }
802 
803 /* marshall frames from the call leg to the conference thread for muxing to other call legs */
conference_loop_input(switch_thread_t * thread,void * obj)804 void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj)
805 {
806 	switch_event_t *event;
807 	conference_member_t *member = obj;
808 	switch_channel_t *channel;
809 	switch_status_t status;
810 	switch_frame_t *read_frame = NULL;
811 	uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, diff_level = 400;
812 	switch_core_session_t *session = member->session;
813 	uint32_t flush_len;
814 	switch_frame_t tmp_frame = { 0 };
815 
816 	if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
817 		goto end;
818 	}
819 
820 	switch_assert(member != NULL);
821 
822 	conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
823 
824 	channel = switch_core_session_get_channel(session);
825 
826 	switch_core_session_get_read_impl(session, &member->read_impl);
827 
828 	switch_channel_audio_sync(channel);
829 
830 	flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval);
831 
832 	/* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it
833 	   and mux it with any audio from other channels. */
834 
835 	while (conference_utils_member_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) {
836 
837 		if (switch_channel_ready(channel) && switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
838 			switch_yield(100000);
839 			continue;
840 		}
841 
842 		/* Read a frame. */
843 		status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
844 
845 		switch_mutex_lock(member->read_mutex);
846 
847 		/* end the loop, if appropriate */
848 		if (!SWITCH_READ_ACCEPTABLE(status) || !conference_utils_member_test_flag(member, MFLAG_RUNNING)) {
849 			switch_mutex_unlock(member->read_mutex);
850 			break;
851 		}
852 
853 		if (switch_channel_test_flag(channel, CF_VIDEO) && !conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO)) {
854 			conference_utils_member_set_flag_locked(member, MFLAG_ACK_VIDEO);
855 			switch_mutex_lock(member->flag_mutex);
856 			switch_img_free(&member->avatar_png_img);
857 			switch_mutex_unlock(member->flag_mutex);
858 			conference_video_check_avatar(member, SWITCH_FALSE);
859 			switch_core_session_video_reinit(member->session);
860 			conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE);
861 			conference_video_check_flush(member, SWITCH_TRUE);
862 			switch_core_session_request_video_refresh(member->session);
863 		} else if (conference_utils_member_test_flag(member, MFLAG_ACK_VIDEO) && !switch_channel_test_flag(channel, CF_VIDEO)) {
864 			conference_video_check_avatar(member, SWITCH_FALSE);
865 		}
866 
867 		/* if we have caller digits, feed them to the parser to find an action */
868 		if (switch_channel_has_dtmf(channel)) {
869 			char dtmf[128] = "";
870 
871 			switch_channel_dequeue_dtmf_string(channel, dtmf, sizeof(dtmf));
872 
873 			if (conference_utils_member_test_flag(member, MFLAG_DIST_DTMF)) {
874 				conference_member_send_all_dtmf(member, member->conference, dtmf);
875 			} else if (member->dmachine) {
876 				char *p;
877 				char str[2] = "";
878 				for (p = dtmf; p && *p; p++) {
879 					str[0] = *p;
880 					switch_ivr_dmachine_feed(member->dmachine, str, NULL);
881 				}
882 			}
883 		} else if (member->dmachine) {
884 			switch_ivr_dmachine_ping(member->dmachine, NULL);
885 		}
886 
887 		if (switch_queue_size(member->dtmf_queue)) {
888 			switch_dtmf_t *dt;
889 			void *pop;
890 
891 			if (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
892 				dt = (switch_dtmf_t *) pop;
893 				switch_core_session_send_dtmf(member->session, dt);
894 				free(dt);
895 			}
896 		}
897 
898 		if (switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) {
899 			member->reset_media = 10;
900 			switch_channel_audio_sync(member->channel);
901 			switch_channel_clear_flag(member->channel, CF_CONFERENCE_RESET_MEDIA);
902 		}
903 
904 		if (member->reset_media) {
905 			if (--member->reset_media > 0) {
906 				goto do_continue;
907 			}
908 
909 			if (conference_member_setup_media(member, member->conference)) {
910 				switch_mutex_unlock(member->read_mutex);
911 				break;
912 			}
913 
914 			member->loop_loop = 1;
915 
916 			goto do_continue;
917 		}
918 
919 		if (switch_test_flag(read_frame, SFF_CNG)) {
920 			if (hangunder_hits) {
921 				hangunder_hits--;
922 			}
923 			if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
924 				if (++hangover_hits >= hangover) {
925 					hangover_hits = hangunder_hits = 0;
926 					if (member->nogate_count < hangover) {
927 						member->nogate_count = 0;
928 					} else {
929 						member->nogate_count -= hangover;
930 					}
931 					conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
932 					conference_member_update_status_field(member);
933 					conference_member_set_score_iir(member, 0);
934 					member->floor_packets = 0;
935 					stop_talking_handler(member);
936 				}
937 			}
938 
939 			goto do_continue;
940 		}
941 
942 		if (!switch_channel_test_flag(channel, CF_AUDIO)) {
943 			goto do_continue;
944 		}
945 
946 		/* if the member can speak, compute the audio energy level and */
947 		/* generate events when the level crosses the threshold        */
948 		if (((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) ||
949 			 conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) {
950 			uint32_t energy = 0, i = 0, samples = 0, j = 0;
951 			int16_t *data;
952 			int gate_check = 0;
953 			int score_iir = 0;
954 
955 			data = read_frame->data;
956 			member->score = 0;
957 
958 			if (member->volume_in_level) {
959 				switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level);
960 			}
961 
962 			if ((samples = read_frame->datalen / sizeof(*data))) {
963 				for (i = 0; i < samples; i++) {
964 					energy += abs(data[j]);
965 					j++;
966 				}
967 
968 				member->score = energy / samples;
969 			}
970 
971 			if (member->vol_period) {
972 				member->vol_period--;
973 			}
974 
975 			gate_check = conference_member_noise_gate_check(member);
976 
977 			if (gate_check && member->agc) {
978 				switch_agc_feed(member->agc, (int16_t *)read_frame->data, (read_frame->datalen / 2) * member->conference->channels, 1);
979 			}
980 
981 			score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));
982 
983 			if (score_iir > SCORE_MAX_IIR) {
984 				score_iir = SCORE_MAX_IIR;
985 			}
986 
987 			conference_member_set_score_iir(member, score_iir);
988 
989 			if (member->auto_energy_level && !conference_utils_member_test_flag(member, MFLAG_TALKING)) {
990 				if (++member->auto_energy_track >= (1000 / member->conference->interval * member->conference->auto_energy_sec)) {
991 					if (member->energy_level > member->conference->energy_level) {
992 						int new_level = member->energy_level - 100;
993 
994 						if (new_level < member->conference->energy_level) {
995 							new_level = member->conference->energy_level;
996 						}
997 						member->energy_level = new_level;
998 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "ENERGY DOWN %d\n", member->energy_level);
999 					}
1000 					member->auto_energy_track = 0;
1001 				}
1002 			}
1003 
1004 			gate_check = conference_member_noise_gate_check(member);
1005 
1006 			if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) {
1007 				if (member->max_energy_level) {
1008 					if (member->score > member->max_energy_level && ++member->max_energy_hits > member->max_energy_hit_trigger) {
1009 						member->mute_counter = member->burst_mute_count;
1010 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY HIT!\n");
1011 					} else if (!member->mute_counter && member->score > (int)((double)member->max_energy_level * .75)) {
1012 						int dec = 1;
1013 
1014 						if (member->score_count > 9) {
1015 							dec = 4;
1016 						} else if (member->score_count > 6) {
1017 							dec = 3;
1018 						} else if (member->score_count > 3) {
1019 							dec = 2;
1020 						}
1021 
1022 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY THRESHOLD! -%d\n", dec);
1023 						switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, -1 * dec);
1024 					}
1025 				}
1026 
1027 				if (member->mute_counter > 0) {
1028 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY DECAY %d\n", member->mute_counter);
1029 					member->mute_counter--;
1030 					switch_generate_sln_silence(read_frame->data, (read_frame->datalen / 2), member->conference->channels, 1400 * (member->conference->rate / 8000));
1031 					if (member->mute_counter == 0) {
1032 						member->max_energy_hits = 0;
1033 					}
1034 				}
1035 
1036 				if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
1037 					member->talking_count++;
1038 
1039 					if (gate_check) {
1040 						int gate_count = 0, nogate_count = 0;
1041 						double pct;
1042 						member->score_accum += member->score;
1043 						member->score_delta_accum += abs(member->score - member->last_score);
1044 						member->score_count++;
1045 						member->score_avg = member->score_accum / member->score_count;
1046 
1047 						member->gate_count++;
1048 						member->gate_open = 1;
1049 
1050 						gate_count = member->gate_count;
1051 						nogate_count = member->nogate_count;
1052 
1053 						if (!gate_count) {
1054 							pct = 0;
1055 						} else {
1056 							pct = ((float)nogate_count / (float)gate_count) * 100;
1057 						}
1058 
1059 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "TRACK %d %d %d/%d %f\n",
1060 										  member->score,
1061 										  member->score_avg,
1062 										  gate_count, nogate_count, pct);
1063 
1064 
1065 					} else {
1066 						member->nogate_count++;
1067 						member->gate_open = 0;
1068 					}
1069 
1070 				}
1071 
1072 				if (conference_utils_member_test_flag(member, MFLAG_TALK_DATA_EVENTS)) {
1073 					if (++member->talk_track >= (1000 / member->conference->interval * 10)) {
1074 						uint32_t diff = 0;
1075 						double avg = 0;
1076 						switch_event_t *event;
1077 
1078 						if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
1079 							conference_member_add_event_data(member, event);
1080 
1081 
1082 							if (member->first_talk_detect) {
1083 
1084 								if (!member->talk_detects) {
1085 									member->talk_detects = 1;
1086 								}
1087 
1088 								diff = (uint32_t) (switch_micro_time_now() - member->first_talk_detect) / 1000;
1089 								avg = (double)diff / member->talk_detects;
1090 								switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detects", "%d", member->talk_detects);
1091 								switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detect-duration", "%d", diff);
1092 								switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detect-avg", "%f", avg);
1093 							} else {
1094 								switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detects", "%d", 0);
1095 							}
1096 
1097 
1098 							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "talk-report");
1099 							switch_event_fire(&event);
1100 						}
1101 
1102 						if (!conference_utils_member_test_flag(member, MFLAG_TALKING)) {
1103 							member->first_talk_detect = 0;
1104 							member->talk_detects = 0;
1105 						} else {
1106 							member->talk_detects = 1;
1107 						}
1108 
1109 						member->talk_track = 0;
1110 					}
1111 				}
1112 			}
1113 
1114 
1115 			if (gate_check) {
1116 				uint32_t diff = member->score - member->energy_level;
1117 				if (hangover_hits) {
1118 					hangover_hits--;
1119 				}
1120 
1121 				if (member->id == member->conference->floor_holder) {
1122 					member->floor_packets++;
1123 				}
1124 
1125 				if (diff >= diff_level || ++hangunder_hits >= hangunder) {
1126 
1127 					hangover_hits = hangunder_hits = 0;
1128 					member->last_talking = switch_epoch_time_now(NULL);
1129 
1130 					if (!conference_utils_member_test_flag(member, MFLAG_TALKING)) {
1131 						conference_utils_member_set_flag_locked(member, MFLAG_TALKING);
1132 						conference_member_update_status_field(member);
1133 						member->floor_packets = 0;
1134 
1135 
1136 						if (!member->first_talk_detect) {
1137 							member->first_talk_detect = switch_micro_time_now();
1138 						}
1139 
1140 						member->talk_detects++;
1141 						member->score_delta_accum = 0;
1142 						member->score_accum = 0;
1143 						member->score_count = 0;
1144 						member->talking_count = 0;
1145 
1146 						if (test_eflag(member->conference, EFLAG_START_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
1147 							!conference_utils_member_test_flag(member, MFLAG_HOLD) &&
1148 							switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
1149 							conference_member_add_event_data(member, event);
1150 							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-talking");
1151 							switch_event_fire(&event);
1152 						}
1153 
1154 						if (conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) && !conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
1155 
1156 							if (!zstr(member->conference->mute_detect_sound)) {
1157 								conference_utils_member_set_flag(member, MFLAG_INDICATE_MUTE_DETECT);
1158 							}
1159 
1160 							if (test_eflag(member->conference, EFLAG_MUTE_DETECT) &&
1161 								switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
1162 								conference_member_add_event_data(member, event);
1163 								switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "mute-detect");
1164 								switch_event_fire(&event);
1165 							}
1166 						}
1167 					}
1168 				}
1169 			} else {
1170 				if (hangunder_hits) {
1171 					hangunder_hits--;
1172 				}
1173 
1174 				if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
1175 					!conference_utils_member_test_flag(member, MFLAG_HOLD)) {
1176 					if (++hangover_hits >= hangover) {
1177 						hangover_hits = hangunder_hits = 0;
1178 
1179 						if (member->nogate_count < hangover) {
1180 							member->nogate_count = 0;
1181 						} else {
1182 							member->nogate_count -= hangover;
1183 						}
1184 
1185 						conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
1186 						conference_member_update_status_field(member);
1187 
1188 						stop_talking_handler(member);
1189 					}
1190 				}
1191 			}
1192 
1193 
1194 			member->last_score = member->score;
1195 
1196 			if ((switch_channel_test_flag(channel, CF_VIDEO) || member->avatar_png_img) && (member->id == member->conference->floor_holder)) {
1197 				if (member->id != member->conference->video_floor_holder &&
1198 					(member->floor_packets > member->conference->video_floor_packets || member->energy_level == 0)) {
1199 					conference_video_set_floor_holder(member->conference, member, SWITCH_FALSE);
1200 				}
1201 			}
1202 		}
1203 
1204 		/* skip frames that are not actual media or when we are muted or silent */
1205 		if ((conference_utils_member_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || conference_utils_test_flag(member->conference, CFLAG_AUDIO_ALWAYS))
1206 			&& conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD)
1207 			&& !conference_utils_member_test_flag(member, MFLAG_HOLD)
1208 			&& (member->conference->count > 1 || (member->conference->record_count && member->conference->count >= member->conference->min_recording_participants))) {
1209 			switch_audio_resampler_t *read_resampler = member->read_resampler;
1210 			void *data;
1211 			uint32_t datalen;
1212 
1213 			if (read_resampler) {
1214 				int16_t *bptr = (int16_t *) read_frame->data;
1215 				int len = (int) read_frame->datalen;
1216 
1217 				switch_resample_process(read_resampler, bptr, len / 2 / member->read_impl.number_of_channels);
1218 				memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2 * member->read_impl.number_of_channels);
1219 				len = read_resampler->to_len * 2 * member->read_impl.number_of_channels;
1220 				datalen = len;
1221 				data = member->resample_out;
1222 			} else {
1223 				data = read_frame->data;
1224 				datalen = read_frame->datalen;
1225 			}
1226 
1227 			tmp_frame.data = data;
1228 			tmp_frame.datalen = datalen;
1229 			tmp_frame.rate = member->conference->rate;
1230 			conference_member_check_channels(&tmp_frame, member, SWITCH_TRUE);
1231 
1232 
1233 			if (datalen) {
1234 				switch_size_t ok = 1;
1235 
1236 				/* Write the audio into the input buffer */
1237 				switch_mutex_lock(member->audio_in_mutex);
1238 				if (switch_buffer_inuse(member->audio_buffer) > flush_len) {
1239 					switch_buffer_toss(member->audio_buffer, tmp_frame.datalen);
1240 				}
1241 				ok = switch_buffer_write(member->audio_buffer, tmp_frame.data, tmp_frame.datalen);
1242 				switch_mutex_unlock(member->audio_in_mutex);
1243 				if (!ok) {
1244 					switch_mutex_unlock(member->read_mutex);
1245 					break;
1246 				}
1247 			}
1248 		}
1249 
1250 	do_continue:
1251 
1252 		switch_mutex_unlock(member->read_mutex);
1253 
1254 	}
1255 
1256 	if (switch_queue_size(member->dtmf_queue)) {
1257 		switch_dtmf_t *dt;
1258 		void *pop;
1259 
1260 		while (switch_queue_trypop(member->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
1261 			dt = (switch_dtmf_t *) pop;
1262 			free(dt);
1263 		}
1264 	}
1265 
1266 
1267 	switch_resample_destroy(&member->read_resampler);
1268 	switch_core_session_rwunlock(session);
1269 
1270  end:
1271 
1272 	conference_utils_member_clear_flag_locked(member, MFLAG_ITHREAD);
1273 
1274 	return NULL;
1275 }
1276 
1277 
1278 /* launch an input thread for the call leg */
conference_loop_launch_input(conference_member_t * member,switch_memory_pool_t * pool)1279 void conference_loop_launch_input(conference_member_t *member, switch_memory_pool_t *pool)
1280 {
1281 	switch_threadattr_t *thd_attr = NULL;
1282 
1283 	if (member == NULL || member->input_thread)
1284 		return;
1285 
1286 	switch_threadattr_create(&thd_attr, pool);
1287 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
1288 	conference_utils_member_set_flag_locked(member, MFLAG_ITHREAD);
1289 	if (switch_thread_create(&member->input_thread, thd_attr, conference_loop_input, member, pool) != SWITCH_STATUS_SUCCESS) {
1290 		conference_utils_member_clear_flag_locked(member, MFLAG_ITHREAD);
1291 	}
1292 }
1293 
1294 /* marshall frames from the conference (or file or tts output) to the call leg */
1295 /* NB. this starts the input thread after some initial setup for the call leg */
conference_loop_output(conference_member_t * member)1296 void conference_loop_output(conference_member_t *member)
1297 {
1298 	switch_channel_t *channel;
1299 	switch_frame_t write_frame = { 0 };
1300 	uint8_t *data = NULL;
1301 	switch_timer_t timer = { 0 };
1302 	uint32_t interval;
1303 	uint32_t samples;
1304 	//uint32_t csamples;
1305 	uint32_t tsamples;
1306 	uint32_t flush_len;
1307 	uint32_t low_count, bytes;
1308 	call_list_t *call_list, *cp;
1309 	switch_codec_implementation_t read_impl = { 0 }, real_read_impl = { 0 };
1310 	int sanity;
1311 	switch_status_t st;
1312 
1313 	switch_core_session_get_read_impl(member->session, &read_impl);
1314 	switch_core_session_get_real_read_impl(member->session, &real_read_impl);
1315 
1316 
1317 	channel = switch_core_session_get_channel(member->session);
1318 	interval = read_impl.microseconds_per_packet / 1000;
1319 	samples = switch_samples_per_packet(member->conference->rate, interval);
1320 	//csamples = samples;
1321 	tsamples = real_read_impl.samples_per_packet;
1322 	low_count = 0;
1323 	bytes = samples * 2 * member->conference->channels;
1324 	call_list = NULL;
1325 	cp = NULL;
1326 
1327 	member->loop_loop = 0;
1328 
1329 	switch_assert(member->conference != NULL);
1330 
1331 	flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval);
1332 
1333 	if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) {
1334 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed.  Conference Cannot Start\n");
1335 		return;
1336 	}
1337 
1338 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Setup timer %s success interval: %u  samples: %u from codec %s\n",
1339 					  member->conference->timer_name, interval, tsamples, real_read_impl.iananame);
1340 
1341 
1342 	write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE);
1343 	write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
1344 
1345 
1346 	write_frame.codec = &member->write_codec;
1347 
1348 	/* Start the input thread */
1349 	conference_loop_launch_input(member, switch_core_session_get_pool(member->session));
1350 
1351 	if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
1352 		const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
1353 		const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
1354 		const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout");
1355 		const char *flags = switch_channel_get_variable(channel, "conference_utils_auto_outcall_flags");
1356 		const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile");
1357 		const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
1358 		const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
1359 		const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait");
1360 		const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter");
1361 		const char *skip_member_beep = switch_channel_get_variable(channel, "conference_auto_outcall_skip_member_beep");
1362 		int to = 60;
1363 		int wait_sec = 2;
1364 		int loops = 0;
1365 		switch_event_t *var_event;
1366 
1367 		switch_event_create(&var_event, SWITCH_EVENT_CHANNEL_DATA);
1368 		switch_channel_process_export(channel, NULL, var_event, "conference_auto_outcall_export_vars");
1369 
1370 		if (ann && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) {
1371 			member->conference->special_announce = switch_core_strdup(member->conference->pool, ann);
1372 		}
1373 
1374 		switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
1375 
1376 		conference_utils_set_flag(member->conference, CFLAG_OUTCALL);
1377 
1378 		if (toval) {
1379 			to = atoi(toval);
1380 			if (to < 10 || to > 500) {
1381 				to = 60;
1382 			}
1383 		}
1384 
1385 		for (cp = call_list; cp; cp = cp->next) {
1386 			int argc;
1387 			char *argv[512] = { 0 };
1388 			char *cpstr = strdup(cp->string);
1389 			int x = 0;
1390 
1391 			switch_assert(cpstr);
1392 			if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) {
1393 				char delimiter = *delimiter_val;
1394 				argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
1395 			} else {
1396 				argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
1397 			}
1398 			for (x = 0; x < argc; x++) {
1399 				char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
1400 				switch_event_t *event = NULL;
1401 				switch_event_dup(&event, var_event);
1402 				switch_assert(dial_str);
1403 				conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
1404 									  profile, &member->conference->cancel_cause, &event);
1405 				switch_safe_free(dial_str);
1406 			}
1407 			switch_safe_free(cpstr);
1408 		}
1409 
1410 		if (maxwait) {
1411 			int tmp = atoi(maxwait);
1412 			if (tmp > 0) {
1413 				wait_sec = tmp;
1414 			}
1415 		}
1416 
1417 
1418 		loops = wait_sec * 10;
1419 
1420 		switch_channel_set_app_flag(channel, CF_APP_TAGGED);
1421 		do {
1422 			switch_ivr_sleep(member->session, 100, SWITCH_TRUE, NULL);
1423 		} while(switch_channel_up(channel) && (member->conference->originating && --loops));
1424 		switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
1425 
1426 		if (!switch_channel_ready(channel)) {
1427 			member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
1428 			goto end;
1429 		}
1430 
1431 		if (!skip_member_beep || !switch_true(skip_member_beep))
1432 			conference_member_play_file(member, "tone_stream://%(500,0,640)", 0, SWITCH_TRUE);
1433 	}
1434 
1435 	if (!conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
1436 		switch_channel_answer(channel);
1437 	}
1438 
1439 
1440 	sanity = 2000;
1441 	while(!conference_utils_member_test_flag(member, MFLAG_ITHREAD) && sanity > 0) {
1442 		switch_cond_next();
1443 		sanity--;
1444 	}
1445 
1446 	/* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed,      */
1447 	/* you better not block this thread loop for more than the duration of member->conference->timer_name!  */
1448 	while (!member->loop_loop && conference_utils_member_test_flag(member, MFLAG_RUNNING) && conference_utils_member_test_flag(member, MFLAG_ITHREAD)
1449 		   && switch_channel_ready(channel)) {
1450 		switch_event_t *event;
1451 		switch_buffer_t *use_buffer = NULL;
1452 		uint32_t mux_used = 0;
1453 
1454 
1455 		//if (member->reset_media || switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) {
1456 		//	switch_cond_next();
1457 		//	continue;
1458 		//}
1459 
1460 		switch_mutex_lock(member->write_mutex);
1461 
1462 
1463 		if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) {
1464 			if (member->conference->la) {
1465 				conference_event_adv_la(member->conference, member, SWITCH_TRUE);
1466 			}
1467 			switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV);
1468 		}
1469 
1470 
1471 		if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1472 			if (event->event_id == SWITCH_EVENT_MESSAGE) {
1473 				char *from = switch_event_get_header(event, "from");
1474 				char *to = switch_event_get_header(event, "to");
1475 				char *body = switch_event_get_body(event);
1476 
1477 				if (to && from && body) {
1478 					if (strchr(to, '+') && strncmp(to, CONF_CHAT_PROTO, strlen(CONF_CHAT_PROTO))) {
1479 						switch_event_del_header(event, "to");
1480 						switch_event_add_header(event, SWITCH_STACK_BOTTOM,
1481 												"to", "%s+%s@%s", CONF_CHAT_PROTO, member->conference->name, member->conference->domain);
1482 					} else {
1483 						switch_event_del_header(event, "to");
1484 						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", member->conference->name);
1485 					}
1486 					chat_send(event);
1487 				}
1488 			}
1489 			switch_event_destroy(&event);
1490 		}
1491 
1492 		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
1493 			/* test to see if outbound channel has answered */
1494 			if (switch_channel_test_flag(channel, CF_ANSWERED) && !conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
1495 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
1496 								  "Outbound conference channel answered, setting CFLAG_ANSWERED\n");
1497 				conference_utils_set_flag(member->conference, CFLAG_ANSWERED);
1498 			}
1499 		} else {
1500 			if (conference_utils_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
1501 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n");
1502 				switch_channel_answer(channel);
1503 			}
1504 		}
1505 
1506 		use_buffer = NULL;
1507 		mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);
1508 
1509 		if (mux_used) {
1510 			if (mux_used < bytes) {
1511 				if (++low_count >= 5) {
1512 					/* partial frame sitting around this long is useless and builds delay */
1513 					conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
1514 				}
1515 			} else if (mux_used > flush_len) {
1516 				/* getting behind, clear the buffer */
1517 				conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
1518 			}
1519 		}
1520 
1521 		if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
1522 			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
1523 		} else if (mux_used >= bytes) {
1524 			/* Flush the output buffer and write all the data (presumably muxed) back to the channel */
1525 			switch_mutex_lock(member->audio_out_mutex);
1526 			write_frame.data = data;
1527 			use_buffer = member->mux_buffer;
1528 			low_count = 0;
1529 
1530 			if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) {
1531 				write_frame.samples = write_frame.datalen / 2 / member->conference->channels;
1532 
1533 				if( !conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
1534 					memset(write_frame.data, 255, write_frame.datalen);
1535 				} else if (member->volume_out_level) { /* Check for output volume adjustments */
1536 					switch_change_sln_volume(write_frame.data, write_frame.samples * member->conference->channels, member->volume_out_level);
1537 				}
1538 
1539 				//write_frame.timestamp = timer.samplecount;
1540 
1541 				if (member->fnode) {
1542 					conference_member_add_file_data(member, write_frame.data, write_frame.datalen);
1543 				}
1544 
1545 				conference_member_check_channels(&write_frame, member, SWITCH_FALSE);
1546 
1547 				if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
1548 					switch_mutex_unlock(member->audio_out_mutex);
1549 					switch_mutex_unlock(member->write_mutex);
1550 					break;
1551 				}
1552 			}
1553 
1554 			switch_mutex_unlock(member->audio_out_mutex);
1555 		}
1556 
1557 		if (conference_utils_member_test_flag(member, MFLAG_FLUSH_BUFFER)) {
1558 			if (switch_buffer_inuse(member->mux_buffer)) {
1559 				switch_mutex_lock(member->audio_out_mutex);
1560 				switch_buffer_zero(member->mux_buffer);
1561 				switch_mutex_unlock(member->audio_out_mutex);
1562 			}
1563 			conference_utils_member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER);
1564 		}
1565 
1566 		switch_mutex_unlock(member->write_mutex);
1567 
1568 
1569 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE)) {
1570 			if (!zstr(member->conference->muted_sound)) {
1571 				conference_member_play_file(member, member->conference->muted_sound, 0, SWITCH_TRUE);
1572 			} else {
1573 				char msg[512];
1574 
1575 				switch_snprintf(msg, sizeof(msg), "Muted");
1576 				conference_member_say(member, msg, 0);
1577 			}
1578 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE);
1579 		}
1580 
1581 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) {
1582 			if (!zstr(member->conference->mute_detect_sound)) {
1583 				conference_member_play_file(member, member->conference->mute_detect_sound, 0, SWITCH_TRUE);
1584 			} else {
1585 				char msg[512];
1586 
1587 				switch_snprintf(msg, sizeof(msg), "Currently Muted");
1588 				conference_member_say(member, msg, 0);
1589 			}
1590 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT);
1591 		}
1592 
1593 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNMUTE)) {
1594 			if (!zstr(member->conference->unmuted_sound)) {
1595 				conference_member_play_file(member, member->conference->unmuted_sound, 0, SWITCH_TRUE);
1596 			} else {
1597 				char msg[512];
1598 
1599 				switch_snprintf(msg, sizeof(msg), "Un-Muted");
1600 				conference_member_say(member, msg, 0);
1601 			}
1602 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNMUTE);
1603 		}
1604 
1605 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_DEAF)) {
1606 			if (!zstr(member->conference->deaf_sound)) {
1607 				conference_member_play_file(member, member->conference->deaf_sound, 0, SWITCH_TRUE);
1608 			}
1609 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_DEAF);
1610 		}
1611 
1612 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNDEAF)) {
1613 			if (!zstr(member->conference->undeaf_sound)) {
1614 				conference_member_play_file(member, member->conference->undeaf_sound, 0, SWITCH_TRUE);
1615 			}
1616 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNDEAF);
1617 		}
1618 
1619 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_BLIND)) {
1620 			if (!zstr(member->conference->deaf_sound)) {
1621 				conference_member_play_file(member, member->conference->deaf_sound, 0, SWITCH_TRUE);
1622 			}
1623 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_BLIND);
1624 		}
1625 
1626 		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNBLIND)) {
1627 			if (!zstr(member->conference->undeaf_sound)) {
1628 				conference_member_play_file(member, member->conference->undeaf_sound, 0, SWITCH_TRUE);
1629 			}
1630 			conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNBLIND);
1631 		}
1632 
1633 		if (switch_core_session_private_event_count(member->session)) {
1634 			switch_channel_set_app_flag(channel, CF_APP_TAGGED);
1635 			switch_ivr_parse_all_events(member->session);
1636 			switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
1637 			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
1638 			switch_core_session_set_read_codec(member->session, &member->read_codec);
1639 		} else {
1640 			switch_ivr_parse_all_messages(member->session);
1641 		}
1642 
1643 		switch_core_timer_next(&timer);
1644 
1645 	} /* Rinse ... Repeat */
1646 
1647  end:
1648 
1649 	if (!member->loop_loop) {
1650 		conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);
1651 
1652 		/* Wait for the input thread to end */
1653 		if (member->input_thread) {
1654 			switch_thread_join(&st, member->input_thread);
1655 			member->input_thread = NULL;
1656 		}
1657 	}
1658 
1659 	switch_core_timer_destroy(&timer);
1660 
1661 	if (member->loop_loop) {
1662 		return;
1663 	}
1664 
1665 	switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_INFO, "Channel leaving conference, cause: %s\n",
1666 					  switch_channel_cause2str(switch_channel_get_cause(channel)));
1667 
1668 	/* if it's an outbound channel, store the release cause in the conference struct, we might need it */
1669 	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
1670 		member->conference->bridge_hangup_cause = switch_channel_get_cause(channel);
1671 	}
1672 }
1673 
1674 /* For Emacs:
1675  * Local Variables:
1676  * mode:c
1677  * indent-tabs-mode:t
1678  * tab-width:4
1679  * c-basic-offset:4
1680  * End:
1681  * For VIM:
1682  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1683  */
1684