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