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 SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load);
45 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown);
46 SWITCH_MODULE_DEFINITION(mod_conference, mod_conference_load, mod_conference_shutdown, NULL);
47 SWITCH_STANDARD_APP(conference_function);
48 
49 const char *mod_conference_app_name = "conference";
50 char *mod_conference_cf_name = "conference.conf";
51 conference_globals_t conference_globals = {0};
52 int EC = 0;
53 char *api_syntax = NULL;
54 
SWITCH_STANDARD_API(conference_api_main)55 SWITCH_STANDARD_API(conference_api_main){
56 	return conference_api_main_real(cmd, session, stream);
57 }
58 
59 /* Return a Distinct ID # */
next_member_id(void)60 uint32_t next_member_id(void)
61 {
62 	uint32_t id;
63 
64 	switch_mutex_lock(conference_globals.id_mutex);
65 	id = ++conference_globals.id_pool;
66 	switch_mutex_unlock(conference_globals.id_mutex);
67 
68 	return id;
69 }
70 
conference_list(conference_obj_t * conference,switch_stream_handle_t * stream,char * delim)71 void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim)
72 {
73 	conference_member_t *member = NULL;
74 
75 	switch_assert(conference != NULL);
76 	switch_assert(stream != NULL);
77 	switch_assert(delim != NULL);
78 
79 	switch_mutex_lock(conference->member_mutex);
80 
81 	for (member = conference->members; member; member = member->next) {
82 		switch_channel_t *channel;
83 		switch_caller_profile_t *profile;
84 		char *uuid;
85 		char *name;
86 		uint32_t count = 0;
87 		switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD);
88 
89 		if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
90 			continue;
91 		}
92 
93 		uuid = switch_core_session_get_uuid(member->session);
94 		channel = switch_core_session_get_channel(member->session);
95 		profile = switch_channel_get_caller_profile(channel);
96 		name = switch_channel_get_name(channel);
97 
98 		stream->write_function(stream, "%u%s%s%s%s%s%s%s%s%s",
99 							   member->id, delim, name, delim, uuid, delim, profile->caller_id_name, delim, profile->caller_id_number, delim);
100 
101 		if (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
102 			stream->write_function(stream, "hear");
103 			count++;
104 		}
105 
106 		if (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
107 			stream->write_function(stream, "%s%s", count ? "|" : "", "speak");
108 			count++;
109 		}
110 
111 		if (!hold && conference_utils_member_test_flag(member, MFLAG_TALKING)) {
112 			stream->write_function(stream, "%s%s", count ? "|" : "", "talking");
113 			count++;
114 		}
115 
116 		if (hold) {
117 			stream->write_function(stream, "%s%s", count ? "|" : "", "hold");
118 			count++;
119 		}
120 
121 		if (switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO)) {
122 			stream->write_function(stream, "%s%s", count ? "|" : "", "video");
123 			count++;
124 		}
125 
126 		if (member->id == member->conference->floor_holder) {
127 			stream->write_function(stream, "%s%s", count ? "|" : "", "floor");
128 			count++;
129 		}
130 
131 		if (member->id == member->conference->video_floor_holder) {
132 			stream->write_function(stream, "%s%s", count ? "|" : "", "vid-floor");
133 			count++;
134 		}
135 
136 		if (conference_utils_member_test_flag(member, MFLAG_MOD)) {
137 			stream->write_function(stream, "%s%s", count ? "|" : "", "moderator");
138 			count++;
139 		}
140 
141 		if (conference_utils_member_test_flag(member, MFLAG_GHOST)) {
142 			stream->write_function(stream, "%s%s", count ? "|" : "", "ghost");
143 			count++;
144 		}
145 
146 		if (member->video_reservation_id) {
147 			stream->write_function(stream, "%s%s%s", count ? "|" : "", "res-id:", member->video_reservation_id);
148 			count++;
149 		}
150 
151 		if (member->video_role_id) {
152 			stream->write_function(stream, "%s%s%s", count ? "|" : "", "role-id:", member->video_role_id);
153 			count++;
154 		}
155 
156 		stream->write_function(stream, "%s%d%s%d%s%d\n", delim,
157 							   member->volume_in_level,
158 							   delim, member->volume_out_level, delim, member->energy_level);
159 	}
160 
161 	switch_mutex_unlock(conference->member_mutex);
162 }
163 
conference_send_notify(conference_obj_t * conference,const char * status,const char * call_id,switch_bool_t final)164 void conference_send_notify(conference_obj_t *conference, const char *status, const char *call_id, switch_bool_t final)
165 {
166 	switch_event_t *event;
167 	char *name = NULL, *domain = NULL, *dup_domain = NULL;
168 
169 	if (!conference_utils_test_flag(conference, CFLAG_RFC4579)) {
170 		return;
171 	}
172 
173 	if (!(name = conference->name)) {
174 		name = "conference";
175 	}
176 
177 	if (!(domain = conference->domain)) {
178 		dup_domain = switch_core_get_domain(SWITCH_TRUE);
179 		if (!(domain = dup_domain)) {
180 			domain = "cluecon.com";
181 		}
182 	}
183 
184 
185 	if (switch_event_create(&event, SWITCH_EVENT_CONFERENCE_DATA) == SWITCH_STATUS_SUCCESS) {
186 		event->flags |= EF_UNIQ_HEADERS;
187 
188 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "conference-name", name);
189 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "conference-domain", domain);
190 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "conference-event", "refer");
191 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call_id", call_id);
192 
193 		if (final) {
194 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "final", "true");
195 		}
196 
197 
198 		switch_event_add_body(event, "%s", status);
199 		switch_event_fire(&event);
200 	}
201 
202 	switch_safe_free(dup_domain);
203 
204 }
205 
206 
207 /* Main monitor thread (1 per distinct conference room) */
conference_thread_run(switch_thread_t * thread,void * obj)208 void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *obj)
209 {
210 	conference_obj_t *conference = (conference_obj_t *) obj;
211 	conference_member_t *imember, *omember;
212 	uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval);
213 	uint32_t bytes = samples * 2 * conference->channels;
214 	uint8_t ready = 0, total = 0;
215 	switch_timer_t timer = { 0 };
216 	switch_event_t *event;
217 	uint8_t *file_frame;
218 	uint8_t *async_file_frame;
219 	int16_t *bptr;
220 	uint32_t x = 0;
221 	int32_t z = 0;
222 	conference_cdr_node_t *np;
223 
224 	file_frame = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
225 	async_file_frame = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
226 
227 	if (switch_core_timer_init(&timer, conference->timer_name, conference->interval, samples, conference->pool) == SWITCH_STATUS_SUCCESS) {
228 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setup timer success interval: %u  samples: %u\n", conference->interval, samples);
229 	} else {
230 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Timer Setup Failed.  Conference Cannot Start\n");
231 		return NULL;
232 	}
233 
234 	switch_mutex_lock(conference_globals.hash_mutex);
235 	conference_globals.threads++;
236 	switch_mutex_unlock(conference_globals.hash_mutex);
237 
238 	conference->auto_recording = 0;
239 	conference->record_count = 0;
240 
241 	while (conference_globals.running && !conference_utils_test_flag(conference, CFLAG_DESTRUCT)) {
242 		switch_size_t file_sample_len = samples;
243 		switch_size_t file_data_len = samples * 2 * conference->channels;
244 		int has_file_data = 0, members_with_video = 0, members_with_avatar = 0, members_seeing_video = 0;
245 		int nomoh = 0;
246 		uint32_t floor_holder;
247 		switch_status_t moh_status = SWITCH_STATUS_SUCCESS;
248 
249 		/* Sync the conference to a single timing source */
250 		if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) {
251 			conference_utils_set_flag(conference, CFLAG_DESTRUCT);
252 			break;
253 		}
254 
255 		switch_mutex_lock(conference->mutex);
256 		has_file_data = ready = total = 0;
257 
258 		floor_holder = conference->floor_holder;
259 
260 		for (imember = conference->members; imember; imember = imember->next) {
261 			if (!zstr(imember->text_framedata)) {
262 				switch_frame_t frame = { 0 };
263 				char *framedata;
264 				uint32_t framedatalen;
265 				const char *caller_id_name = switch_channel_get_variable(imember->channel, "caller_id_name");
266 				unsigned char CR[3] = TEXT_UNICODE_LINEFEED;
267 
268 
269 				switch_mutex_lock(imember->text_mutex);
270 
271 				framedatalen = strlen(imember->text_framedata) + strlen(caller_id_name) + 6;
272 
273 				switch_zmalloc(framedata, framedatalen);
274 
275 				switch_snprintf(framedata, framedatalen, "%s::\n%s", caller_id_name, imember->text_framedata);
276 				memcpy(framedata + strlen(framedata), CR, sizeof(CR));
277 
278 
279 				frame.data = framedata;
280 				frame.datalen = framedatalen;
281 
282 				for (omember = conference->members; omember; omember = omember->next) {
283 					if (omember != imember && omember->session) {
284 						switch_core_session_write_text_frame(omember->session, &frame, 0, 0);
285 					}
286 				}
287 
288 				free(framedata);
289 
290 				imember->text_framedata[0] = '\0';
291 
292 				switch_mutex_unlock(imember->text_mutex);
293 			}
294 		}
295 
296 		/* Read one frame of audio from each member channel and save it for redistribution */
297 		for (imember = conference->members; imember; imember = imember->next) {
298 			uint32_t buf_read = 0;
299 			total++;
300 			imember->read = 0;
301 
302 			if (conference_utils_member_test_flag(imember, MFLAG_RUNNING) && imember->session) {
303 				switch_channel_t *channel = switch_core_session_get_channel(imember->session);
304 				switch_media_flow_t video_media_flow;
305 
306 				if ((!floor_holder || (imember->id != conference->floor_holder && imember->score_iir > SCORE_IIR_SPEAKING_MAX && (conference->floor_holder_score_iir < SCORE_IIR_SPEAKING_MIN)))) {// &&
307 					//(!conference_utils_test_flag(conference, CFLAG_VID_FLOOR) || switch_channel_test_flag(channel, CF_VIDEO))) {
308 
309 
310 					if (!conference_utils_member_test_flag(imember, MFLAG_DED_VID_LAYER) || conference_utils_test_flag(conference, CFLAG_DED_VID_LAYER_AUDIO_FLOOR)) {
311 						conference_member_set_floor_holder(conference, imember, 0);
312 						floor_holder = conference->floor_holder;
313 					}
314 				}
315 
316 				video_media_flow = switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO);
317 
318 				if (video_media_flow != imember->video_media_flow) {
319 					imember->video_media_flow = video_media_flow;
320 
321 					if (imember->video_media_flow == SWITCH_MEDIA_FLOW_SENDONLY) {
322 						conference_utils_member_clear_flag(imember, MFLAG_CAN_BE_SEEN);
323 						conference_video_find_floor(imember, SWITCH_FALSE);
324 					} else {
325 						conference_utils_member_set_flag(imember, MFLAG_CAN_BE_SEEN);
326 						conference_video_find_floor(imember, SWITCH_TRUE);
327 						switch_core_session_request_video_refresh(imember->session);
328 					}
329 				}
330 
331 				if (switch_channel_ready(channel) &&
332 					switch_channel_test_flag(channel, CF_VIDEO_READY) &&
333 					imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY &&
334 					!conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) &&
335 					!conference_utils_member_test_flag(imember, MFLAG_HOLD) &&
336 					(!conference_utils_test_flag(conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) ||
337 					 conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN))) {
338 					members_with_video++;
339 				}
340 
341 				if (switch_channel_ready(channel) &&
342 					switch_channel_test_flag(channel, CF_VIDEO_READY) &&
343 					imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY &&
344 					!conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN)) {
345 					members_seeing_video++;
346 				}
347 
348 				if (!conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS)) {
349 					if (imember->avatar_png_img && !switch_channel_test_flag(channel, CF_VIDEO)) {
350 						members_with_avatar++;
351 					}
352 				} else {
353 					members_with_avatar = 0;
354 				}
355 
356 				if (conference_utils_member_test_flag(imember, MFLAG_NOMOH)) {
357 					nomoh++;
358 				}
359 			}
360 
361 			conference_utils_member_clear_flag_locked(imember, MFLAG_HAS_AUDIO);
362 			switch_mutex_lock(imember->audio_in_mutex);
363 
364 			if (switch_buffer_inuse(imember->audio_buffer) >= bytes
365 				&& (buf_read = (uint32_t) switch_buffer_read(imember->audio_buffer, imember->frame, bytes))) {
366 				imember->read = buf_read;
367 				conference_utils_member_set_flag_locked(imember, MFLAG_HAS_AUDIO);
368 				ready++;
369 			}
370 			switch_mutex_unlock(imember->audio_in_mutex);
371 		}
372 
373 		conference->members_with_video = members_with_video;
374 		conference->members_seeing_video = members_seeing_video;
375 		conference->members_with_avatar = members_with_avatar;
376 
377 		if (floor_holder != conference->floor_holder) {
378 			conference_member_set_floor_holder(conference, NULL, floor_holder);
379 		}
380 
381 		if (conference_utils_test_flag(conference, CFLAG_NO_MOH)) {
382 			nomoh++;
383 		}
384 
385 		if (conference->moh_wait > 0) {
386 			conference->moh_wait--;
387 		} else {
388 			char *moh_sound = conference->tmp_moh_sound;
389 
390 			if (!moh_sound) {
391 				moh_sound = conference->moh_sound;
392 			}
393 
394 			if (conference->perpetual_sound && !conference->async_fnode) {
395 				moh_status = conference_file_play(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1);
396 			} else if (moh_sound && ((nomoh == 0 && conference->count == 1)
397 												 || conference_utils_test_flag(conference, CFLAG_WAIT_MOD)) &&
398 					   !conference->async_fnode && !conference->fnode) {
399 				moh_status = conference_file_play(conference, moh_sound, CONF_DEFAULT_LEADIN, NULL, 1);
400 			}
401 		}
402 
403 		if (!conference->moh_wait && moh_status != SWITCH_STATUS_SUCCESS) {
404 			conference->moh_wait = 2000 / conference->interval;
405 		}
406 
407 		/* Find if no one talked for more than x number of second */
408 		if (conference->terminate_on_silence && conference->count > 1) {
409 			int is_talking = 0;
410 
411 			for (imember = conference->members; imember; imember = imember->next) {
412 				if (switch_epoch_time_now(NULL) - imember->join_time <= conference->terminate_on_silence) {
413 					is_talking++;
414 				} else if (imember->last_talking != 0 && switch_epoch_time_now(NULL) - imember->last_talking <= conference->terminate_on_silence) {
415 					is_talking++;
416 				}
417 			}
418 			if (is_talking == 0) {
419 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Conference has been idle for over %d seconds, terminating\n", conference->terminate_on_silence);
420 				conference_utils_set_flag(conference, CFLAG_DESTRUCT);
421 			}
422 		}
423 
424 		/* Start auto recording if there's the minimum number of required participants. */
425 		if (conference->auto_record && !conference->auto_recording && (conference->count >= conference->min_recording_participants)) {
426 			conference->auto_recording++;
427 			conference->record_count++;
428 			imember = conference->members;
429 			if (imember) {
430 				switch_channel_t *channel = switch_core_session_get_channel(imember->session);
431 				char *rfile = switch_channel_expand_variables(channel, conference->auto_record);
432 
433 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Auto recording file: %s\n", rfile);
434 				conference_record_launch_thread(conference, rfile, -1, SWITCH_TRUE);
435 
436 				if (rfile != conference->auto_record) {
437 					conference->record_filename = switch_core_strdup(conference->pool, rfile);
438 					switch_safe_free(rfile);
439 				} else {
440 					conference->record_filename = switch_core_strdup(conference->pool, conference->auto_record);
441 				}
442 
443 				/* Set the conference recording variable for each member */
444 				for (omember = conference->members; omember; omember = omember->next) {
445 					if (!omember->session) continue;
446 					channel = switch_core_session_get_channel(omember->session);
447 					switch_channel_set_variable(channel, "conference_recording", conference->record_filename);
448 					switch_channel_set_variable_printf(channel, "conference_recording_canvas", "%d", conference->auto_record_canvas + 1);
449 				}
450 			} else {
451 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Auto Record Failed.  No members in conference.\n");
452 			}
453 		}
454 
455 		switch_mutex_lock(conference->file_mutex);
456 		/* If a file or speech event is being played */
457 		if (conference->fnode && !switch_test_flag(conference->fnode, NFLAG_PAUSE)) {
458 			/* Lead in time */
459 			if (conference->fnode->leadin) {
460 				conference->fnode->leadin--;
461 			} else if (!conference->fnode->done) {
462 				file_sample_len = samples;
463 
464 				if (conference->fnode->type == NODE_TYPE_SPEECH) {
465 					switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_BLOCKING;
466 					switch_size_t speech_len = file_data_len;
467 
468 					if (conference->fnode->al) {
469 						speech_len /= 2;
470 					}
471 
472 					if (switch_core_speech_read_tts(conference->fnode->sh, file_frame, &speech_len, &flags) == SWITCH_STATUS_SUCCESS) {
473 
474 						if (conference->fnode->al) {
475 							conference_al_process(conference->fnode->al, file_frame, speech_len, conference->rate);
476 						}
477 
478 						file_sample_len = file_data_len / 2 / conference->fnode->sh->channels;
479 
480 
481 					} else {
482 						file_sample_len = file_data_len = 0;
483 					}
484 				} else if (conference->fnode->type == NODE_TYPE_FILE) {
485 					switch_core_file_read(&conference->fnode->fh, file_frame, &file_sample_len);
486 
487 					if (conference->fnode->fh.vol) {
488 						switch_change_sln_volume_granular((void *)file_frame, (uint32_t)file_sample_len * conference->fnode->fh.channels,
489 														  conference->fnode->fh.vol);
490 					}
491 					if (conference->fnode->al) {
492 						conference_al_process(conference->fnode->al, file_frame, file_sample_len * 2, conference->fnode->fh.samplerate);
493 					}
494 				}
495 
496 				if (file_sample_len <= 0) {
497 					if (conference->fnode->loops) {
498 						if (--conference->fnode->loops < 0) {
499 							conference->fnode->loops = -1;
500 						}
501 
502 						if (conference->fnode->loops) {
503 							uint32_t pos = 0;
504 							switch_core_file_seek(&conference->fnode->fh, &pos, 0, SEEK_SET);
505 						}
506 					}
507 
508 					if (!conference->fnode->loops) {
509 						conference->fnode->done++;
510 					}
511 				} else {
512 					has_file_data = 1;
513 				}
514 			}
515 		}
516 
517 		if (conference->async_fnode) {
518 			/* Lead in time */
519 			if (conference->async_fnode->leadin) {
520 				conference->async_fnode->leadin--;
521 			} else if (!conference->async_fnode->done) {
522 				file_sample_len = samples;
523 				switch_core_file_read(&conference->async_fnode->fh, async_file_frame, &file_sample_len);
524 				if (conference->async_fnode->al) {
525 					conference_al_process(conference->async_fnode->al, file_frame, file_sample_len * 2, conference->async_fnode->fh.samplerate);
526 				}
527 				if (file_sample_len <= 0) {
528 					if (conference->async_fnode->loops) {
529 						if (--conference->async_fnode->loops < 0) {
530 							conference->async_fnode->loops = -1;
531 						}
532 
533 						if (conference->async_fnode->loops) {
534 							uint32_t pos = 0;
535 							switch_core_file_seek(&conference->async_fnode->fh, &pos, 0, SEEK_SET);
536 						}
537 					}
538 
539 					if (!conference->async_fnode->loops) {
540 						conference->async_fnode->done++;
541 					}
542 				} else {
543 					if (has_file_data) {
544 						switch_size_t x;
545 						for (x = 0; x < file_sample_len * conference->channels; x++) {
546 							int32_t z;
547 							int16_t *muxed;
548 
549 							muxed = (int16_t *) file_frame;
550 							bptr = (int16_t *) async_file_frame;
551 							z = muxed[x] + bptr[x];
552 							switch_normalize_to_16bit(z);
553 							muxed[x] = (int16_t) z;
554 						}
555 					} else {
556 						memcpy(file_frame, async_file_frame, file_sample_len * 2 * conference->channels);
557 						has_file_data = 1;
558 					}
559 				}
560 			}
561 		}
562 		switch_mutex_unlock(conference->file_mutex);
563 
564 		if (ready || has_file_data) {
565 			/* Use more bits in the main_frame to preserve the exact sum of the audio samples. */
566 			int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
567 			int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
568 
569 
570 			/* Init the main frame with file data if there is any. */
571 			bptr = (int16_t *) file_frame;
572 			if (has_file_data && file_sample_len) {
573 
574 				for (x = 0; x < bytes / 2; x++) {
575 					if (x <= file_sample_len * conference->channels) {
576 						main_frame[x] = (int32_t) bptr[x];
577 					} else {
578 						memset(&main_frame[x], 255, sizeof(main_frame[x]));
579 					}
580 				}
581 			}
582 
583 			conference->mux_loop_count = 0;
584 			conference->member_loop_count = 0;
585 
586 
587 			/* Copy audio from every member known to be producing audio into the main frame. */
588 			for (omember = conference->members; omember; omember = omember->next) {
589 				conference->member_loop_count++;
590 
591 				if (!(conference_utils_member_test_flag(omember, MFLAG_RUNNING) && conference_utils_member_test_flag(omember, MFLAG_HAS_AUDIO))) {
592 					continue;
593 				}
594 
595 				bptr = (int16_t *) omember->frame;
596 				for (x = 0; x < omember->read / 2; x++) {
597 					main_frame[x] += (int32_t) bptr[x];
598 				}
599 			}
600 
601 			/* Create write frame once per member who is not deaf for each sample in the main frame
602 			   check if our audio is involved and if so, subtract it from the sample so we don't hear ourselves.
603 			   Since main frame was 32 bit int, we did not lose any detail, now that we have to convert to 16 bit we can
604 			   cut it off at the min and max range if need be and write the frame to the output buffer.
605 			*/
606 			for (omember = conference->members; omember; omember = omember->next) {
607 				switch_size_t ok = 1;
608 
609 				if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING) ||
610 					(!conference_utils_member_test_flag(omember, MFLAG_NOCHANNEL) && !switch_channel_test_flag(omember->channel, CF_AUDIO))) {
611 					continue;
612 				}
613 
614 				if (!conference_utils_member_test_flag(omember, MFLAG_CAN_HEAR)) {
615 					switch_mutex_lock(omember->audio_out_mutex);
616 					memset(write_frame, 255, bytes);
617 					ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes);
618 					switch_mutex_unlock(omember->audio_out_mutex);
619 					if (!ok) {
620 						switch_mutex_unlock(conference->mutex);
621 						goto end;
622 					}
623 					continue;
624 				}
625 
626 				bptr = (int16_t *) omember->frame;
627 
628 				for (x = 0; x < bytes / 2 ; x++) {
629 					z = main_frame[x];
630 
631 					/* bptr[x] represents my own contribution to this audio sample */
632 					if (conference_utils_member_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) {
633 						z -= (int32_t) bptr[x];
634 					}
635 
636 					/* when there are relationships, we have to do more work by scouring all the members to see if there are any
637 					   reasons why we should not be hearing a paticular member, and if not, delete their samples as well.
638 					*/
639 					if (conference->relationship_total) {
640 						for (imember = conference->members; imember; imember = imember->next) {
641 							if (imember != omember && conference_utils_member_test_flag(imember, MFLAG_HAS_AUDIO)) {
642 								conference_relationship_t *rel;
643 								switch_size_t found = 0;
644 								int16_t *rptr = (int16_t *) imember->frame;
645 								for (rel = imember->relationships; rel; rel = rel->next) {
646 									if ((rel->id == omember->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
647 										z -= (int32_t) rptr[x];
648 										found = 1;
649 										break;
650 									}
651 								}
652 								if (!found) {
653 									for (rel = omember->relationships; rel; rel = rel->next) {
654 										if ((rel->id == imember->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_HEAR)) {
655 											z -= (int32_t) rptr[x];
656 											break;
657 										}
658 									}
659 								}
660 
661 							}
662 						}
663 					}
664 
665 					/* Now we can convert to 16 bit. */
666 					switch_normalize_to_16bit(z);
667 					write_frame[x] = (int16_t) z;
668 				}
669 
670 				if (!omember->channel || switch_channel_test_flag(omember->channel, CF_AUDIO)) {
671 					switch_mutex_lock(omember->audio_out_mutex);
672 					ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes);
673 					switch_mutex_unlock(omember->audio_out_mutex);
674 					if (!ok) {
675 						switch_mutex_unlock(conference->mutex);
676 						goto end;
677 					}
678 				}
679 			}
680 		} else { /* There is no source audio.  Push silence into all of the buffers */
681 			int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
682 
683 			if (conference->comfort_noise_level) {
684 				switch_generate_sln_silence(write_frame, samples, conference->channels, conference->comfort_noise_level * (conference->rate / 8000));
685 			} else {
686 				memset(write_frame, 255, bytes);
687 			}
688 
689 			for (omember = conference->members; omember; omember = omember->next) {
690 				switch_size_t ok = 1;
691 
692 				if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING) ||
693 					(!conference_utils_member_test_flag(omember, MFLAG_NOCHANNEL) && !switch_channel_test_flag(omember->channel, CF_AUDIO))) {
694 					continue;
695 				}
696 
697 				switch_mutex_lock(omember->audio_out_mutex);
698 				ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes);
699 				switch_mutex_unlock(omember->audio_out_mutex);
700 
701 				if (!ok) {
702 					switch_mutex_unlock(conference->mutex);
703 					goto end;
704 				}
705 			}
706 		}
707 
708 		if (conference->async_fnode && conference->async_fnode->done) {
709 			switch_memory_pool_t *pool;
710 
711 			if (conference->canvases[0] && conference->async_fnode->layer_id > -1 ) {
712 				conference_video_canvas_del_fnode_layer(conference, conference->async_fnode);
713 			}
714 
715 			switch_mutex_lock(conference->file_mutex);
716 			conference_file_close(conference, conference->async_fnode);
717 			pool = conference->async_fnode->pool;
718 			conference->async_fnode = NULL;
719 			switch_core_destroy_memory_pool(&pool);
720 			switch_mutex_unlock(conference->file_mutex);
721 		}
722 
723 		if (conference->fnode && conference->fnode->done) {
724 			conference_file_node_t *fnode;
725 			switch_memory_pool_t *pool;
726 
727 			switch_mutex_lock(conference->file_mutex);
728 			if (conference->fnode->type != NODE_TYPE_SPEECH) {
729 				conference_file_close(conference, conference->fnode);
730 			}
731 
732 			if (conference->canvases[0] && conference->fnode->layer_id > -1 ) {
733 				conference_video_canvas_del_fnode_layer(conference, conference->fnode);
734 			}
735 
736 
737 			fnode = conference->fnode;
738 			conference->fnode = conference->fnode->next;
739 
740 			if (conference->fnode) {
741 				conference_video_fnode_check(conference->fnode, -1);
742 			}
743 
744 
745 			pool = fnode->pool;
746 			fnode = NULL;
747 			switch_core_destroy_memory_pool(&pool);
748 			switch_mutex_unlock(conference->file_mutex);
749 		}
750 
751 		if (!conference->end_count && conference->endconference_time &&
752 			switch_epoch_time_now(NULL) - conference->endconference_time > conference->endconference_grace_time) {
753 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Conference %s: endconf grace time exceeded (%u)\n",
754 							  conference->name, conference->endconference_grace_time);
755 			conference_utils_set_flag(conference, CFLAG_DESTRUCT);
756 			conference_utils_set_flag(conference, CFLAG_ENDCONF_FORCED);
757 		}
758 
759 		switch_mutex_unlock(conference->mutex);
760 	}
761 	/* Rinse ... Repeat */
762  end:
763 
764 	if (conference_utils_test_flag(conference, CFLAG_OUTCALL)) {
765 		conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
766 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Ending pending outcall channels for Conference: '%s'\n", conference->name);
767 		while(conference->originating) {
768 			switch_yield(200000);
769 		}
770 	}
771 
772 	conference_send_presence(conference);
773 
774 	switch_mutex_lock(conference->mutex);
775 	conference_file_stop(conference, FILE_STOP_ASYNC);
776 	conference_file_stop(conference, FILE_STOP_ALL);
777 
778 	switch_mutex_lock(conference->member_mutex);
779 	for (imember = conference->members; imember; imember = imember->next) {
780 		switch_channel_t *channel;
781 
782 		if (!conference_utils_member_test_flag(imember, MFLAG_NOCHANNEL)) {
783 			channel = switch_core_session_get_channel(imember->session);
784 
785 			if (!switch_false(switch_channel_get_variable(channel, "hangup_after_conference"))) {
786 				/* add this little bit to preserve the bridge cause code in case of an early media call that */
787 				/* never answers */
788 				if (conference_utils_test_flag(conference, CFLAG_ANSWERED)) {
789 					switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
790 				} else {
791 					/* put actual cause code from outbound channel hangup here */
792 					switch_channel_hangup(channel, conference->bridge_hangup_cause);
793 				}
794 			}
795 		}
796 
797 		conference_utils_member_clear_flag_locked(imember, MFLAG_RUNNING);
798 	}
799 	switch_mutex_unlock(conference->member_mutex);
800 	switch_mutex_unlock(conference->mutex);
801 
802 	if (conference->vh[0].up == 1) {
803 		conference->vh[0].up = -1;
804 	}
805 
806 	if (conference->vh[1].up == 1) {
807 		conference->vh[1].up = -1;
808 	}
809 
810 	while (conference->vh[0].up || conference->vh[1].up) {
811 		switch_cond_next();
812 	}
813 
814 	switch_core_timer_destroy(&timer);
815 	switch_mutex_lock(conference_globals.hash_mutex);
816 	if (conference_utils_test_flag(conference, CFLAG_INHASH)) {
817 		switch_core_hash_delete(conference_globals.conference_hash, conference->name);
818 	}
819 	switch_mutex_unlock(conference_globals.hash_mutex);
820 
821 	conference_utils_clear_flag(conference, CFLAG_VIDEO_MUXING);
822 
823 	for (x = 0; x <= conference->canvas_count; x++) {
824 		if (conference->canvases[x] && conference->canvases[x]->video_muxing_thread) {
825 			switch_status_t st = 0;
826 			switch_thread_join(&st, conference->canvases[x]->video_muxing_thread);
827 			conference->canvases[x]->video_muxing_thread = NULL;
828 		}
829 	}
830 
831 	conference_close_open_files(conference);
832 
833 	/* Wait till everybody is out */
834 	conference_utils_clear_flag_locked(conference, CFLAG_RUNNING);
835 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock ON\n");
836 	switch_thread_rwlock_wrlock(conference->rwlock);
837 	switch_thread_rwlock_unlock(conference->rwlock);
838 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock OFF\n");
839 
840 	if (conference->la) {
841 		switch_live_array_destroy(&conference->la);
842 	}
843 
844 	if (conference->sh) {
845 		switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
846 		switch_core_speech_close(&conference->lsh, &flags);
847 		conference->sh = NULL;
848 	}
849 
850 	conference->end_time = switch_epoch_time_now(NULL);
851 
852 	switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
853 	conference_event_add_data(conference, event);
854 	switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-destroy");
855 	switch_event_fire(&event);
856 
857 	switch_mutex_lock(conference->member_mutex);
858 	conference_cdr_render(conference);
859 
860 	for (np = conference->cdr_nodes; np; np = np->next) {
861 		if (np->var_event) {
862 			switch_event_destroy(&np->var_event);
863 		}
864 	}
865 	switch_mutex_unlock(conference->member_mutex);
866 
867 	switch_mutex_lock(conference_globals.setup_mutex);
868 	if (conference->layout_hash) {
869 		switch_core_hash_destroy(&conference->layout_hash);
870 	}
871 	switch_mutex_unlock(conference_globals.setup_mutex);
872 
873 	if (conference->layout_group_hash) {
874 		switch_core_hash_destroy(&conference->layout_group_hash);
875 	}
876 
877 	switch_mutex_lock(conference->flag_mutex);
878 	switch_event_destroy(&conference->variables);
879 	switch_mutex_unlock(conference->flag_mutex);
880 
881 	if (conference->pool) {
882 		switch_memory_pool_t *pool = conference->pool;
883 		switch_core_destroy_memory_pool(&pool);
884 	}
885 
886 	switch_mutex_lock(conference_globals.hash_mutex);
887 	conference_globals.threads--;
888 	switch_mutex_unlock(conference_globals.hash_mutex);
889 
890 	return NULL;
891 }
892 
893 
894 
895 /* Say some thing with TTS in the conference room */
conference_say(conference_obj_t * conference,const char * text,uint32_t leadin)896 switch_status_t conference_say(conference_obj_t *conference, const char *text, uint32_t leadin)
897 {
898 	switch_status_t status = SWITCH_STATUS_FALSE;
899 	conference_file_node_t *fnode, *nptr;
900 	switch_memory_pool_t *pool;
901 	switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
902 	uint32_t count;
903 	switch_event_t *params = NULL;
904 	char *fp = NULL;
905 	int channels;
906 	const char *position = NULL;
907 	const char *tts_engine = NULL, *tts_voice = NULL;
908 
909 	switch_assert(conference != NULL);
910 
911 	channels = conference->channels;
912 
913 	if (zstr(text)) {
914 		return SWITCH_STATUS_GENERR;
915 	}
916 
917 
918 	switch_mutex_lock(conference->mutex);
919 	switch_mutex_lock(conference->member_mutex);
920 	count = conference->count;
921 	switch_mutex_unlock(conference->member_mutex);
922 	switch_mutex_unlock(conference->mutex);
923 
924 	if (!count) {
925 		return SWITCH_STATUS_FALSE;
926 	}
927 
928 	/* Setup a memory pool to use. */
929 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
930 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n");
931 		return SWITCH_STATUS_MEMERR;
932 	}
933 
934 	/* Create a node object */
935 	if (!(fnode = switch_core_alloc(pool, sizeof(*fnode)))) {
936 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Alloc Failure\n");
937 		switch_core_destroy_memory_pool(&pool);
938 		return SWITCH_STATUS_MEMERR;
939 	}
940 
941 	fnode->conference = conference;
942 	fnode->layer_id = -1;
943 
944 	if (*text == '{') {
945 		char *new_fp;
946 
947 		fp = switch_core_strdup(pool, text);
948 		switch_assert(fp);
949 
950 		if (switch_event_create_brackets(fp, '{', '}', ',', &params, &new_fp, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
951 			new_fp = fp;
952 		}
953 
954 		text = new_fp;
955 	}
956 
957 
958 	fnode->type = NODE_TYPE_SPEECH;
959 	fnode->leadin = leadin;
960 
961 	if (params) {
962 		tts_engine = switch_event_get_header(params, "tts_engine");
963 		tts_voice = switch_event_get_header(params, "tts_voice");
964 
965 		if ((position = switch_event_get_header(params, "position"))) {
966 			if (conference->channels != 2) {
967 				position = NULL;
968 			} else {
969 				channels = 1;
970 				fnode->al = conference_al_create(pool);
971 				if (conference_al_parse_position(fnode->al, position) != SWITCH_STATUS_SUCCESS) {
972 					fnode->al = NULL;
973 					channels = conference->channels;
974 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Position Data.\n");
975 				}
976 			}
977 		}
978 	}
979 
980 	if (conference->sh && conference->last_speech_channels != channels) {
981 		switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
982 		switch_core_speech_close(&conference->lsh, &flags);
983 		conference->sh = NULL;
984 	}
985 
986 	if (!tts_engine) {
987 		tts_engine = conference->tts_engine;
988 	}
989 
990 	if (!tts_voice) {
991 		tts_voice = conference->tts_voice;
992 	}
993 
994 	if (zstr(tts_engine) || zstr(tts_voice)) {
995 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing TTS engine or voice\n");
996 		status = SWITCH_STATUS_FALSE;
997 		goto end;
998 	}
999 
1000 	if (!conference->sh) {
1001 		memset(&conference->lsh, 0, sizeof(conference->lsh));
1002 		if (switch_core_speech_open(&conference->lsh, tts_engine, tts_voice,
1003 									conference->rate, conference->interval, channels, &flags, NULL) != SWITCH_STATUS_SUCCESS) {
1004 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module [%s]!\n", conference->tts_engine);
1005 			status = SWITCH_STATUS_FALSE;
1006 			goto end;
1007 		}
1008 		conference->last_speech_channels = channels;
1009 		conference->sh = &conference->lsh;
1010 	}
1011 
1012 	fnode->pool = pool;
1013 
1014 	/* Queue the node */
1015 	switch_mutex_lock(conference->mutex);
1016 	for (nptr = conference->fnode; nptr && nptr->next; nptr = nptr->next);
1017 
1018 	if (nptr) {
1019 		nptr->next = fnode;
1020 	} else {
1021 		conference->fnode = fnode;
1022 	}
1023 
1024 	fnode->sh = conference->sh;
1025 	if (*text == '#') {
1026 		char *tmp = (char *) text + 1;
1027 		char *vp = tmp, voice[128] = "";
1028 		if ((tmp = strchr(tmp, '#'))) {
1029 			text = tmp + 1;
1030 			switch_copy_string(voice, vp, (tmp - vp) + 1);
1031 			switch_core_speech_text_param_tts(fnode->sh, "voice", voice);
1032 		}
1033 	} else {
1034 		switch_core_speech_text_param_tts(fnode->sh, "voice", tts_voice);
1035 	}
1036 
1037 	/* Begin Generation */
1038 	switch_sleep(200000);
1039 	switch_core_speech_feed_tts(fnode->sh, (char *) text, &flags);
1040 	switch_mutex_unlock(conference->mutex);
1041 	status = SWITCH_STATUS_SUCCESS;
1042 
1043  end:
1044 
1045 	if (params) {
1046 		switch_event_destroy(&params);
1047 	}
1048 
1049 	return status;
1050 }
1051 
1052 
conference_list_conferences(const char * line,const char * cursor,switch_console_callback_match_t ** matches)1053 switch_status_t conference_list_conferences(const char *line, const char *cursor, switch_console_callback_match_t **matches)
1054 {
1055 	switch_console_callback_match_t *my_matches = NULL;
1056 	switch_status_t status = SWITCH_STATUS_FALSE;
1057 	switch_hash_index_t *hi;
1058 	void *val;
1059 	const void *vvar;
1060 
1061 	switch_mutex_lock(conference_globals.hash_mutex);
1062 	for (hi = switch_core_hash_first(conference_globals.conference_hash); hi; hi = switch_core_hash_next(&hi)) {
1063 		switch_core_hash_this(hi, &vvar, NULL, &val);
1064 		switch_console_push_match(&my_matches, (const char *) vvar);
1065 	}
1066 	switch_mutex_unlock(conference_globals.hash_mutex);
1067 
1068 	if (my_matches) {
1069 		*matches = my_matches;
1070 		status = SWITCH_STATUS_SUCCESS;
1071 	}
1072 
1073 	return status;
1074 }
1075 
conference_list_pretty(conference_obj_t * conference,switch_stream_handle_t * stream)1076 void conference_list_pretty(conference_obj_t *conference, switch_stream_handle_t *stream)
1077 {
1078 	conference_member_t *member = NULL;
1079 
1080 	switch_assert(conference != NULL);
1081 	switch_assert(stream != NULL);
1082 
1083 	switch_mutex_lock(conference->member_mutex);
1084 
1085 	for (member = conference->members; member; member = member->next) {
1086 		switch_channel_t *channel;
1087 		switch_caller_profile_t *profile;
1088 
1089 		if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
1090 			continue;
1091 		}
1092 		channel = switch_core_session_get_channel(member->session);
1093 		profile = switch_channel_get_caller_profile(channel);
1094 
1095 		stream->write_function(stream, "%u) %s (%s)\n", member->id, profile->caller_id_name, profile->caller_id_number);
1096 	}
1097 
1098 	switch_mutex_unlock(conference->member_mutex);
1099 }
1100 
1101 
conference_list_count_only(conference_obj_t * conference,switch_stream_handle_t * stream)1102 void conference_list_count_only(conference_obj_t *conference, switch_stream_handle_t *stream)
1103 {
1104 	switch_assert(conference != NULL);
1105 	switch_assert(stream != NULL);
1106 
1107 	stream->write_function(stream, "%d", conference->count);
1108 }
1109 
1110 
add_x_tag(switch_xml_t x_member,const char * name,const char * value,int off)1111 switch_xml_t add_x_tag(switch_xml_t x_member, const char *name, const char *value, int off)
1112 {
1113 	switch_size_t dlen;
1114 	char *data;
1115 	switch_xml_t x_tag;
1116 
1117 	if (!value) {
1118 		return 0;
1119 	}
1120 
1121 	dlen = strlen(value) * 3 + 1;
1122 
1123 	x_tag = switch_xml_add_child_d(x_member, name, off);
1124 	switch_assert(x_tag);
1125 
1126 	switch_zmalloc(data, dlen);
1127 
1128 	switch_url_encode(value, data, dlen);
1129 	switch_xml_set_txt_d(x_tag, data);
1130 	free(data);
1131 
1132 	return x_tag;
1133 }
1134 
conference_xlist(conference_obj_t * conference,switch_xml_t x_conference,int off)1135 void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, int off)
1136 {
1137 	conference_member_t *member = NULL;
1138 	switch_xml_t x_member = NULL, x_members = NULL, x_flags, x_variables;
1139 	switch_event_header_t *hp;
1140 	int moff = 0;
1141 	char i[30] = "";
1142 	char *ival = i;
1143 	switch_assert(conference != NULL);
1144 	switch_assert(x_conference != NULL);
1145 
1146 	switch_xml_set_attr_d(x_conference, "name", conference->name);
1147 	switch_snprintf(i, sizeof(i), "%d", conference->count);
1148 	switch_xml_set_attr_d(x_conference, "member-count", ival);
1149 	switch_snprintf(i, sizeof(i), "%d", conference->count_ghosts);
1150 	switch_xml_set_attr_d(x_conference, "ghost-count", ival);
1151 	switch_snprintf(i, sizeof(i), "%u", conference->rate);
1152 	switch_xml_set_attr_d(x_conference, "rate", ival);
1153 	switch_xml_set_attr_d(x_conference, "uuid", conference->uuid_str);
1154 
1155 	if (conference_utils_test_flag(conference, CFLAG_LOCKED)) {
1156 		switch_xml_set_attr_d(x_conference, "locked", "true");
1157 	}
1158 
1159 	if (conference_utils_test_flag(conference, CFLAG_DESTRUCT)) {
1160 		switch_xml_set_attr_d(x_conference, "destruct", "true");
1161 	}
1162 
1163 	if (conference_utils_test_flag(conference, CFLAG_WAIT_MOD)) {
1164 		switch_xml_set_attr_d(x_conference, "wait_mod", "true");
1165 	}
1166 
1167 	if (conference_utils_test_flag(conference, CFLAG_AUDIO_ALWAYS)) {
1168 		switch_xml_set_attr_d(x_conference, "audio_always", "true");
1169 	}
1170 
1171 	if (conference_utils_test_flag(conference, CFLAG_RUNNING)) {
1172 		switch_xml_set_attr_d(x_conference, "running", "true");
1173 	}
1174 
1175 	if (conference_utils_test_flag(conference, CFLAG_ANSWERED)) {
1176 		switch_xml_set_attr_d(x_conference, "answered", "true");
1177 	}
1178 
1179 	if (conference_utils_test_flag(conference, CFLAG_ENFORCE_MIN)) {
1180 		switch_xml_set_attr_d(x_conference, "enforce_min", "true");
1181 	}
1182 
1183 	if (conference_utils_test_flag(conference, CFLAG_BRIDGE_TO)) {
1184 		switch_xml_set_attr_d(x_conference, "bridge_to", "true");
1185 	}
1186 
1187 	if (conference_utils_test_flag(conference, CFLAG_DYNAMIC)) {
1188 		switch_xml_set_attr_d(x_conference, "dynamic", "true");
1189 	}
1190 
1191 	if (conference_utils_test_flag(conference, CFLAG_EXIT_SOUND)) {
1192 		switch_xml_set_attr_d(x_conference, "exit_sound", "true");
1193 	}
1194 
1195 	if (conference_utils_test_flag(conference, CFLAG_ENTER_SOUND)) {
1196 		switch_xml_set_attr_d(x_conference, "enter_sound", "true");
1197 	}
1198 
1199 	if (conference->max_members > 0) {
1200 		switch_snprintf(i, sizeof(i), "%d", conference->max_members);
1201 		switch_xml_set_attr_d(x_conference, "max_members", ival);
1202 	}
1203 
1204 	if (conference->record_count > 0) {
1205 		switch_xml_set_attr_d(x_conference, "recording", "true");
1206 	}
1207 
1208 	if (conference->endconference_grace_time > 0) {
1209 		switch_snprintf(i, sizeof(i), "%u", conference->endconference_grace_time);
1210 		switch_xml_set_attr_d(x_conference, "endconference_grace_time", ival);
1211 	}
1212 
1213 	if (conference_utils_test_flag(conference, CFLAG_VID_FLOOR)) {
1214 		switch_xml_set_attr_d(x_conference, "video_floor_only", "true");
1215 	}
1216 
1217 	if (conference_utils_test_flag(conference, CFLAG_RFC4579)) {
1218 		switch_xml_set_attr_d(x_conference, "video_rfc4579", "true");
1219 	}
1220 
1221 	switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - conference->run_time);
1222 	switch_xml_set_attr_d(x_conference, "run_time", ival);
1223 
1224 	x_variables = switch_xml_add_child_d(x_conference, "variables", 0);
1225 	for (hp = conference->variables->headers; hp; hp = hp->next) {
1226 		switch_xml_t x_variable = switch_xml_add_child_d(x_variables, "variable", 0);
1227 		switch_xml_set_attr_d(x_variable, "name", hp->name);
1228 		switch_xml_set_attr_d(x_variable, "value", hp->value);
1229 	}
1230 
1231 	x_members = switch_xml_add_child_d(x_conference, "members", 0);
1232 	switch_assert(x_members);
1233 
1234 	switch_mutex_lock(conference->member_mutex);
1235 
1236 	for (member = conference->members; member; member = member->next) {
1237 		switch_channel_t *channel;
1238 		switch_caller_profile_t *profile;
1239 		char *uuid;
1240 		//char *name;
1241 		uint32_t count = 0;
1242 		switch_xml_t x_tag;
1243 		int toff = 0;
1244 		char tmp[50] = "";
1245 		switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD);
1246 
1247 		if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
1248 			if (member->rec_path) {
1249 				x_member = switch_xml_add_child_d(x_members, "member", moff++);
1250 				switch_assert(x_member);
1251 				switch_xml_set_attr_d(x_member, "type", "recording_node");
1252 				/* or:
1253 				   x_member = switch_xml_add_child_d(x_members, "recording_node", moff++);
1254 				*/
1255 
1256 				x_tag = switch_xml_add_child_d(x_member, "record_path", count++);
1257 				if (conference_utils_member_test_flag(member, MFLAG_PAUSE_RECORDING)) {
1258 					switch_xml_set_attr_d(x_tag, "status", "paused");
1259 				}
1260 				switch_xml_set_txt_d(x_tag, member->rec_path);
1261 
1262 				x_tag = switch_xml_add_child_d(x_member, "join_time", count++);
1263 				switch_xml_set_attr_d(x_tag, "type", "UNIX-epoch");
1264 				switch_snprintf(i, sizeof(i), "%d", member->rec_time);
1265 				switch_xml_set_txt_d(x_tag, i);
1266 			}
1267 			continue;
1268 		}
1269 
1270 		uuid = switch_core_session_get_uuid(member->session);
1271 		channel = switch_core_session_get_channel(member->session);
1272 		profile = switch_channel_get_caller_profile(channel);
1273 		//name = switch_channel_get_name(channel);
1274 
1275 
1276 		x_member = switch_xml_add_child_d(x_members, "member", moff++);
1277 		switch_assert(x_member);
1278 		switch_xml_set_attr_d(x_member, "type", "caller");
1279 
1280 		switch_snprintf(i, sizeof(i), "%d", member->id);
1281 
1282 		add_x_tag(x_member, "id", i, toff++);
1283 		add_x_tag(x_member, "uuid", uuid, toff++);
1284 		add_x_tag(x_member, "caller_id_name", profile->caller_id_name, toff++);
1285 		add_x_tag(x_member, "caller_id_number", profile->caller_id_number, toff++);
1286 
1287 
1288 		switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - member->join_time);
1289 		add_x_tag(x_member, "join_time", i, toff++);
1290 
1291 		switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - member->last_talking);
1292 		add_x_tag(x_member, "last_talking", member->last_talking ? i : "N/A", toff++);
1293 
1294 		switch_snprintf(i, sizeof(i), "%d", member->energy_level);
1295 		add_x_tag(x_member, "energy", i, toff++);
1296 
1297 		switch_snprintf(i, sizeof(i), "%d", member->volume_in_level);
1298 		add_x_tag(x_member, "volume_in", i, toff++);
1299 
1300 		switch_snprintf(i, sizeof(i), "%d", member->volume_out_level);
1301 		add_x_tag(x_member, "volume_out", i, toff++);
1302 
1303 		x_flags = switch_xml_add_child_d(x_member, "flags", count++);
1304 		switch_assert(x_flags);
1305 
1306 		x_tag = switch_xml_add_child_d(x_flags, "can_hear", count++);
1307 		switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) ? "true" : "false");
1308 
1309 		x_tag = switch_xml_add_child_d(x_flags, "can_see", count++);
1310 		switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SEE)) ? "true" : "false");
1311 
1312 		x_tag = switch_xml_add_child_d(x_flags, "can_speak", count++);
1313 		switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) ? "true" : "false");
1314 
1315 		x_tag = switch_xml_add_child_d(x_flags, "mute_detect", count++);
1316 		switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false");
1317 
1318 		x_tag = switch_xml_add_child_d(x_flags, "talking", count++);
1319 		switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_TALKING)) ? "true" : "false");
1320 
1321 		x_tag = switch_xml_add_child_d(x_flags, "hold", count++);
1322 		switch_xml_set_txt_d(x_tag, hold ? "true" : "false");
1323 
1324 		x_tag = switch_xml_add_child_d(x_flags, "has_video", count++);
1325 		switch_xml_set_txt_d(x_tag, switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO) ? "true" : "false");
1326 
1327 		x_tag = switch_xml_add_child_d(x_flags, "video_bridge", count++);
1328 		switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_VIDEO_BRIDGE) ? "true" : "false");
1329 
1330 		x_tag = switch_xml_add_child_d(x_flags, "has_floor", count++);
1331 		switch_xml_set_txt_d(x_tag, (member->id == member->conference->floor_holder) ? "true" : "false");
1332 
1333 		x_tag = switch_xml_add_child_d(x_flags, "is_moderator", count++);
1334 		switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_MOD) ? "true" : "false");
1335 
1336 		x_tag = switch_xml_add_child_d(x_flags, "end_conference", count++);
1337 		switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_ENDCONF) ? "true" : "false");
1338 
1339 		x_tag = switch_xml_add_child_d(x_flags, "is_ghost", count++);
1340 		switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_GHOST) ? "true" : "false");
1341 
1342 		switch_snprintf(tmp, sizeof(tmp), "%d", member->volume_out_level);
1343 		add_x_tag(x_member, "output-volume", tmp, toff++);
1344 	}
1345 
1346 	switch_mutex_unlock(conference->member_mutex);
1347 }
1348 
conference_jlist(conference_obj_t * conference,cJSON * json_conferences)1349 void conference_jlist(conference_obj_t *conference, cJSON *json_conferences)
1350 {
1351 	conference_member_t *member = NULL;
1352 	static cJSON *json_conference, *json_conference_variables, *json_conference_members, *json_conference_member, *json_conference_member_flags;
1353 	switch_event_header_t *hp;
1354 
1355 	switch_assert(conference != NULL);
1356 	json_conference = cJSON_CreateObject();
1357 	switch_assert(json_conference);
1358 
1359 	cJSON_AddItemToObject(json_conferences, "conference", json_conference);
1360 	cJSON_AddStringToObject(json_conference, "conference_name", conference->name);
1361 	cJSON_AddNumberToObject(json_conference,"member_count", conference->count);
1362 	cJSON_AddNumberToObject(json_conference,"ghost_count", conference->count_ghosts);
1363 	cJSON_AddNumberToObject(json_conference,"rate", conference->rate);
1364 	cJSON_AddNumberToObject(json_conference,"run_time", switch_epoch_time_now(NULL) - conference->run_time);
1365 	cJSON_AddStringToObject(json_conference, "conference_uuid", conference->uuid_str);
1366 	cJSON_AddNumberToObject(json_conference, "canvas_count", conference->canvas_count);
1367 	cJSON_AddNumberToObject(json_conference, "max_bw_in", conference->max_bw_in);
1368 	cJSON_AddNumberToObject(json_conference, "force_bw_in", conference->force_bw_in);
1369 	cJSON_AddNumberToObject(json_conference, "video_floor_packets", conference->video_floor_packets);
1370 
1371 #define ADDBOOL(obj, name, b) cJSON_AddItemToObject(obj, name, (b) ? cJSON_CreateTrue() : cJSON_CreateFalse())
1372 
1373 	ADDBOOL(json_conference, "locked", conference_utils_test_flag(conference, CFLAG_LOCKED));
1374 	ADDBOOL(json_conference, "destruct", conference_utils_test_flag(conference, CFLAG_DESTRUCT));
1375 	ADDBOOL(json_conference, "wait_mod", conference_utils_test_flag(conference, CFLAG_WAIT_MOD));
1376 	ADDBOOL(json_conference, "audio_always", conference_utils_test_flag(conference, CFLAG_AUDIO_ALWAYS));
1377 	ADDBOOL(json_conference, "running", conference_utils_test_flag(conference, CFLAG_RUNNING));
1378 	ADDBOOL(json_conference, "answered", conference_utils_test_flag(conference, CFLAG_ANSWERED));
1379 	ADDBOOL(json_conference, "enforce_min", conference_utils_test_flag(conference, CFLAG_ENFORCE_MIN));
1380 	ADDBOOL(json_conference, "bridge_to", conference_utils_test_flag(conference, CFLAG_BRIDGE_TO));
1381 	ADDBOOL(json_conference, "dynamic", conference_utils_test_flag(conference, CFLAG_DYNAMIC));
1382 	ADDBOOL(json_conference, "exit_sound", conference_utils_test_flag(conference, CFLAG_EXIT_SOUND));
1383 	ADDBOOL(json_conference, "enter_sound", conference_utils_test_flag(conference, CFLAG_ENTER_SOUND));
1384 	ADDBOOL(json_conference, "recording", conference->record_count > 0);
1385 	ADDBOOL(json_conference, "video_bridge", conference_utils_test_flag(conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO));
1386 	ADDBOOL(json_conference, "video_floor_only", conference_utils_test_flag(conference, CFLAG_VID_FLOOR));
1387 	ADDBOOL(json_conference, "video_rfc4579", conference_utils_test_flag(conference, CFLAG_RFC4579));
1388 
1389 	if (conference->max_members > 0) {
1390 		cJSON_AddNumberToObject(json_conference, "max_members", conference->max_members);
1391 	}
1392 
1393 	cJSON_AddItemToObject(json_conference, "variables", json_conference_variables = cJSON_CreateObject());
1394 	for (hp = conference->variables->headers; hp; hp = hp->next) {
1395 		cJSON_AddStringToObject(json_conference_variables, hp->name, hp->value);
1396 	}
1397 
1398 	cJSON_AddItemToObject(json_conference, "members", json_conference_members = cJSON_CreateArray());
1399 	switch_mutex_lock(conference->member_mutex);
1400 	for (member = conference->members; member; member = member->next) {
1401 		switch_channel_t *channel;
1402 		switch_caller_profile_t *profile;
1403 		char *uuid;
1404 		switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD);
1405 
1406 		cJSON_AddItemToObject(json_conference_members, "member", json_conference_member = cJSON_CreateObject());
1407 
1408 		if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
1409 			if (member->rec_path) {
1410 				cJSON_AddStringToObject(json_conference_member, "type", "recording_node");
1411 				cJSON_AddStringToObject(json_conference_member, "record_path", member->rec_path);
1412 				if (conference_utils_member_test_flag(member, MFLAG_PAUSE_RECORDING)) {
1413 					cJSON_AddStringToObject(json_conference_member, "status", "paused");
1414 				}
1415 				cJSON_AddNumberToObject(json_conference_member, "join_time", member->rec_time);
1416 			}
1417 			continue;
1418 		}
1419 
1420 		uuid = switch_core_session_get_uuid(member->session);
1421 		channel = switch_core_session_get_channel(member->session);
1422 		profile = switch_channel_get_caller_profile(channel);
1423 
1424 		cJSON_AddStringToObject(json_conference_member, "type", "caller");
1425 		cJSON_AddNumberToObject(json_conference_member, "id", member->id);
1426 		cJSON_AddItemToObject(json_conference_member, "flags", json_conference_member_flags = cJSON_CreateObject());
1427 		cJSON_AddStringToObject(json_conference_member, "uuid", uuid);
1428 		cJSON_AddStringToObject(json_conference_member, "caller_id_name", profile->caller_id_name);
1429 		cJSON_AddStringToObject(json_conference_member,"caller_id_number", profile->caller_id_number);
1430 		cJSON_AddNumberToObject(json_conference_member, "join_time", switch_epoch_time_now(NULL) - member->join_time);
1431 		cJSON_AddNumberToObject(json_conference_member, "last_talking", member->last_talking ? switch_epoch_time_now(NULL) - member->last_talking : 0);
1432 		cJSON_AddNumberToObject(json_conference_member, "energy", member->energy_level);
1433 		cJSON_AddNumberToObject(json_conference_member, "volume_in", member->volume_in_level);
1434 		cJSON_AddNumberToObject(json_conference_member, "volume_out", member->volume_out_level);
1435 		cJSON_AddNumberToObject(json_conference_member, "output-volume", member->volume_out_level);
1436 		cJSON_AddNumberToObject(json_conference_member, "input-volume", member->volume_in_level);
1437 		ADDBOOL(json_conference_member_flags, "can_hear", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR));
1438 		ADDBOOL(json_conference_member_flags, "can_see", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_SEE));
1439 		ADDBOOL(json_conference_member_flags, "can_speak", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK));
1440 		ADDBOOL(json_conference_member_flags, "hold", hold);
1441 		ADDBOOL(json_conference_member_flags, "mute_detect", conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT));
1442 		ADDBOOL(json_conference_member_flags, "talking", conference_utils_member_test_flag(member, MFLAG_TALKING));
1443 		ADDBOOL(json_conference_member_flags, "has_video", switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO));
1444 		ADDBOOL(json_conference_member_flags, "video_bridge", conference_utils_member_test_flag(member, MFLAG_VIDEO_BRIDGE));
1445 		ADDBOOL(json_conference_member_flags, "has_floor", member->id == member->conference->floor_holder);
1446 		ADDBOOL(json_conference_member_flags, "is_moderator", conference_utils_member_test_flag(member, MFLAG_MOD));
1447 		ADDBOOL(json_conference_member_flags, "end_conference", conference_utils_member_test_flag(member, MFLAG_ENDCONF));
1448 	}
1449 	switch_mutex_unlock(conference->member_mutex);
1450 }
1451 
conference_fnode_toggle_pause(conference_file_node_t * fnode,switch_stream_handle_t * stream)1452 void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_handle_t *stream)
1453 {
1454 	if (fnode) {
1455 		switch_core_file_command(&fnode->fh, SCFC_PAUSE_READ);
1456 		if (switch_test_flag(fnode, NFLAG_PAUSE)) {
1457 			stream->write_function(stream, "+OK Resume\n");
1458 			switch_clear_flag(fnode, NFLAG_PAUSE);
1459 		} else {
1460 			stream->write_function(stream, "+OK Pause\n");
1461 			switch_set_flag(fnode, NFLAG_PAUSE);
1462 		}
1463 	}
1464 }
1465 
conference_fnode_check_status(conference_file_node_t * fnode,switch_stream_handle_t * stream)1466 void conference_fnode_check_status(conference_file_node_t *fnode, switch_stream_handle_t *stream)
1467 {
1468 	if (fnode) {
1469 		stream->write_function(stream, "+OK %"SWITCH_INT64_T_FMT "/%" SWITCH_INT64_T_FMT " %s\n",
1470 			fnode->fh.vpos, fnode->fh.duration, fnode->fh.file_path);
1471 	} else {
1472 		stream->write_function(stream, "-ERR Nothing is playing\n");
1473 	}
1474 }
1475 
conference_fnode_seek(conference_file_node_t * fnode,switch_stream_handle_t * stream,char * arg)1476 void conference_fnode_seek(conference_file_node_t *fnode, switch_stream_handle_t *stream, char *arg)
1477 {
1478 	if (fnode && fnode->type == NODE_TYPE_FILE) {
1479 		unsigned int samps = 0;
1480 		unsigned int pos = 0;
1481 
1482 		if (*arg == '+' || *arg == '-') {
1483 			int step;
1484 			int32_t target;
1485 			if (!(step = atoi(arg))) {
1486 				step = 1000;
1487 			}
1488 
1489 			samps = step * (fnode->fh.native_rate / 1000);
1490 			target = (int32_t)fnode->fh.pos + samps;
1491 
1492 			if (target < 0) {
1493 				target = 0;
1494 			}
1495 
1496 			stream->write_function(stream, "+OK seek to position %d\n", target);
1497 			switch_core_file_seek(&fnode->fh, &pos, target, SEEK_SET);
1498 
1499 		} else {
1500 			samps = switch_atoui(arg) * (fnode->fh.native_rate / 1000);
1501 			stream->write_function(stream, "+OK seek to position %d\n", samps);
1502 			switch_core_file_seek(&fnode->fh, &pos, samps, SEEK_SET);
1503 		}
1504 	}
1505 }
1506 
1507 
1508 /* generate an outbound call from the conference */
conference_outcall(conference_obj_t * conference,char * conference_name,switch_core_session_t * session,char * bridgeto,uint32_t timeout,char * flags,char * cid_name,char * cid_num,char * profile,switch_call_cause_t * cause,switch_call_cause_t * cancel_cause,switch_event_t * var_event,char ** peer_uuid)1509 switch_status_t conference_outcall(conference_obj_t *conference,
1510 								   char *conference_name,
1511 								   switch_core_session_t *session,
1512 								   char *bridgeto, uint32_t timeout,
1513 								   char *flags, char *cid_name,
1514 								   char *cid_num,
1515 								   char *profile,
1516 								   switch_call_cause_t *cause,
1517 								   switch_call_cause_t *cancel_cause,
1518 								   switch_event_t *var_event,
1519 								   char** peer_uuid
1520 								   )
1521 {
1522 	switch_core_session_t *peer_session = NULL;
1523 	switch_channel_t *peer_channel;
1524 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1525 	switch_channel_t *caller_channel = NULL;
1526 	char appdata[512];
1527 	int rdlock = 0;
1528 	switch_bool_t have_flags = SWITCH_FALSE;
1529 	const char *outcall_flags;
1530 	int track = 0;
1531 	const char *call_id = NULL;
1532 
1533 	if (var_event && switch_true(switch_event_get_header(var_event, "conference_track_status"))) {
1534 		track++;
1535 		call_id = switch_event_get_header(var_event, "conference_track_call_id");
1536 	}
1537 
1538 	*cause = SWITCH_CAUSE_NORMAL_CLEARING;
1539 
1540 	if (conference == NULL) {
1541 		char *dialstr = switch_mprintf("{ignore_early_media=true}%s", bridgeto);
1542 		status = switch_ivr_originate(NULL, &peer_session, cause, dialstr, 60, NULL, cid_name, cid_num, NULL, var_event, SOF_NO_LIMITS, NULL, NULL);
1543 		switch_safe_free(dialstr);
1544 
1545 		if (status != SWITCH_STATUS_SUCCESS) {
1546 			return status;
1547 		}
1548 
1549 		peer_channel = switch_core_session_get_channel(peer_session);
1550 		rdlock = 1;
1551 		goto callup;
1552 	}
1553 
1554 	conference_name = conference->name;
1555 
1556 	if (switch_thread_rwlock_tryrdlock(conference->rwlock) != SWITCH_STATUS_SUCCESS) {
1557 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Read Lock Fail\n");
1558 		return SWITCH_STATUS_FALSE;
1559 	}
1560 
1561 	if (session != NULL) {
1562 		caller_channel = switch_core_session_get_channel(session);
1563 	}
1564 
1565 	if (zstr(cid_name)) {
1566 		cid_name = conference->caller_id_name;
1567 	}
1568 
1569 	if (zstr(cid_num)) {
1570 		cid_num = conference->caller_id_number;
1571 	}
1572 
1573 	/* establish an outbound call leg */
1574 
1575 	switch_mutex_lock(conference->mutex);
1576 	conference->originating++;
1577 	switch_mutex_unlock(conference->mutex);
1578 
1579 	if (track) {
1580 		conference_send_notify(conference, "SIP/2.0 100 Trying\r\n", call_id, SWITCH_FALSE);
1581 	}
1582 
1583 
1584 	status = switch_ivr_originate(session, &peer_session, cause, bridgeto, timeout, NULL, cid_name, cid_num, NULL, var_event, SOF_NO_LIMITS, cancel_cause, NULL);
1585 	switch_mutex_lock(conference->mutex);
1586 	conference->originating--;
1587 	switch_mutex_unlock(conference->mutex);
1588 
1589 	if (status != SWITCH_STATUS_SUCCESS) {
1590 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot create outgoing channel, cause: %s\n",
1591 						  switch_channel_cause2str(*cause));
1592 		if (caller_channel) {
1593 			switch_channel_hangup(caller_channel, *cause);
1594 		}
1595 
1596 		if (track) {
1597 			conference_send_notify(conference, "SIP/2.0 481 Failure\r\n", call_id, SWITCH_TRUE);
1598 		}
1599 
1600 		goto done;
1601 	}
1602 
1603 	if (track) {
1604 		conference_send_notify(conference, "SIP/2.0 200 OK\r\n", call_id, SWITCH_TRUE);
1605 	}
1606 
1607 	rdlock = 1;
1608 	peer_channel = switch_core_session_get_channel(peer_session);
1609 
1610 	/* make sure the conference still exists */
1611 	if (!conference_utils_test_flag(conference, CFLAG_RUNNING)) {
1612 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Conference is gone now, nevermind..\n");
1613 		if (caller_channel) {
1614 			switch_channel_hangup(caller_channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
1615 		}
1616 		switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
1617 		goto done;
1618 	}
1619 
1620 	if (caller_channel && switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
1621 		switch_channel_answer(caller_channel);
1622 	}
1623 
1624  callup:
1625 
1626 	/* if the outbound call leg is ready */
1627 	if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
1628 		switch_caller_extension_t *extension = NULL;
1629 
1630 		if(peer_uuid) {
1631 			*peer_uuid = switch_channel_get_uuid(peer_channel);
1632 		}
1633 
1634 		/* build an extension name object */
1635 		if ((extension = switch_caller_extension_new(peer_session, conference_name, conference_name)) == 0) {
1636 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
1637 			status = SWITCH_STATUS_MEMERR;
1638 			goto done;
1639 		}
1640 
1641 		if ((outcall_flags = switch_channel_get_variable(peer_channel, "outcall_flags"))) {
1642 			if (!zstr(outcall_flags)) {
1643 				flags = (char *)outcall_flags;
1644 			}
1645 		}
1646 
1647 		if (flags && strcasecmp(flags, "none")) {
1648 			have_flags = SWITCH_TRUE;
1649 		}
1650 		/* add them to the conference */
1651 
1652 		switch_snprintf(appdata, sizeof(appdata), "%s%s%s%s%s%s", conference_name,
1653 						profile?"@":"", profile?profile:"",
1654 						have_flags?"+flags{":"", have_flags?flags:"", have_flags?"}":"");
1655 		switch_caller_extension_add_application(peer_session, extension, (char *) mod_conference_app_name, appdata);
1656 
1657 		switch_channel_set_caller_extension(peer_channel, extension);
1658 		switch_channel_set_state(peer_channel, CS_EXECUTE);
1659 
1660 	} else {
1661 		switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
1662 		status = SWITCH_STATUS_FALSE;
1663 		goto done;
1664 	}
1665 
1666  done:
1667 	if (conference) {
1668 		switch_thread_rwlock_unlock(conference->rwlock);
1669 	}
1670 	if (rdlock && peer_session) {
1671 		switch_core_session_rwunlock(peer_session);
1672 	}
1673 
1674 	return status;
1675 }
1676 
conference_outcall_run(switch_thread_t * thread,void * obj)1677 void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread, void *obj)
1678 {
1679 	struct bg_call *call = (struct bg_call *) obj;
1680 	char* peer_uuid = NULL;
1681 
1682 	if (call) {
1683 		switch_call_cause_t cause;
1684 		switch_event_t *event;
1685 
1686 
1687 		conference_outcall(call->conference, call->conference_name,
1688 						   call->session, call->bridgeto, call->timeout,
1689 						   call->flags, call->cid_name, call->cid_num, call->profile, &cause, call->cancel_cause, call->var_event, &peer_uuid);
1690 
1691 		if (call->conference && test_eflag(call->conference, EFLAG_BGDIAL_RESULT) &&
1692 			switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
1693 			conference_event_add_data(call->conference, event);
1694 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "bgdial-result");
1695 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Result", switch_channel_cause2str(cause));
1696 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", call->uuid);
1697 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Peer-UUID", peer_uuid);
1698 			switch_event_fire(&event);
1699 		}
1700 
1701 		if (call->var_event) {
1702 			switch_event_destroy(&call->var_event);
1703 		}
1704 
1705 		switch_safe_free(call->bridgeto);
1706 		switch_safe_free(call->flags);
1707 		switch_safe_free(call->cid_name);
1708 		switch_safe_free(call->cid_num);
1709 		switch_safe_free(call->conference_name);
1710 		switch_safe_free(call->uuid);
1711 		switch_safe_free(call->profile);
1712 		if (call->pool) {
1713 			switch_core_destroy_memory_pool(&call->pool);
1714 		}
1715 		switch_safe_free(call);
1716 	}
1717 
1718 	return NULL;
1719 }
1720 
conference_outcall_bg(conference_obj_t * conference,char * conference_name,switch_core_session_t * session,char * bridgeto,uint32_t timeout,const char * flags,const char * cid_name,const char * cid_num,const char * call_uuid,const char * profile,switch_call_cause_t * cancel_cause,switch_event_t ** var_event)1721 switch_status_t conference_outcall_bg(conference_obj_t *conference,
1722 									  char *conference_name,
1723 									  switch_core_session_t *session, char *bridgeto, uint32_t timeout, const char *flags, const char *cid_name,
1724 									  const char *cid_num, const char *call_uuid, const char *profile, switch_call_cause_t *cancel_cause, switch_event_t **var_event)
1725 {
1726 	struct bg_call *call = NULL;
1727 	switch_thread_t *thread;
1728 	switch_threadattr_t *thd_attr = NULL;
1729 	switch_memory_pool_t *pool = NULL;
1730 
1731 	if (!(call = malloc(sizeof(*call))))
1732 		return SWITCH_STATUS_MEMERR;
1733 
1734 	memset(call, 0, sizeof(*call));
1735 	call->conference = conference;
1736 	call->session = session;
1737 	call->timeout = timeout;
1738 	call->cancel_cause = cancel_cause;
1739 
1740 	if (var_event) {
1741 		call->var_event = *var_event;
1742 		var_event = NULL;
1743 	} else {
1744 		switch_event_create_plain(&call->var_event, SWITCH_EVENT_GENERAL);
1745 	}
1746 
1747 	if (conference) {
1748 		pool = conference->pool;
1749 	} else {
1750 		switch_core_new_memory_pool(&pool);
1751 		call->pool = pool;
1752 	}
1753 
1754 	if (bridgeto) {
1755 		call->bridgeto = strdup(bridgeto);
1756 	}
1757 	if (flags) {
1758 		call->flags = strdup(flags);
1759 	}
1760 	if (cid_name) {
1761 		call->cid_name = strdup(cid_name);
1762 	}
1763 	if (cid_num) {
1764 		call->cid_num = strdup(cid_num);
1765 	}
1766 
1767 	if (conference_name) {
1768 		call->conference_name = strdup(conference_name);
1769 	}
1770 
1771 	if (call_uuid) {
1772 		call->uuid = strdup(call_uuid);
1773 		if (call->var_event) {
1774 			switch_event_add_header_string(call->var_event, SWITCH_STACK_BOTTOM, "conference_bgdial_jobid", call->uuid);
1775 		}
1776 	}
1777 
1778 	if (profile) {
1779 		call->profile = strdup(profile);
1780 	}
1781 
1782 	switch_threadattr_create(&thd_attr, pool);
1783 	switch_threadattr_detach_set(thd_attr, 1);
1784 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
1785 	switch_thread_create(&thread, thd_attr, conference_outcall_run, call, pool);
1786 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Launching BG Thread for outcall\n");
1787 
1788 	return SWITCH_STATUS_SUCCESS;
1789 }
1790 
1791 
1792 
SWITCH_STANDARD_APP(conference_auto_function)1793 SWITCH_STANDARD_APP(conference_auto_function)
1794 {
1795 	switch_channel_t *channel = switch_core_session_get_channel(session);
1796 	call_list_t *call_list, *np;
1797 
1798 	call_list = switch_channel_get_private(channel, "_conference_autocall_list_");
1799 
1800 	if (zstr(data)) {
1801 		call_list = NULL;
1802 	} else {
1803 		np = switch_core_session_alloc(session, sizeof(*np));
1804 		switch_assert(np != NULL);
1805 
1806 		np->string = switch_core_session_strdup(session, data);
1807 		if (call_list) {
1808 			np->next = call_list;
1809 			np->iteration = call_list->iteration + 1;
1810 		} else {
1811 			np->iteration = 1;
1812 		}
1813 		call_list = np;
1814 	}
1815 	switch_channel_set_private(channel, "_conference_autocall_list_", call_list);
1816 }
1817 
1818 
conference_text_thread_callback(switch_core_session_t * session,switch_frame_t * frame,void * user_data)1819 switch_status_t conference_text_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
1820 {
1821 	conference_member_t *member = (conference_member_t *)user_data;
1822 	switch_channel_t *channel = switch_core_session_get_channel(session);
1823 	switch_size_t inuse = 0;
1824 
1825 	if (!member) return SWITCH_STATUS_FALSE;
1826 
1827 
1828 	switch_mutex_lock(member->text_mutex);
1829 	if (!member->text_buffer) {
1830 		switch_buffer_create_dynamic(&member->text_buffer, 512, 1024, 0);
1831 		switch_zmalloc(member->text_framedata, 1024);
1832 		member->text_framesize = 1024;
1833 	}
1834 
1835 	if (frame->data && frame->datalen && !(frame->flags & SFF_CNG)) {
1836 		switch_buffer_write(member->text_buffer, frame->data, frame->datalen);
1837 	}
1838 
1839 	inuse = switch_buffer_inuse(member->text_buffer);
1840 
1841 	if (zstr(member->text_framedata) && inuse && (switch_channel_test_flag(channel, CF_TEXT_IDLE) || switch_test_flag(frame, SFF_TEXT_LINE_BREAK))) {
1842 		int bytes = 0;//, ok = 0;
1843 
1844 		if (inuse + 1 > member->text_framesize) {
1845 			void *tmp = malloc(inuse + 1024);
1846 			switch_assert(tmp);
1847 			memcpy(tmp, member->text_framedata, member->text_framesize);
1848 
1849 			switch_assert(tmp);
1850 
1851 			member->text_framesize = inuse + 1024;
1852 
1853 			free(member->text_framedata);
1854 			member->text_framedata = tmp;
1855 
1856 		}
1857 
1858 		bytes = switch_buffer_read(member->text_buffer, member->text_framedata, inuse);
1859 		*(member->text_framedata + bytes) = '\0';
1860 
1861 		/*
1862 		for(p = member->text_framedata; p && *p; p++) {
1863 			if (*p > 32 && *p < 127) {
1864 				ok++;
1865 			}
1866 		}
1867 
1868 		if (!ok) {
1869 			member->text_framedata[0] = '\0';
1870 		}
1871 		*/
1872 	}
1873 
1874 	switch_mutex_unlock(member->text_mutex);
1875 
1876 	return SWITCH_STATUS_SUCCESS;
1877 }
1878 
1879 /* Application interface function that is called from the dialplan to join the channel to a conference */
SWITCH_STANDARD_APP(conference_function)1880 SWITCH_STANDARD_APP(conference_function)
1881 {
1882 	switch_codec_t *read_codec = NULL;
1883 	//uint32_t flags = 0;
1884 	conference_member_t member = { 0 };
1885 	conference_obj_t *conference = NULL;
1886 	switch_channel_t *channel = switch_core_session_get_channel(session);
1887 	char *mydata = NULL;
1888 	char *conference_name = NULL;
1889 	char *bridge_prefix = "bridge:";
1890 	char *flags_prefix = "+flags{";
1891 	char *bridgeto = NULL;
1892 	char *profile_name = NULL;
1893 	switch_xml_t cxml = NULL, cfg = NULL, profiles = NULL;
1894 	const char *flags_str, *v_flags_str;
1895 	const char *cflags_str, *v_cflags_str;
1896 	member_flag_t mflags[MFLAG_MAX] = { 0 };
1897 	switch_core_session_message_t msg = { 0 };
1898 	uint8_t rl = 0, isbr = 0;
1899 	char *dpin = "";
1900 	const char *mdpin = "";
1901 	conference_xml_cfg_t xml_cfg = { 0 };
1902 	switch_event_t *params = NULL;
1903 	int locked = 0;
1904 	int mpin_matched = 0;
1905 	uint32_t *mid;
1906 
1907 	if (!switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_DONE) &&
1908 		(switch_channel_test_flag(channel, CF_RECOVERED) || switch_true(switch_channel_get_variable(channel, "conference_silent_entry")))) {
1909 		switch_channel_set_app_flag_key("conference_silent", channel, CONF_SILENT_REQ);
1910 	}
1911 
1912 	switch_core_session_video_reset(session);
1913 
1914 	switch_channel_set_flag(channel, CF_CONFERENCE);
1915 
1916 	if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
1917 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel pre answer failed.\n");
1918 		goto end;
1919 	}
1920 
1921 	/* Save the original read codec. */
1922 	if (!(read_codec = switch_core_session_get_read_codec(session))) {
1923 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel has no media!\n");
1924 		goto end;
1925 	}
1926 
1927 
1928 	if (zstr(data)) {
1929 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Invalid arguments\n");
1930 		goto end;
1931 	}
1932 
1933 	mydata = switch_core_session_strdup(session, data);
1934 
1935 	if (!mydata) {
1936 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Pool Failure\n");
1937 		goto end;
1938 	}
1939 
1940 	if ((flags_str = strstr(mydata, flags_prefix))) {
1941 		char *p;
1942 		*((char *) flags_str) = '\0';
1943 		flags_str += strlen(flags_prefix);
1944 		if ((p = strchr(flags_str, '}'))) {
1945 			*p = '\0';
1946 		}
1947 	}
1948 
1949 	//if ((v_flags_str = switch_channel_get_variable(channel, "conference_member_flags"))) {
1950 	if ((v_flags_str = conference_utils_combine_flag_var(session, "conference_member_flags"))) {
1951 		if (zstr(flags_str)) {
1952 			flags_str = v_flags_str;
1953 		} else {
1954 			flags_str = switch_core_session_sprintf(session, "%s|%s", flags_str, v_flags_str);
1955 		}
1956 	}
1957 
1958 	cflags_str = flags_str;
1959 
1960 	//if ((v_cflags_str = switch_channel_get_variable(channel, "conference_flags"))) {
1961 	if ((v_cflags_str = conference_utils_combine_flag_var(session, "conference_flags"))) {
1962 		if (zstr(cflags_str)) {
1963 			cflags_str = v_cflags_str;
1964 		} else {
1965 			cflags_str = switch_core_session_sprintf(session, "%s|%s", cflags_str, v_cflags_str);
1966 		}
1967 	}
1968 
1969 	/* is this a bridging conference ? */
1970 	if (!strncasecmp(mydata, bridge_prefix, strlen(bridge_prefix))) {
1971 		isbr = 1;
1972 		mydata += strlen(bridge_prefix);
1973 		if ((bridgeto = strchr(mydata, ':'))) {
1974 			*bridgeto++ = '\0';
1975 		} else {
1976 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Config Error!\n");
1977 			goto done;
1978 		}
1979 	}
1980 
1981 	conference_name = mydata;
1982 
1983 	/* eat all leading spaces on conference name, which can cause problems */
1984 	while (*conference_name == ' ') {
1985 		conference_name++;
1986 	}
1987 
1988 	/* is there a conference pin ? */
1989 	if ((dpin = strchr(conference_name, '+'))) {
1990 		*dpin++ = '\0';
1991 	} else dpin = "";
1992 
1993 	/* is there profile specification ? */
1994 	if ((profile_name = strrchr(conference_name, '@'))) {
1995 		*profile_name++ = '\0';
1996 	} else {
1997 		profile_name = "default";
1998 	}
1999 
2000 #if 0
2001 	if (0) {
2002 		member.dtmf_parser = conference->dtmf_parser;
2003 	} else {
2004 
2005 	}
2006 #endif
2007 
2008 	if (switch_channel_test_flag(channel, CF_RECOVERED)) {
2009 		const char *check = switch_channel_get_variable(channel, "last_transfered_conference");
2010 
2011 		if (!zstr(check)) {
2012 			conference_name = (char *) check;
2013 		}
2014 	}
2015 
2016 	switch_event_create(&params, SWITCH_EVENT_COMMAND);
2017 	switch_assert(params);
2018 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "conference_name", conference_name);
2019 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile_name", profile_name);
2020 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Fetch-Call-UUID", switch_core_session_get_uuid(session));
2021 
2022 	/* Open the config from the xml registry */
2023 	if (!(cxml = switch_xml_open_cfg(mod_conference_cf_name, &cfg, params))) {
2024 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Open of %s failed\n", mod_conference_cf_name);
2025 		goto done;
2026 	}
2027 
2028 	if ((profiles = switch_xml_child(cfg, "profiles"))) {
2029 		xml_cfg.profile = switch_xml_find_child(profiles, "profile", "name", profile_name);
2030 	}
2031 
2032 	/* if this is a bridging call, and it's not a duplicate, build a */
2033 	/* conference object, and skip pin handling, and locked checking */
2034 
2035 	switch_mutex_lock(conference_globals.setup_mutex);
2036 	locked = 1;
2037 
2038 	if (isbr) {
2039 		char *uuid = switch_core_session_get_uuid(session);
2040 
2041 		if (!strcmp(conference_name, "_uuid_")) {
2042 			conference_name = uuid;
2043 		}
2044 
2045 		if ((conference = conference_find(conference_name, NULL))) {
2046 			switch_thread_rwlock_unlock(conference->rwlock);
2047 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Conference %s already exists!\n", conference_name);
2048 			goto done;
2049 		}
2050 
2051 		/* Create the conference object. */
2052 		conference = conference_new(conference_name, xml_cfg, session, NULL);
2053 
2054 		if (!conference) {
2055 			goto done;
2056 		}
2057 
2058 		conference->flags[CFLAG_JSON_STATUS] = 1;
2059 		conference_utils_set_cflags(cflags_str, conference->flags);
2060 
2061 		switch_mutex_unlock(conference_globals.setup_mutex);
2062 		locked = 0;
2063 
2064 		switch_channel_set_variable(channel, "conference_name", conference->name);
2065 		switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str);
2066 
2067 		/* Set the minimum number of members (once you go above it you cannot go below it) */
2068 		conference->min = 2;
2069 
2070 		/* Indicate the conference is dynamic */
2071 		conference_utils_set_flag_locked(conference, CFLAG_DYNAMIC);
2072 
2073 		/* Indicate the conference has a bridgeto party */
2074 		conference_utils_set_flag_locked(conference, CFLAG_BRIDGE_TO);
2075 
2076 		/* Start the conference thread for this conference */
2077 		conference_launch_thread(conference);
2078 
2079 		switch_channel_api_on(channel, "api_on_conference_create");
2080 	} else {
2081 		int enforce_security =  switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND;
2082 		const char *pvar = switch_channel_get_variable(channel, "conference_enforce_security");
2083 
2084 		if (pvar) {
2085 			enforce_security = switch_true(pvar);
2086 		}
2087 
2088 		if ((conference = conference_find(conference_name, NULL))) {
2089 			switch_mutex_unlock(conference_globals.setup_mutex);
2090 			locked = 0;
2091 		}
2092 
2093 		/* if the conference exists, get the pointer to it */
2094 		if (!conference) {
2095 			const char *max_members_str;
2096 			const char *endconference_grace_time_str;
2097 			const char *auto_record_str;
2098 
2099 			/* no conference yet, so check for join-only flag */
2100 			if (flags_str) {
2101 				conference_utils_set_mflags(flags_str, mflags);
2102 
2103 				if (!(mflags[MFLAG_CAN_SPEAK])) {
2104 					if (!(mflags[MFLAG_MUTE_DETECT])) {
2105 						switch_core_media_hard_mute(session, SWITCH_TRUE);
2106 					}
2107 				}
2108 
2109 				if (mflags[MFLAG_JOIN_ONLY]) {
2110 					switch_event_t *event;
2111 					switch_xml_t jos_xml;
2112 					char *val;
2113 					/* send event */
2114 					switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
2115 					switch_channel_event_set_basic_data(channel, event);
2116 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Name", conference_name);
2117 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Profile-Name", profile_name);
2118 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "rejected-join-only");
2119 					switch_event_fire(&event);
2120 					/* check what sound file to play */
2121 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Cannot create a conference since join-only flag is set\n");
2122 					jos_xml = switch_xml_find_child(xml_cfg.profile, "param", "name", "join-only-sound");
2123 					if (jos_xml && (val = (char *) switch_xml_attr_soft(jos_xml, "value"))) {
2124 						switch_channel_answer(channel);
2125 						switch_ivr_play_file(session, NULL, val, NULL);
2126 					}
2127 					if (!switch_false(switch_channel_get_variable(channel, "hangup_after_conference"))) {
2128 						switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
2129 					}
2130 					goto done;
2131 				}
2132 			}
2133 
2134 			/* couldn't find the conference, create one */
2135 			conference = conference_new(conference_name, xml_cfg, session, NULL);
2136 
2137 			if (!conference) {
2138 				goto done;
2139 			}
2140 
2141 			conference->flags[CFLAG_JSON_STATUS] = 1;
2142 			conference_utils_set_cflags(cflags_str, conference->flags);
2143 
2144 			if (locked) {
2145 				switch_mutex_unlock(conference_globals.setup_mutex);
2146 				locked = 0;
2147 			}
2148 
2149 			switch_channel_set_variable(channel, "conference_name", conference->name);
2150 			switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str);
2151 
2152 			/* Set MOH from variable if not set */
2153 			if (zstr(conference->moh_sound)) {
2154 				conference->moh_sound = switch_core_strdup(conference->pool, switch_channel_get_variable(channel, "conference_moh_sound"));
2155 			}
2156 
2157 			/* Set perpetual-sound from variable if not set */
2158 			if (zstr(conference->perpetual_sound)) {
2159 				conference->perpetual_sound = switch_core_strdup(conference->pool, switch_channel_get_variable(channel, "conference_perpetual_sound"));
2160 			}
2161 
2162 			/* Override auto-record profile parameter from variable */
2163 			if (!zstr(auto_record_str = switch_channel_get_variable(channel, "conference_auto_record"))) {
2164 				conference->auto_record = switch_core_strdup(conference->pool, auto_record_str);
2165 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
2166 								  "conference_auto_record set from variable to %s\n", auto_record_str);
2167 			}
2168 
2169 			/* Set the minimum number of members (once you go above it you cannot go below it) */
2170 			conference->min = 1;
2171 
2172 			/* check for variable used to specify override for max_members */
2173 			if (!zstr(max_members_str = switch_channel_get_variable(channel, "conference_max_members"))) {
2174 				uint32_t max_members_val;
2175 				errno = 0;		/* sanity first */
2176 				max_members_val = strtol(max_members_str, NULL, 0);	/* base 0 lets 0x... for hex 0... for octal and base 10 otherwise through */
2177 				if (errno == ERANGE || errno == EINVAL || (int32_t) max_members_val < 0 || max_members_val == 1) {
2178 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2179 									  "conference_max_members variable %s is invalid, not setting a limit\n", max_members_str);
2180 				} else {
2181 					conference->max_members = max_members_val;
2182 				}
2183 			}
2184 
2185 			/* check for variable to override endconference_grace_time profile value */
2186 			if (!zstr(endconference_grace_time_str = switch_channel_get_variable(channel, "conference_endconference_grace_time"))) {
2187 				uint32_t grace_time_val;
2188 				errno = 0;		/* sanity first */
2189 				grace_time_val = strtol(endconference_grace_time_str, NULL, 0);	/* base 0 lets 0x... for hex 0... for octal and base 10 otherwise through */
2190 				if (errno == ERANGE || errno == EINVAL || (int32_t) grace_time_val < 0) {
2191 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2192 									  "conference_endconference_grace_time variable %s is invalid, not setting a time limit\n", endconference_grace_time_str);
2193 				} else {
2194 					conference->endconference_grace_time = grace_time_val;
2195 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
2196 									  "conference endconference_grace_time set from variable to %d\n", grace_time_val);
2197 				}
2198 			}
2199 
2200 			/* Indicate the conference is dynamic */
2201 			conference_utils_set_flag_locked(conference, CFLAG_DYNAMIC);
2202 
2203 			/* acquire a read lock on the thread so it can't leave without us */
2204 			if (switch_thread_rwlock_tryrdlock(conference->rwlock) != SWITCH_STATUS_SUCCESS) {
2205 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Read Lock Fail\n");
2206 				goto done;
2207 			}
2208 
2209 			rl++;
2210 
2211 			/* Start the conference thread for this conference */
2212 			conference_launch_thread(conference);
2213 
2214 			switch_channel_api_on(channel, "api_on_conference_create");
2215 		} else {				/* setup user variable */
2216 			switch_channel_set_variable(channel, "conference_name", conference->name);
2217 			switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str);
2218 			rl++;
2219 		}
2220 
2221 		/* Moderator PIN as a channel variable */
2222 		mdpin = switch_channel_get_variable(channel, "conference_moderator_pin");
2223 
2224 		if (zstr(dpin) && conference->pin) {
2225 			dpin = conference->pin;
2226 		}
2227 		if (zstr(mdpin) && conference->mpin) {
2228 			mdpin = conference->mpin;
2229 		}
2230 
2231 		/* Tell the channel we have a new Session-ID */
2232 		msg.from = __FILE__;
2233 		msg.message_id = SWITCH_MESSAGE_INDICATE_SESSION_ID;
2234 		switch_core_session_receive_message(session, &msg);
2235 
2236 		switch_channel_answer(channel);
2237 
2238 		/* if this is not an outbound call, deal with conference pins */
2239 		if (enforce_security && (!zstr(dpin) || !zstr(mdpin))) {
2240 			char pin_buf[80] = "";
2241 			char *cf_pin_url_param_name = "X-ConfPin=";
2242 			int pin_retries = conference->pin_retries;
2243 			int pin_valid = 0;
2244 			switch_status_t status = SWITCH_STATUS_SUCCESS;
2245 			char *supplied_pin_value;
2246 
2247 			/* look for PIN in channel variable first.  If not present or invalid revert to prompting user */
2248 			supplied_pin_value = switch_core_strdup(conference->pool, switch_channel_get_variable(channel, "supplied_pin"));
2249 			if (!zstr(supplied_pin_value)) {
2250 				char *supplied_pin_value_start;
2251 				int i = 0;
2252 				if ((supplied_pin_value_start = (char *) switch_stristr(cf_pin_url_param_name, supplied_pin_value))) {
2253 					/* pin supplied as a URL parameter, move pointer to start of actual pin value */
2254 					supplied_pin_value = supplied_pin_value_start + strlen(cf_pin_url_param_name);
2255 				}
2256 				while (*supplied_pin_value != 0 && *supplied_pin_value != ';') {
2257 					pin_buf[i++] = *supplied_pin_value++;
2258 				}
2259 
2260 				validate_pin(pin_buf, dpin, mdpin);
2261 				memset(pin_buf, 0, sizeof(pin_buf));
2262 			}
2263 
2264 			if (!conference->pin_sound) {
2265 				conference->pin_sound = switch_core_strdup(conference->pool, "conference/conf-pin.wav");
2266 			}
2267 
2268 			if (!conference->bad_pin_sound) {
2269 				conference->bad_pin_sound = switch_core_strdup(conference->pool, "conference/conf-bad-pin.wav");
2270 			}
2271 
2272 			while (!pin_valid && pin_retries && status == SWITCH_STATUS_SUCCESS) {
2273 				size_t dpin_length = strlen(dpin);
2274 				size_t mdpin_length = mdpin ? strlen(mdpin) : 0;
2275 				int maxpin = dpin_length > mdpin_length ? (int)dpin_length : (int)mdpin_length;
2276 				switch_status_t pstatus = SWITCH_STATUS_FALSE;
2277 
2278 				/* be friendly */
2279 				if (conference->pin_sound) {
2280 					pstatus = conference_file_local_play(conference, session, conference->pin_sound, 20, pin_buf, sizeof(pin_buf));
2281 				} else if (conference->tts_engine && conference->tts_voice) {
2282 					pstatus =
2283 						switch_ivr_speak_text(session, conference->tts_engine, conference->tts_voice, "please enter the conference pin number", NULL);
2284 				} else {
2285 					pstatus = switch_ivr_speak_text(session, "flite", "slt", "please enter the conference pin number", NULL);
2286 				}
2287 
2288 				if (pstatus != SWITCH_STATUS_SUCCESS && pstatus != SWITCH_STATUS_BREAK) {
2289 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot ask the user for a pin, ending call\n");
2290 					switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2291 				}
2292 
2293 				/* wait for them if neccessary */
2294 				if ((int)strlen(pin_buf) < maxpin) {
2295 					char *buf = pin_buf + strlen(pin_buf);
2296 					char term = '\0';
2297 
2298 					status = switch_ivr_collect_digits_count(session,
2299 															 buf,
2300 															 sizeof(pin_buf) - strlen(pin_buf), maxpin - strlen(pin_buf), "#", &term, 10000, 0, 0);
2301 					if (status == SWITCH_STATUS_TIMEOUT) {
2302 						status = SWITCH_STATUS_SUCCESS;
2303 					}
2304 				}
2305 
2306 				if (status == SWITCH_STATUS_SUCCESS) {
2307 					validate_pin(pin_buf, dpin, mdpin);
2308 				}
2309 
2310 				if (!pin_valid) {
2311 					/* zero the collected pin */
2312 					memset(pin_buf, 0, sizeof(pin_buf));
2313 
2314 					/* more friendliness */
2315 					if (conference->bad_pin_sound) {
2316 						conference_file_local_play(conference, session, conference->bad_pin_sound, 20, NULL, 0);
2317 					}
2318 					switch_channel_flush_dtmf(channel);
2319 				}
2320 				pin_retries--;
2321 			}
2322 
2323 			if (!pin_valid) {
2324 				conference_cdr_rejected(conference, channel, CDRR_PIN);
2325 				goto done;
2326 			}
2327 		}
2328 
2329 		if (conference->special_announce && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) {
2330 			conference_file_local_play(conference, session, conference->special_announce, CONF_DEFAULT_LEADIN, NULL, 0);
2331 		}
2332 
2333 		/* don't allow more callers if the conference is locked, unless we invited them */
2334 		if (conference_utils_test_flag(conference, CFLAG_LOCKED) && enforce_security) {
2335 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Conference %s is locked.\n", conference_name);
2336 			conference_cdr_rejected(conference, channel, CDRR_LOCKED);
2337 			if (conference->locked_sound) {
2338 				/* Answer the channel */
2339 				switch_channel_answer(channel);
2340 				conference_file_local_play(conference, session, conference->locked_sound, 20, NULL, 0);
2341 			}
2342 			goto done;
2343 		}
2344 
2345 		/* dont allow more callers than the max_members allows for -- I explicitly didnt allow outbound calls
2346 		 * someone else can add that (see above) if they feel that outbound calls should be able to violate the
2347 		 * max_members limit
2348 		 */
2349 		if ((conference->max_members > 0) && (conference->count >= conference->max_members)) {
2350 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Conference %s is full.\n", conference_name);
2351 			conference_cdr_rejected(conference, channel, CDRR_MAXMEMBERS);
2352 			if (conference->maxmember_sound) {
2353 				/* Answer the channel */
2354 				switch_channel_answer(channel);
2355 				conference_file_local_play(conference, session, conference->maxmember_sound, 20, NULL, 0);
2356 			}
2357 			goto done;
2358 		}
2359 
2360 		if (conference->member_enter_sound && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) {
2361 			conference_file_local_play(conference, session, conference->member_enter_sound, CONF_DEFAULT_LEADIN, NULL, 0);
2362 		}
2363 
2364 	}
2365 
2366 	/* Release the config registry handle */
2367 	switch_xml_free(cxml);
2368 	cxml = NULL;
2369 
2370 	/* if we're using "bridge:" make an outbound call and bridge it in */
2371 	if (!zstr(bridgeto) && strcasecmp(bridgeto, "none")) {
2372 		switch_call_cause_t cause;
2373 		if (conference_outcall(conference, NULL, session, bridgeto, 60, NULL, NULL, NULL, NULL, &cause, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
2374 			goto done;
2375 		}
2376 	} else {
2377 		/* if we're not using "bridge:" set the conference answered flag */
2378 		/* and this isn't an outbound channel, answer the call */
2379 		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND)
2380 			conference_utils_set_flag(conference, CFLAG_ANSWERED);
2381 	}
2382 
2383 	member.session = session;
2384 	member.channel = switch_core_session_get_channel(session);
2385 	member.pool = switch_core_session_get_pool(session);
2386 
2387 	/* Prepare MUTEXS */
2388 	switch_mutex_init(&member.flag_mutex, SWITCH_MUTEX_NESTED, member.pool);
2389 	switch_mutex_init(&member.write_mutex, SWITCH_MUTEX_NESTED, member.pool);
2390 	switch_mutex_init(&member.read_mutex, SWITCH_MUTEX_NESTED, member.pool);
2391 	switch_mutex_init(&member.fnode_mutex, SWITCH_MUTEX_NESTED, member.pool);
2392 	switch_mutex_init(&member.audio_in_mutex, SWITCH_MUTEX_NESTED, member.pool);
2393 	switch_mutex_init(&member.audio_out_mutex, SWITCH_MUTEX_NESTED, member.pool);
2394 	switch_mutex_init(&member.text_mutex, SWITCH_MUTEX_NESTED, member.pool);
2395 	switch_thread_rwlock_create(&member.rwlock, member.pool);
2396 
2397 	if (conference_member_setup_media(&member, conference)) {
2398 		//flags = 0;
2399 		goto done;
2400 	}
2401 
2402 
2403 	if (!(mid = switch_channel_get_private(channel, "__confmid"))) {
2404 		mid = switch_core_session_alloc(session, sizeof(*mid));
2405 		*mid = next_member_id();
2406 		switch_channel_set_private(channel, "__confmid", mid);
2407 	}
2408 
2409 	switch_channel_set_variable_printf(channel, "conference_member_id", "%u", *mid);
2410 	member.id = *mid;
2411 
2412 
2413 	/* Install our Signed Linear codec so we get the audio in that format */
2414 	switch_core_session_set_read_codec(member.session, &member.read_codec);
2415 
2416 
2417 	memcpy(mflags, conference->mflags, sizeof(mflags));
2418 
2419 	conference_utils_set_mflags(flags_str, mflags);
2420 	mflags[MFLAG_RUNNING] = 1;
2421 
2422 	if (!(mflags[MFLAG_CAN_SPEAK])) {
2423 		if (!(mflags[MFLAG_MUTE_DETECT])) {
2424 			switch_core_media_hard_mute(member.session, SWITCH_TRUE);
2425 		}
2426 	}
2427 
2428 	if (!mflags[MFLAG_CAN_BE_SEEN]) {
2429 		switch_channel_set_flag(channel, CF_VIDEO_PAUSE_READ);
2430 	}
2431 
2432 	if (mpin_matched) {
2433 		mflags[MFLAG_MOD] = 1;
2434 	}
2435 
2436 	conference_utils_merge_mflags(member.flags, mflags);
2437 
2438 
2439 	if (mflags[MFLAG_MINTWO]) {
2440 		conference->min = 2;
2441 	}
2442 
2443 
2444 	if (conference->conference_video_mode == CONF_VIDEO_MODE_MUX) {
2445 		switch_queue_create(&member.video_queue, 200, member.pool);
2446 		switch_frame_buffer_create(&member.fb, 500);
2447 	}
2448 
2449 	/* Add the caller to the conference */
2450 	if (conference_member_add(conference, &member) != SWITCH_STATUS_SUCCESS) {
2451 		switch_core_codec_destroy(&member.read_codec);
2452 		goto done;
2453 	}
2454 
2455 	if (conference->conference_video_mode == CONF_VIDEO_MODE_MUX) {
2456 		conference_video_launch_muxing_write_thread(&member);
2457 		conference_video_launch_layer_thread(&member);
2458 	}
2459 
2460 	msg.from = __FILE__;
2461 
2462 	/* Tell the channel we are going to be in a bridge */
2463 	msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
2464 	switch_core_session_receive_message(session, &msg);
2465 
2466 	if (conference_utils_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) {
2467 		switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2468 		switch_core_media_gen_key_frame(session);
2469 	}
2470 
2471 	/* Chime in the core video thread */
2472 	switch_core_session_set_video_read_callback(session, conference_video_thread_callback, (void *)&member);
2473 	switch_core_session_set_text_read_callback(session, conference_text_thread_callback, (void *)&member);
2474 
2475 	if (switch_channel_test_flag(channel, CF_VIDEO_ONLY) || !switch_channel_test_flag(channel, CF_AUDIO)) {
2476 		while(conference_utils_member_test_flag((&member), MFLAG_RUNNING) && switch_channel_ready(channel)) {
2477 			switch_frame_t *read_frame;
2478 			if (switch_channel_test_flag(channel, CF_AUDIO)) {
2479 				switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
2480 			}
2481 			switch_yield(100000);
2482 		}
2483 	} else {
2484 
2485 		/* Run the conference loop */
2486 		do {
2487 			conference_loop_output(&member);
2488 		} while (member.loop_loop);
2489 	}
2490 
2491 	switch_core_session_video_reset(session);
2492 	switch_channel_clear_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2493 
2494 	switch_core_session_set_video_read_callback(session, NULL, NULL);
2495 	switch_core_session_set_text_read_callback(session, NULL, NULL);
2496 
2497 	switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
2498 
2499 	/* Tell the channel we are no longer going to be in a bridge */
2500 	msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE;
2501 	switch_core_session_receive_message(session, &msg);
2502 
2503 	conference_utils_member_clear_flag(&member, MFLAG_RUNNING);
2504 
2505 	if (member.video_muxing_write_thread) {
2506 		switch_status_t st = SWITCH_STATUS_SUCCESS;
2507 		switch_frame_buffer_push(member.fb, NULL);
2508 		switch_thread_join(&st, member.video_muxing_write_thread);
2509 		member.video_muxing_write_thread = NULL;
2510 	}
2511 
2512 	if (member.video_layer_thread) {
2513 		switch_status_t st = SWITCH_STATUS_SUCCESS;
2514 
2515 		while(member.layer_thread_running) {
2516 			conference_video_wake_layer_thread(&member);
2517 			switch_yield(10000);
2518 		}
2519 
2520 		switch_thread_join(&st, member.video_layer_thread);
2521 		member.video_layer_thread = NULL;
2522 	}
2523 
2524 	/* Remove the caller from the conference */
2525 	conference_member_del(member.conference, &member);
2526 
2527 	/* Put the original codec back */
2528 	switch_core_session_set_read_codec(member.session, NULL);
2529 
2530 	/* Clean Up. */
2531 
2532  done:
2533 
2534 	if (locked) {
2535 		switch_mutex_unlock(conference_globals.setup_mutex);
2536 	}
2537 
2538 	if (member.read_resampler) {
2539 		switch_resample_destroy(&member.read_resampler);
2540 	}
2541 
2542 	switch_event_destroy(&params);
2543 	switch_buffer_destroy(&member.resample_buffer);
2544 	switch_buffer_destroy(&member.audio_buffer);
2545 	switch_buffer_destroy(&member.mux_buffer);
2546 
2547 	if (member.fb) {
2548 		switch_frame_buffer_destroy(&member.fb);
2549 	}
2550 
2551 	if (conference) {
2552 		switch_mutex_lock(conference->mutex);
2553 		if (conference_utils_test_flag(conference, CFLAG_DYNAMIC) && conference->count == 0 && conference->count_ghosts == 0) {
2554 			conference_utils_set_flag_locked(conference, CFLAG_DESTRUCT);
2555 		}
2556 		switch_mutex_unlock(conference->mutex);
2557 	}
2558 
2559 	/* Release the config registry handle */
2560 	if (cxml) {
2561 		switch_xml_free(cxml);
2562 	}
2563 
2564 	if (conference && conference_utils_member_test_flag(&member, MFLAG_KICKED) && conference->kicked_sound) {
2565 		char *toplay = NULL;
2566 		char *dfile = NULL;
2567 		char *expanded = NULL;
2568 		char *src = member.kicked_sound ? member.kicked_sound : conference->kicked_sound;
2569 
2570 
2571 		if (!strncasecmp(src, "say:", 4)) {
2572 			if (conference->tts_engine && conference->tts_voice) {
2573 				switch_ivr_speak_text(session, conference->tts_engine, conference->tts_voice, src + 4, NULL);
2574 			}
2575 		} else {
2576 			if ((expanded = switch_channel_expand_variables(switch_core_session_get_channel(session), src)) != src) {
2577 				toplay = expanded;
2578 			} else {
2579 				expanded = NULL;
2580 				toplay = src;
2581 			}
2582 
2583 			if (!switch_is_file_path(toplay) && conference->sound_prefix) {
2584 				dfile = switch_mprintf("%s%s%s", conference->sound_prefix, SWITCH_PATH_SEPARATOR, toplay);
2585 				switch_assert(dfile);
2586 				toplay = dfile;
2587 			}
2588 
2589 			switch_ivr_play_file(session, NULL, toplay, NULL);
2590 			switch_safe_free(dfile);
2591 			switch_safe_free(expanded);
2592 		}
2593 	}
2594 
2595 	switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
2596 
2597 	/* release the readlock */
2598 	if (rl) {
2599 		switch_thread_rwlock_unlock(conference->rwlock);
2600 	}
2601 
2602 	switch_channel_set_variable(channel, "last_transfered_conference", NULL);
2603 
2604  end:
2605 
2606 	switch_channel_clear_flag(channel, CF_CONFERENCE);
2607 
2608 	switch_core_session_video_reset(session);
2609 }
2610 
2611 
2612 
2613 /* Create a thread for the conference and launch it */
conference_launch_thread(conference_obj_t * conference)2614 void conference_launch_thread(conference_obj_t *conference)
2615 {
2616 	switch_thread_t *thread;
2617 	switch_threadattr_t *thd_attr = NULL;
2618 
2619 	conference_utils_set_flag_locked(conference, CFLAG_RUNNING);
2620 	switch_threadattr_create(&thd_attr, conference->pool);
2621 	switch_threadattr_detach_set(thd_attr, 1);
2622 	switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
2623 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2624 	switch_mutex_lock(conference_globals.hash_mutex);
2625 	switch_mutex_unlock(conference_globals.hash_mutex);
2626 	switch_thread_create(&thread, thd_attr, conference_thread_run, conference, conference->pool);
2627 }
2628 
conference_find(char * name,char * domain)2629 conference_obj_t *conference_find(char *name, char *domain)
2630 {
2631 	conference_obj_t *conference;
2632 
2633 	switch_mutex_lock(conference_globals.hash_mutex);
2634 	if ((conference = switch_core_hash_find(conference_globals.conference_hash, name))) {
2635 		if (conference_utils_test_flag(conference, CFLAG_DESTRUCT)) {
2636 			switch_core_hash_delete(conference_globals.conference_hash, conference->name);
2637 			conference_utils_clear_flag(conference, CFLAG_INHASH);
2638 			conference = NULL;
2639 		} else if (!zstr(domain) && conference->domain && strcasecmp(domain, conference->domain)) {
2640 			conference = NULL;
2641 		}
2642 	}
2643 	if (conference) {
2644 		if (switch_thread_rwlock_tryrdlock(conference->rwlock) != SWITCH_STATUS_SUCCESS) {
2645 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Read Lock Fail\n");
2646 			conference = NULL;
2647 		}
2648 	}
2649 	switch_mutex_unlock(conference_globals.hash_mutex);
2650 
2651 	return conference;
2652 }
2653 
conference_set_variable(conference_obj_t * conference,const char * var,const char * val)2654 void conference_set_variable(conference_obj_t *conference, const char *var, const char *val)
2655 {
2656 	switch_mutex_lock(conference->flag_mutex);
2657 	switch_event_add_header_string(conference->variables, SWITCH_STACK_BOTTOM, var, val);
2658 	switch_mutex_unlock(conference->flag_mutex);
2659 }
2660 
conference_get_variable(conference_obj_t * conference,const char * var)2661 const char *conference_get_variable(conference_obj_t *conference, const char *var)
2662 {
2663 	const char *val;
2664 
2665 	switch_mutex_lock(conference->flag_mutex);
2666 	val = switch_event_get_header(conference->variables, var);
2667 	switch_mutex_unlock(conference->flag_mutex);
2668 
2669 	if (val) {
2670 		return switch_core_strdup(conference->pool, val);
2671 	}
2672 
2673 	return NULL;
2674 }
2675 
2676 /* create a new conferene with a specific profile */
conference_new(char * name,conference_xml_cfg_t cfg,switch_core_session_t * session,switch_memory_pool_t * pool)2677 conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_core_session_t *session, switch_memory_pool_t *pool)
2678 {
2679 	conference_obj_t *conference;
2680 	switch_xml_t xml_kvp;
2681 	char *timer_name = NULL;
2682 	char *domain = NULL;
2683 	char *desc = NULL;
2684 	char *name_domain = NULL;
2685 	char *tts_engine = NULL;
2686 	char *tts_voice = NULL;
2687 	char *member_enter_sound = NULL;
2688 	char *enter_sound = NULL;
2689 	char *sound_prefix = NULL;
2690 	char *exit_sound = NULL;
2691 	char *alone_sound = NULL;
2692 	char *muted_sound = NULL;
2693 	char *mute_detect_sound = NULL;
2694 	char *unmuted_sound = NULL;
2695 	char *locked_sound = NULL;
2696 	char *is_locked_sound = NULL;
2697 	char *is_unlocked_sound = NULL;
2698 	char *kicked_sound = NULL;
2699 	char *deaf_sound = NULL;
2700 	char *undeaf_sound = NULL;
2701 	char *blind_sound = NULL;
2702 	char *unblind_sound = NULL;
2703 	char *pin = NULL;
2704 	char *mpin = NULL;
2705 	char *pin_sound = NULL;
2706 	char *bad_pin_sound = NULL;
2707 	char *energy_level = NULL;
2708 	char *auto_energy_level = NULL;
2709 	char *max_energy_level = NULL;
2710 	char *max_energy_hit_trigger = NULL;
2711 	char *max_energy_level_mute_ms = NULL;
2712 	char *auto_energy_sec = NULL;
2713 	char *agc_level = NULL;
2714 	char *agc_low_energy_level = NULL;
2715 	char *agc_margin = NULL;
2716 	char *agc_change_factor = NULL;
2717 	char *agc_period_len = NULL;
2718 	char *caller_id_name = NULL;
2719 	char *caller_id_number = NULL;
2720 	char *caller_controls = NULL;
2721 	char *moderator_controls = NULL;
2722 	char *member_flags = NULL;
2723 	char *conference_flags = NULL;
2724 	char *perpetual_sound = NULL;
2725 	char *moh_sound = NULL;
2726 	char *outcall_templ = NULL;
2727 	char *video_layout_conf = NULL;
2728 	char *video_layout_name = NULL;
2729 	char *video_layout_group = NULL;
2730 	char *video_canvas_size = NULL;
2731 	char *video_canvas_bgcolor = NULL;
2732 	char *video_border_color = NULL;
2733 	int video_border_size = 0;
2734 	char *video_super_canvas_bgcolor = NULL;
2735 	char *video_letterbox_bgcolor = NULL;
2736 	char *video_codec_bandwidth = NULL;
2737 	char *no_video_avatar = NULL;
2738 	char *video_mute_banner = NULL;
2739 	conference_video_mode_t conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH;
2740 	int conference_video_quality = 1;
2741 	int auto_kps_debounce = 5000;
2742 	float fps = 30.0f;
2743 	uint32_t max_members = 0;
2744 	uint32_t announce_count = 0;
2745 	char *maxmember_sound = NULL;
2746 	uint32_t rate = 8000, interval = 20;
2747 	uint32_t channels = 1;
2748 	int broadcast_chat_messages = 1;
2749 	int comfort_noise_level = 0;
2750 	int pin_retries = 3;
2751 	int ivr_dtmf_timeout = 500;
2752 	int ivr_input_timeout = 0;
2753 	int video_canvas_count = 0;
2754 	int video_super_canvas_label_layers = 0;
2755 	int video_super_canvas_show_all_layers = 0;
2756 	char *suppress_events = NULL;
2757 	char *verbose_events = NULL;
2758 	char *auto_record = NULL;
2759 	char *recording_metadata = NULL;
2760 	int min_recording_participants = 1;
2761 	char *conference_log_dir = NULL;
2762 	char *cdr_event_mode = NULL;
2763 	char *terminate_on_silence = NULL;
2764 	char *endconference_grace_time = NULL;
2765 	char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1];
2766 	switch_uuid_t uuid;
2767 	switch_codec_implementation_t read_impl = { 0 };
2768 	switch_channel_t *channel = NULL;
2769 	const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL, *force_canvas_size = NULL;
2770 	uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0, video_auto_floor_msec = 0;
2771 	switch_event_t *event;
2772 
2773 	int scale_h264_canvas_width = 0;
2774 	int scale_h264_canvas_height = 0;
2775 	int scale_h264_canvas_fps_divisor = 0;
2776 	char *scale_h264_canvas_bandwidth = NULL;
2777 	char *video_codec_config_profile_name = NULL;
2778 	int tmp;
2779 
2780 	/* Validate the conference name */
2781 	if (zstr(name)) {
2782 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Record! no name.\n");
2783 		return NULL;
2784 	}
2785 
2786 	if (session) {
2787 		uint32_t tmp;
2788 
2789 		switch_core_session_get_read_impl(session, &read_impl);
2790 		channel = switch_core_session_get_channel(session);
2791 
2792 		presence_id = switch_channel_get_variable(channel, "presence_id");
2793 
2794 		if ((force_rate = switch_channel_get_variable(channel, "conference_force_rate"))) {
2795 			if (!strcasecmp(force_rate, "auto")) {
2796 				force_rate_i = rate = read_impl.actual_samples_per_second;
2797 			} else {
2798 				tmp = atoi(force_rate);
2799 
2800 				if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 44100 || tmp == 48000) {
2801 					force_rate_i = rate = tmp;
2802 				}
2803 			}
2804 		}
2805 
2806 		if ((force_channels = switch_channel_get_variable(channel, "conference_force_channels"))) {
2807 			if (!strcasecmp(force_channels, "auto")) {
2808 				force_channels_i = channels = read_impl.number_of_channels;
2809 			} else {
2810 				tmp = atoi(force_channels);
2811 
2812 				if (tmp == 1 || tmp == 2) {
2813 					force_channels_i = channels = tmp;
2814 				}
2815 			}
2816 		}
2817 
2818 		if ((force_interval = switch_channel_get_variable(channel, "conference_force_interval"))) {
2819 			if (!strcasecmp(force_interval, "auto")) {
2820 				force_interval_i = interval = read_impl.microseconds_per_packet / 1000;
2821 			} else {
2822 				tmp = atoi(force_interval);
2823 
2824 				if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
2825 					force_interval_i = interval = tmp;
2826 				}
2827 			}
2828 		}
2829 
2830 
2831 		if ((force_canvas_size = switch_channel_get_variable(channel, "conference_force_canvas_size"))) {
2832 			video_canvas_size = (char *)force_canvas_size;
2833 		}
2834 	}
2835 
2836 	switch_mutex_lock(conference_globals.hash_mutex);
2837 
2838 	/* parse the profile tree for param values */
2839 	if (cfg.profile)
2840 		for (xml_kvp = switch_xml_child(cfg.profile, "param"); xml_kvp; xml_kvp = xml_kvp->next) {
2841 			char *var = (char *) switch_xml_attr_soft(xml_kvp, "name");
2842 			char *val = (char *) switch_xml_attr_soft(xml_kvp, "value");
2843 			char buf[128] = "";
2844 			char *p;
2845 
2846 			if (strchr(var, '_')) {
2847 				switch_copy_string(buf, var, sizeof(buf));
2848 				for (p = buf; *p; p++) {
2849 					if (*p == '_') {
2850 						*p = '-';
2851 					}
2852 				}
2853 				var = buf;
2854 			}
2855 
2856 			if (!force_rate_i && !strcasecmp(var, "rate") && !zstr(val)) {
2857 				uint32_t tmp = atoi(val);
2858 				if (session && tmp == 0) {
2859 					if (!strcasecmp(val, "auto")) {
2860 						rate = read_impl.actual_samples_per_second;
2861 					}
2862 				} else {
2863 					if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 44100 || tmp == 48000) {
2864 						rate = tmp;
2865 					}
2866 				}
2867 			} else if (!force_channels_i && !strcasecmp(var, "channels") && !zstr(val)) {
2868 				uint32_t tmp = atoi(val);
2869 				if (session && tmp == 0) {
2870 					if (!strcasecmp(val, "auto")) {
2871 						channels = read_impl.number_of_channels;
2872 					}
2873 				} else {
2874 					if (tmp == 1 || tmp == 2) {
2875 						channels = tmp;
2876 					}
2877 				}
2878 			} else if (!strcasecmp(var, "domain") && !zstr(val)) {
2879 				domain = val;
2880 			} else if (!strcasecmp(var, "description") && !zstr(val)) {
2881 				desc = val;
2882 			} else if (!force_interval_i && !strcasecmp(var, "interval") && !zstr(val)) {
2883 				uint32_t tmp = atoi(val);
2884 
2885 				if (session && tmp == 0) {
2886 					if (!strcasecmp(val, "auto")) {
2887 						interval = read_impl.microseconds_per_packet / 1000;
2888 					}
2889 				} else {
2890 					if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
2891 						interval = tmp;
2892 					} else {
2893 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2894 										  "Interval must be multipe of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
2895 					}
2896 				}
2897 			} else if (!strcasecmp(var, "timer-name") && !zstr(val)) {
2898 				timer_name = val;
2899 			} else if (!strcasecmp(var, "tts-engine") && !zstr(val)) {
2900 				tts_engine = val;
2901 			} else if (!strcasecmp(var, "tts-voice") && !zstr(val)) {
2902 				tts_voice = val;
2903 			} else if (!strcasecmp(var, "member-enter-sound") && !zstr(val)) {
2904 				member_enter_sound = val;
2905 			} else if (!strcasecmp(var, "enter-sound") && !zstr(val)) {
2906 				enter_sound = val;
2907 			} else if (!strcasecmp(var, "outcall-templ") && !zstr(val)) {
2908 				outcall_templ = val;
2909 			} else if (!strcasecmp(var, "video-layout-name") && !zstr(val)) {
2910 				video_layout_name = val;
2911 			} else if (!strcasecmp(var, "video-layout-conf") && !zstr(val)) {
2912 				video_layout_conf = val;
2913 			} else if (!strcasecmp(var, "video-canvas-count") && !zstr(val)) {
2914 				video_canvas_count = atoi(val);
2915 			} else if (!strcasecmp(var, "video-super-canvas-label-layers") && !zstr(val)) {
2916 				video_super_canvas_label_layers = atoi(val);
2917 			} else if (!strcasecmp(var, "video-super-canvas-show-all-layers") && !zstr(val)) {
2918 				video_super_canvas_show_all_layers = atoi(val);
2919 			} else if (!strcasecmp(var, "video-canvas-bgcolor") && !zstr(val)) {
2920 				video_canvas_bgcolor = val;
2921 			} else if (!strcasecmp(var, "video-border-color") && !zstr(val)) {
2922 				video_border_color = val;
2923 			} else if (!strcasecmp(var, "video-border-size") && !zstr(val)) {
2924 				video_border_size = atoi(val);
2925 			} else if (!strcasecmp(var, "video-super-canvas-bgcolor") && !zstr(val)) {
2926 				video_super_canvas_bgcolor= val;
2927 			} else if (!strcasecmp(var, "video-letterbox-bgcolor") && !zstr(val)) {
2928 				video_letterbox_bgcolor= val;
2929 			} else if (!video_canvas_size && !strcasecmp(var, "video-canvas-size") && !zstr(val)) {
2930 				video_canvas_size = val;
2931 			} else if (!strcasecmp(var, "video-fps") && !zstr(val)) {
2932 				fps = (float)atof(val);
2933 			} else if (!strcasecmp(var, "video-codec-bandwidth") && !zstr(val)) {
2934 				video_codec_bandwidth = val;
2935 			} else if (!strcasecmp(var, "video-no-video-avatar") && !zstr(val)) {
2936 				no_video_avatar = val;
2937 			} else if (!strcasecmp(var, "video-mute-banner") && !zstr(val)) {
2938 				video_mute_banner = val;
2939 			} else if (!strcasecmp(var, "exit-sound") && !zstr(val)) {
2940 				exit_sound = val;
2941 			} else if (!strcasecmp(var, "alone-sound") && !zstr(val)) {
2942 				alone_sound = val;
2943 			} else if (!strcasecmp(var, "perpetual-sound") && !zstr(val)) {
2944 				perpetual_sound = val;
2945 			} else if (!strcasecmp(var, "moh-sound") && !zstr(val)) {
2946 				moh_sound = val;
2947 			} else if (!strcasecmp(var, "muted-sound") && !zstr(val)) {
2948 				muted_sound = val;
2949 			} else if (!strcasecmp(var, "mute-detect-sound") && !zstr(val)) {
2950 				mute_detect_sound = val;
2951 			} else if (!strcasecmp(var, "unmuted-sound") && !zstr(val)) {
2952 				unmuted_sound = val;
2953 			} else if (!strcasecmp(var, "locked-sound") && !zstr(val)) {
2954 				locked_sound = val;
2955 			} else if (!strcasecmp(var, "is-locked-sound") && !zstr(val)) {
2956 				is_locked_sound = val;
2957 			} else if (!strcasecmp(var, "is-unlocked-sound") && !zstr(val)) {
2958 				is_unlocked_sound = val;
2959 			} else if (!strcasecmp(var, "deaf-sound") && !zstr(val)) {
2960 				deaf_sound = val;
2961 			} else if (!strcasecmp(var, "undeaf-sound") && !zstr(val)) {
2962 				undeaf_sound = val;
2963 			} else if (!strcasecmp(var, "blind-sound") && !zstr(val)) {
2964 				blind_sound = val;
2965 			} else if (!strcasecmp(var, "unblind-sound") && !zstr(val)) {
2966 				unblind_sound = val;
2967 			} else if (!strcasecmp(var, "member-flags") && !zstr(val)) {
2968 				member_flags = val;
2969 			} else if (!strcasecmp(var, "conference-flags") && !zstr(val)) {
2970 				conference_flags = val;
2971 			} else if (!strcasecmp(var, "cdr-log-dir") && !zstr(val)) {
2972 				conference_log_dir = val;
2973 			} else if (!strcasecmp(var, "cdr-event-mode") && !zstr(val)) {
2974 				cdr_event_mode = val;
2975 			} else if (!strcasecmp(var, "kicked-sound") && !zstr(val)) {
2976 				kicked_sound = val;
2977 			} else if (!strcasecmp(var, "pin") && !zstr(val)) {
2978 				pin = val;
2979 			} else if (!strcasecmp(var, "moderator-pin") && !zstr(val)) {
2980 				mpin = val;
2981 			} else if (!strcasecmp(var, "pin-retries") && !zstr(val)) {
2982 				int tmp = atoi(val);
2983 				if (tmp >= 0) {
2984 					pin_retries = tmp;
2985 				}
2986 			} else if (!strcasecmp(var, "pin-sound") && !zstr(val)) {
2987 				pin_sound = val;
2988 			} else if (!strcasecmp(var, "bad-pin-sound") && !zstr(val)) {
2989 				bad_pin_sound = val;
2990 			} else if (!strcasecmp(var, "energy-level") && !zstr(val)) {
2991 				energy_level = val;
2992 			} else if (!strcasecmp(var, "auto-energy-level") && !zstr(val)) {
2993 				auto_energy_level = val;
2994 			} else if (!strcasecmp(var, "max-energy-level") && !zstr(val)) {
2995 				max_energy_level = val;
2996 			} else if (!strcasecmp(var, "max-energy-hit-trigger") && !zstr(val)) {
2997 				max_energy_hit_trigger = val;
2998 			} else if (!strcasecmp(var, "max-energy-level-mute-ms") && !zstr(val)) {
2999 				max_energy_level_mute_ms = val;
3000 			} else if (!strcasecmp(var, "auto-energy-seconds") && !zstr(val)) {
3001 				auto_energy_sec = val;
3002 			} else if (!strcasecmp(var, "auto-gain-level") && !zstr(val)) {
3003 				agc_level = val;
3004 			} else if (!strcasecmp(var, "auto-gain-low-energy-level") && !zstr(val)) {
3005 				agc_low_energy_level = val;
3006 			} else if (!strcasecmp(var, "auto-gain-margin") && !zstr(val)) {
3007 				agc_margin = val;
3008 			} else if (!strcasecmp(var, "auto-gain-change-factor") && !zstr(val)) {
3009 				agc_change_factor = val;
3010 			} else if (!strcasecmp(var, "auto-gain-period-len") && !zstr(val)) {
3011 				agc_period_len = val;
3012 			} else if (!strcasecmp(var, "caller-id-name") && !zstr(val)) {
3013 				caller_id_name = val;
3014 			} else if (!strcasecmp(var, "caller-id-number") && !zstr(val)) {
3015 				caller_id_number = val;
3016 			} else if (!strcasecmp(var, "caller-controls") && !zstr(val)) {
3017 				caller_controls = val;
3018 			} else if (!strcasecmp(var, "ivr-dtmf-timeout") && !zstr(val)) {
3019 				ivr_dtmf_timeout = atoi(val);
3020 				if (ivr_dtmf_timeout < 500) {
3021 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "not very smart value for ivr-dtmf-timeout found (%d), defaulting to 500ms\n", ivr_dtmf_timeout);
3022 					ivr_dtmf_timeout = 500;
3023 				}
3024 			} else if (!strcasecmp(var, "ivr-input-timeout") && !zstr(val)) {
3025 				ivr_input_timeout = atoi(val);
3026 				if (ivr_input_timeout != 0 && ivr_input_timeout < 500) {
3027 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "not very smart value for ivr-input-timeout found (%d), defaulting to 500ms\n", ivr_input_timeout);
3028 					ivr_input_timeout = 5000;
3029 				}
3030 			} else if (!strcasecmp(var, "moderator-controls") && !zstr(val)) {
3031 				moderator_controls = val;
3032 			} else if (!strcasecmp(var, "broadcast-chat-messages") && !zstr(val)) {
3033 				broadcast_chat_messages = switch_true(val);
3034 			} else if (!strcasecmp(var, "comfort-noise") && !zstr(val)) {
3035 				int tmp;
3036 				tmp = atoi(val);
3037 				if (tmp > 1 && tmp < 10000) {
3038 					comfort_noise_level = tmp;
3039 				} else if (switch_true(val)) {
3040 					comfort_noise_level = 1400;
3041 				}
3042 			} else if (!strcasecmp(var, "video-auto-floor-msec") && !zstr(val)) {
3043 				int tmp;
3044 				tmp = atoi(val);
3045 
3046 				if (tmp > 0) {
3047 					video_auto_floor_msec = tmp;
3048 				}
3049 			} else if (!strcasecmp(var, "sound-prefix") && !zstr(val)) {
3050 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "override sound-prefix with: %s\n", val);
3051 				sound_prefix = val;
3052 			} else if (!strcasecmp(var, "max-members") && !zstr(val)) {
3053 				errno = 0;		/* sanity first */
3054 				max_members = strtol(val, NULL, 0);	/* base 0 lets 0x... for hex 0... for octal and base 10 otherwise through */
3055 				if (errno == ERANGE || errno == EINVAL || (int32_t) max_members < 0 || max_members == 1) {
3056 					/* a negative wont work well, and its foolish to have a conference limited to 1 person unless the outbound
3057 					 * stuff is added, see comments above
3058 					 */
3059 					max_members = 0;	/* set to 0 to disable max counts */
3060 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "max-members %s is invalid, not setting a limit\n", val);
3061 				}
3062 			} else if (!strcasecmp(var, "max-members-sound") && !zstr(val)) {
3063 				maxmember_sound = val;
3064 			} else if (!strcasecmp(var, "announce-count") && !zstr(val)) {
3065 				errno = 0;		/* safety first */
3066 				announce_count = strtol(val, NULL, 0);
3067 				if (errno == ERANGE || errno == EINVAL) {
3068 					announce_count = 0;
3069 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "announce-count is invalid, not anouncing member counts\n");
3070 				}
3071 			} else if (!strcasecmp(var, "suppress-events") && !zstr(val)) {
3072 				suppress_events = val;
3073 			} else if (!strcasecmp(var, "verbose-events") && !zstr(val)) {
3074 				verbose_events = val;
3075 			} else if (!strcasecmp(var, "auto-record") && !zstr(val)) {
3076 				auto_record = val;
3077 			} else if (!strcasecmp(var, "recording-metadata") && !zstr(val)) {
3078 				recording_metadata = val;
3079 			} else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) {
3080 				if (!strcmp(val, "1")) {
3081 					min_recording_participants = 1;
3082 				} else if (!strcmp(val, "2")) {
3083 					min_recording_participants = 2;
3084 				} else {
3085 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "min-required-recording-participants is invalid, leaving set to %d\n", min_recording_participants);
3086 				}
3087 			} else if (!strcasecmp(var, "terminate-on-silence") && !zstr(val)) {
3088 				terminate_on_silence = val;
3089 			} else if (!strcasecmp(var, "endconf-grace-time") && !zstr(val)) {
3090 				endconference_grace_time = val;
3091 			} else if (!strcasecmp(var, "video-quality") && !zstr(val)) {
3092 				int tmp = atoi(val);
3093 
3094 				if (tmp > -1 && tmp < 5) {
3095 					conference_video_quality = tmp;
3096 				} else {
3097 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Video quality must be between 0 and 4\n");
3098 				}
3099 			} else if (!strcasecmp(var, "video-kps-debounce") && !zstr(val)) {
3100 				int tmp = atoi(val);
3101 
3102 				if (tmp >= 0) {
3103 					auto_kps_debounce = tmp;
3104 				} else {
3105 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-kps-debounce must be 0 or higher\n");
3106 				}
3107 
3108 			} else if (!strcasecmp(var, "video-mode") && !zstr(val)) {
3109 				if (!strcasecmp(val, "passthrough")) {
3110 					conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH;
3111 				} else if (!strcasecmp(val, "transcode")) {
3112 					conference_video_mode = CONF_VIDEO_MODE_TRANSCODE;
3113 				} else if (!strcasecmp(val, "mux")) {
3114 					conference_video_mode = CONF_VIDEO_MODE_MUX;
3115 				} else {
3116 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, valid settings are 'passthrough', 'transcode' and 'mux'\n");
3117 				}
3118 			} else if (!strcasecmp(var, "scale-h264-canvas-size") && !zstr(val)) {
3119 				char *p;
3120 
3121 				if ((scale_h264_canvas_width = atoi(val))) {
3122 					if ((p = strchr(val, 'x'))) {
3123 						p++;
3124 						if (*p) {
3125 							scale_h264_canvas_height = atoi(p);
3126 						}
3127 					}
3128 				}
3129 
3130 				if (scale_h264_canvas_width < 320 || scale_h264_canvas_height < 180) {
3131 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid scale-h264-canvas-size, falling back to 320x180\n");
3132 					scale_h264_canvas_width = 320;
3133 					scale_h264_canvas_height = 180;
3134 				}
3135 			} else if (!strcasecmp(var, "scale-h264-canvas-fps-divisor") && !zstr(val)) {
3136 				scale_h264_canvas_fps_divisor = atoi(val);
3137 				if (scale_h264_canvas_fps_divisor < 0) scale_h264_canvas_fps_divisor = 0;
3138 			} else if (!strcasecmp(var, "scale-h264-canvas-bandwidth") && !zstr(val)) {
3139 				scale_h264_canvas_bandwidth = val;
3140 			} else if (!strcasecmp(var, "video-codec-config-profile-name") && !zstr(val)) {
3141 				video_codec_config_profile_name = val;
3142 			}
3143 		}
3144 
3145 	/* Set defaults and various paramaters */
3146 
3147 	if (zstr(video_layout_conf)) {
3148 		video_layout_conf = "conference_layouts.conf";
3149 	}
3150 
3151 	/* Timer module to use */
3152 	if (zstr(timer_name)) {
3153 		timer_name = "soft";
3154 	}
3155 
3156 	/* Caller ID Name */
3157 	if (zstr(caller_id_name)) {
3158 		caller_id_name = (char *) mod_conference_app_name;
3159 	}
3160 
3161 	/* Caller ID Number */
3162 	if (zstr(caller_id_number)) {
3163 		caller_id_number = SWITCH_DEFAULT_CLID_NUMBER;
3164 	}
3165 
3166 	if (!pool) {
3167 		/* Setup a memory pool to use. */
3168 		if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
3169 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n");
3170 			conference = NULL;
3171 			goto end;
3172 		}
3173 	}
3174 
3175 	/* Create the conference object. */
3176 	if (!(conference = switch_core_alloc(pool, sizeof(*conference)))) {
3177 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
3178 		conference = NULL;
3179 		goto end;
3180 	}
3181 
3182 	conference->start_time = switch_epoch_time_now(NULL);
3183 
3184 	/* initialize the conference object with settings from the specified profile */
3185 	conference->pool = pool;
3186 	conference->profile_name = switch_core_strdup(conference->pool, cfg.profile ? switch_xml_attr_soft(cfg.profile, "name") : "none");
3187 	if (timer_name) {
3188 		conference->timer_name = switch_core_strdup(conference->pool, timer_name);
3189 	}
3190 	if (tts_engine) {
3191 		conference->tts_engine = switch_core_strdup(conference->pool, tts_engine);
3192 	}
3193 	if (tts_voice) {
3194 		conference->tts_voice = switch_core_strdup(conference->pool, tts_voice);
3195 	}
3196 
3197 	conference->video_layout_conf = switch_core_strdup(conference->pool, video_layout_conf);
3198 	conference->comfort_noise_level = comfort_noise_level;
3199 	conference->pin_retries = pin_retries;
3200 	conference->caller_id_name = switch_core_strdup(conference->pool, caller_id_name);
3201 	conference->caller_id_number = switch_core_strdup(conference->pool, caller_id_number);
3202 	conference->caller_controls = switch_core_strdup(conference->pool, caller_controls);
3203 	conference->moderator_controls = switch_core_strdup(conference->pool, moderator_controls);
3204 	conference->broadcast_chat_messages = broadcast_chat_messages;
3205 	conference->video_quality = conference_video_quality;
3206 	conference->auto_kps_debounce = auto_kps_debounce;
3207 	switch_event_create_plain(&conference->variables, SWITCH_EVENT_CHANNEL_DATA);
3208 	conference->conference_video_mode = conference_video_mode;
3209 	conference->video_codec_config_profile_name = switch_core_strdup(conference->pool, video_codec_config_profile_name);
3210 
3211 	conference->scale_h264_canvas_width = scale_h264_canvas_width;
3212 	conference->scale_h264_canvas_height = scale_h264_canvas_height;
3213 	conference->scale_h264_canvas_fps_divisor = scale_h264_canvas_fps_divisor;
3214 	conference->scale_h264_canvas_bandwidth = switch_core_strdup(conference->pool, scale_h264_canvas_bandwidth);
3215 
3216 	if (!switch_core_has_video() && (conference->conference_video_mode == CONF_VIDEO_MODE_MUX || conference->conference_video_mode == CONF_VIDEO_MODE_TRANSCODE)) {
3217 		conference->conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH;
3218 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, only valid setting is 'passthrough' due to no video capabilities\n");
3219 	}
3220 
3221 	if (conference->conference_video_mode == CONF_VIDEO_MODE_MUX) {
3222 		int canvas_w = 0, canvas_h = 0;
3223 		if (video_canvas_size) {
3224 			char *p;
3225 
3226 			if ((canvas_w = atoi(video_canvas_size))) {
3227 				if ((p = strchr(video_canvas_size, 'x'))) {
3228 					p++;
3229 					if (*p) {
3230 						canvas_h = atoi(p);
3231 					}
3232 				}
3233 			}
3234 		}
3235 
3236 		if ((canvas_w % 2) != 0) {
3237 			canvas_w++;
3238 		}
3239 
3240 		if ((canvas_h % 2) != 0) {
3241 			canvas_h++;
3242 		}
3243 
3244 		if (canvas_w < 320 || canvas_h < 180) {
3245 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s video-canvas-size, falling back to %ux%u\n",
3246 							  video_canvas_size ? "Invalid" : "Unspecified", CONFERENCE_CANVAS_DEFAULT_WIDTH, CONFERENCE_CANVAS_DEFAULT_HIGHT);
3247 			canvas_w = CONFERENCE_CANVAS_DEFAULT_WIDTH;
3248 			canvas_h = CONFERENCE_CANVAS_DEFAULT_HIGHT;
3249 		}
3250 
3251 		if (video_border_size) {
3252 			if (video_border_size < 0) video_border_size = 0;
3253 			if (video_border_size > 50) video_border_size = 50;
3254 		}
3255 		conference->video_border_size = video_border_size;
3256 
3257 		conference_video_parse_layouts(conference, canvas_w, canvas_h);
3258 
3259 		if (!video_canvas_bgcolor) {
3260 			video_canvas_bgcolor = "#333333";
3261 		}
3262 
3263 		if (!video_border_color) {
3264 			video_border_color = "#00ff00";
3265 		}
3266 
3267 		if (!video_super_canvas_bgcolor) {
3268 			video_super_canvas_bgcolor = "#068df3";
3269 		}
3270 
3271 		if (!video_letterbox_bgcolor) {
3272 			video_letterbox_bgcolor = "#000000";
3273 		}
3274 
3275 		if (video_mute_banner) {
3276 		    conference->video_mute_banner = switch_core_strdup(conference->pool, video_mute_banner);
3277 		}
3278 
3279 		if (no_video_avatar) {
3280 			conference->no_video_avatar = switch_core_strdup(conference->pool, no_video_avatar);
3281 		}
3282 
3283 
3284 		conference->video_canvas_bgcolor = switch_core_strdup(conference->pool, video_canvas_bgcolor);
3285 		conference->video_border_color = switch_core_strdup(conference->pool, video_border_color);
3286 		conference->video_super_canvas_bgcolor = switch_core_strdup(conference->pool, video_super_canvas_bgcolor);
3287 		conference->video_letterbox_bgcolor = switch_core_strdup(conference->pool, video_letterbox_bgcolor);
3288 
3289 		if (fps) {
3290 			conference_video_set_fps(conference, fps);
3291 		}
3292 
3293 		if (!conference->video_fps.ms) {
3294 			conference_video_set_fps(conference, 30);
3295 		}
3296 
3297 		if (video_codec_bandwidth) {
3298 			if (!strcasecmp(video_codec_bandwidth, "auto")) {
3299 				conference->video_codec_settings.video.bandwidth = switch_calc_bitrate(canvas_w, canvas_h, conference->video_quality, conference->video_fps.fps);
3300 			} else {
3301 				conference->video_codec_settings.video.bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth);
3302 			}
3303 		}
3304 
3305 		conference->video_codec_settings.video.try_hardware_encoder = 1;
3306 
3307 		if (zstr(video_layout_name)) {
3308 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No video-layout-name specified, using " CONFERENCE_MUX_DEFAULT_LAYOUT "\n");
3309 			video_layout_name = CONFERENCE_MUX_DEFAULT_LAYOUT;
3310 		}
3311 
3312 		if (video_layout_name) {
3313 			if (!strncasecmp(video_layout_name, "group:", 6)) {
3314 				video_layout_group = video_layout_name + 6;
3315 			}
3316 			conference->video_layout_name = switch_core_strdup(conference->pool, video_layout_name);
3317 		}
3318 
3319 		if (video_layout_group) {
3320 			conference->video_layout_group = switch_core_strdup(conference->pool, video_layout_group);
3321 		}
3322 
3323 		if (!conference_video_get_layout(conference, video_layout_name, video_layout_group)) {
3324 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid video-layout-name specified, using " CONFERENCE_MUX_DEFAULT_LAYOUT "\n");
3325 			video_layout_name = CONFERENCE_MUX_DEFAULT_LAYOUT;
3326 			video_layout_group = video_layout_name + 6;
3327 			conference->video_layout_name = switch_core_strdup(conference->pool, video_layout_name);
3328 			conference->video_layout_group = switch_core_strdup(conference->pool, video_layout_group);
3329 		}
3330 
3331 		if (!conference_video_get_layout(conference, video_layout_name, video_layout_group)) {
3332 			conference->video_layout_name = conference->video_layout_group = video_layout_group = video_layout_name = NULL;
3333 			if (conference_video_get_layout(conference, conference->default_layout_name, NULL)) {
3334 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Defaulting to layout %s\n", conference->default_layout_name);
3335 				video_layout_name = conference->video_layout_name = conference->default_layout_name;
3336 			}
3337 		}
3338 
3339 		if (!conference_video_get_layout(conference, video_layout_name, video_layout_group)) {
3340 			conference->video_layout_name = conference->video_layout_group = video_layout_group = video_layout_name = NULL;
3341 			conference->conference_video_mode = CONF_VIDEO_MODE_TRANSCODE;
3342 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid conference layout settings, falling back to transcode mode\n");
3343 		} else {
3344 			conference->canvas_width = canvas_w;
3345 			conference->canvas_height = canvas_h;
3346 		}
3347 	}
3348 
3349 	if (conference->conference_video_mode == CONF_VIDEO_MODE_TRANSCODE || conference->conference_video_mode == CONF_VIDEO_MODE_MUX) {
3350 		conference_utils_set_flag(conference, CFLAG_TRANSCODE_VIDEO);
3351 	}
3352 
3353 	if (outcall_templ) {
3354 		conference->outcall_templ = switch_core_strdup(conference->pool, outcall_templ);
3355 	}
3356 	conference->run_time = switch_epoch_time_now(NULL);
3357 
3358 	if (!zstr(conference_log_dir)) {
3359 		char *path;
3360 
3361 		if (!strcmp(conference_log_dir, "auto")) {
3362 			path = switch_core_sprintf(conference->pool, "%s%sconference_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR);
3363 		} else if (!switch_is_file_path(conference_log_dir)) {
3364 			path = switch_core_sprintf(conference->pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, conference_log_dir);
3365 		} else {
3366 			path = switch_core_strdup(conference->pool, conference_log_dir);
3367 		}
3368 
3369 		switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS, conference->pool);
3370 		conference->log_dir = path;
3371 
3372 	}
3373 
3374 	if (!zstr(cdr_event_mode)) {
3375 		if (!strcmp(cdr_event_mode, "content")) {
3376 			conference->cdr_event_mode = CDRE_AS_CONTENT;
3377 		} else if (!strcmp(cdr_event_mode, "file")) {
3378 			if (!zstr(conference->log_dir)) {
3379 				conference->cdr_event_mode = CDRE_AS_FILE;
3380 			} else {
3381 				conference->cdr_event_mode = CDRE_NONE;
3382 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "'cdr-log-dir' parameter not set; CDR event mode 'file' ignored");
3383 			}
3384 		} else {
3385 			conference->cdr_event_mode = CDRE_NONE;
3386 		}
3387 	}
3388 
3389 	if (!zstr(perpetual_sound)) {
3390 		conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound);
3391 	}
3392 
3393 	conference->mflags[MFLAG_CAN_SPEAK] = conference->mflags[MFLAG_CAN_HEAR] = conference->mflags[MFLAG_CAN_BE_SEEN] = conference->mflags[MFLAG_CAN_SEE] = 1;
3394 
3395 	if (!zstr(moh_sound) && switch_is_moh(moh_sound)) {
3396 		conference->moh_sound = switch_core_strdup(conference->pool, moh_sound);
3397 	}
3398 
3399 	if (member_flags) {
3400 		conference_utils_set_mflags(member_flags, conference->mflags);
3401 	}
3402 
3403 	if (conference_flags) {
3404 		conference_utils_set_cflags(conference_flags, conference->flags);
3405 	}
3406 
3407 	if (!zstr(sound_prefix)) {
3408 		conference->sound_prefix = switch_core_strdup(conference->pool, sound_prefix);
3409 	} else {
3410 		const char *val;
3411 		if ((val = switch_channel_get_variable(channel, "sound_prefix")) && !zstr(val)) {
3412 			/* if no sound_prefix was set, use the channel sound_prefix */
3413 			conference->sound_prefix = switch_core_strdup(conference->pool, val);
3414 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "using channel sound prefix: %s\n", conference->sound_prefix);
3415 		}
3416 	}
3417 
3418 	if (!zstr(enter_sound)) {
3419 		conference->enter_sound = switch_core_strdup(conference->pool, enter_sound);
3420 	}
3421 
3422 	if (!zstr(member_enter_sound)) {
3423 		conference->member_enter_sound = switch_core_strdup(conference->pool, member_enter_sound);
3424 	}
3425 
3426 	if (!zstr(exit_sound)) {
3427 		conference->exit_sound = switch_core_strdup(conference->pool, exit_sound);
3428 	}
3429 
3430 	if (!zstr(muted_sound)) {
3431 		conference->muted_sound = switch_core_strdup(conference->pool, muted_sound);
3432 	}
3433 
3434 	if (zstr(mute_detect_sound)) {
3435 		if (!zstr(muted_sound)) {
3436 			conference->mute_detect_sound = switch_core_strdup(conference->pool, muted_sound);
3437 		}
3438 	} else {
3439 		conference->mute_detect_sound = switch_core_strdup(conference->pool, mute_detect_sound);
3440 	}
3441 
3442 	if (!zstr(unmuted_sound)) {
3443 		conference->unmuted_sound = switch_core_strdup(conference->pool, unmuted_sound);
3444 	}
3445 
3446 	if (!zstr(kicked_sound)) {
3447 		conference->kicked_sound = switch_core_strdup(conference->pool, kicked_sound);
3448 	}
3449 
3450 	if (!zstr(pin_sound)) {
3451 		conference->pin_sound = switch_core_strdup(conference->pool, pin_sound);
3452 	}
3453 
3454 	if (!zstr(bad_pin_sound)) {
3455 		conference->bad_pin_sound = switch_core_strdup(conference->pool, bad_pin_sound);
3456 	}
3457 
3458 	if (!zstr(deaf_sound)) {
3459 		conference->deaf_sound = switch_core_strdup(conference->pool, deaf_sound);
3460 	}
3461 
3462 	if (!zstr(undeaf_sound)) {
3463 		conference->undeaf_sound = switch_core_strdup(conference->pool, undeaf_sound);
3464 	}
3465 
3466 	if (!zstr(blind_sound)) {
3467 		conference->blind_sound = switch_core_strdup(conference->pool, blind_sound);
3468 	}
3469 
3470 	if (!zstr(unblind_sound)) {
3471 		conference->unblind_sound = switch_core_strdup(conference->pool, unblind_sound);
3472 	}
3473 
3474 	if (!zstr(pin)) {
3475 		conference->pin = switch_core_strdup(conference->pool, pin);
3476 	}
3477 
3478 	if (!zstr(mpin)) {
3479 		conference->mpin = switch_core_strdup(conference->pool, mpin);
3480 	}
3481 
3482 	if (!zstr(alone_sound)) {
3483 		conference->alone_sound = switch_core_strdup(conference->pool, alone_sound);
3484 	}
3485 
3486 	if (!zstr(locked_sound)) {
3487 		conference->locked_sound = switch_core_strdup(conference->pool, locked_sound);
3488 	}
3489 
3490 	if (!zstr(is_locked_sound)) {
3491 		conference->is_locked_sound = switch_core_strdup(conference->pool, is_locked_sound);
3492 	}
3493 
3494 	if (!zstr(is_unlocked_sound)) {
3495 		conference->is_unlocked_sound = switch_core_strdup(conference->pool, is_unlocked_sound);
3496 	}
3497 
3498 	if (!zstr(energy_level)) {
3499 		conference->energy_level = atoi(energy_level);
3500 		if (conference->energy_level < 0) {
3501 			conference->energy_level = 0;
3502 		}
3503 	}
3504 
3505 	if (!zstr(max_energy_level_mute_ms)) {
3506 		int mute_ms = atoi(max_energy_level_mute_ms);
3507 
3508 		if (mute_ms > 0) {
3509 			conference->burst_mute_count = mute_ms / interval;
3510 		}
3511 	}
3512 
3513 	conference->max_energy_hit_trigger = 5;
3514 
3515 	if (!zstr(max_energy_level)) {
3516 		conference->max_energy_hit_trigger = atoi(max_energy_hit_trigger);
3517 		if (conference->max_energy_hit_trigger < 0) {
3518 			conference->max_energy_hit_trigger = 0;
3519 		}
3520 
3521 		conference->max_energy_level = atoi(max_energy_level);
3522 		if (conference->max_energy_level < 0) {
3523 			conference->max_energy_level = 0;
3524 		}
3525 
3526 
3527 		if (conference->energy_level && conference->max_energy_level < conference->energy_level) {
3528 			conference->max_energy_level = 0;
3529 		}
3530 	}
3531 
3532 	if (!zstr(auto_energy_sec)) {
3533 		conference->auto_energy_sec = atoi(auto_energy_sec);
3534 		if (conference->auto_energy_sec < 0) {
3535 			conference->auto_energy_sec = 0;
3536 		}
3537 	}
3538 
3539 	if (!conference->auto_energy_sec) {
3540 		conference->auto_energy_sec = 5;
3541 	}
3542 
3543 	if (!zstr(auto_energy_level)) {
3544 		conference->auto_energy_level = atoi(auto_energy_level);
3545 		if (conference->auto_energy_level < 0) {
3546 			conference->auto_energy_level = 0;
3547 		}
3548 
3549 		if (!conference->energy_level) {
3550 			conference->energy_level = conference->auto_energy_level / 2;
3551 		}
3552 	}
3553 
3554 	if (!zstr(maxmember_sound)) {
3555 		conference->maxmember_sound = switch_core_strdup(conference->pool, maxmember_sound);
3556 	}
3557 	/* its going to be 0 by default, set to a value otherwise so this should be safe */
3558 	conference->max_members = max_members;
3559 	conference->announce_count = announce_count;
3560 
3561 	conference->name = switch_core_strdup(conference->pool, name);
3562 
3563 	if ((name_domain = strchr(conference->name, '@'))) {
3564 		name_domain++;
3565 		conference->domain = switch_core_strdup(conference->pool, name_domain);
3566 	} else if (domain) {
3567 		conference->domain = switch_core_strdup(conference->pool, domain);
3568 	} else if (presence_id && (name_domain = strchr(presence_id, '@'))) {
3569 		name_domain++;
3570 		conference->domain = switch_core_strdup(conference->pool, name_domain);
3571 	} else {
3572 		conference->domain = "cluecon.com";
3573 	}
3574 
3575 	conference->chat_id = switch_core_sprintf(conference->pool, "conf+%s@%s", conference->name, conference->domain);
3576 
3577 	conference->channels = channels;
3578 	conference->rate = rate;
3579 	conference->interval = interval;
3580 	conference->ivr_dtmf_timeout = ivr_dtmf_timeout;
3581 	conference->ivr_input_timeout = ivr_input_timeout;
3582 
3583 
3584 	conference->agc_level = 0;
3585 	conference->agc_low_energy_level = 0;
3586 	conference->agc_margin = 20;
3587 	conference->agc_change_factor = 3;
3588 	conference->agc_period_len = (1000 / conference->interval) * 2;
3589 
3590 
3591 	if (agc_level) {
3592 		tmp = atoi(agc_level);
3593 		if (tmp > 0) {
3594 			conference->agc_level = tmp;
3595 		}
3596 	}
3597 
3598 	if (agc_low_energy_level) {
3599 		tmp = atoi(agc_low_energy_level);
3600 		if (tmp > 0) {
3601 			conference->agc_low_energy_level = tmp;
3602 		}
3603 	}
3604 
3605 	if (agc_margin) {
3606 		tmp = atoi(agc_margin);
3607 		if (tmp > 0) {
3608 			conference->agc_margin = tmp;
3609 		}
3610 	}
3611 
3612 	if (agc_change_factor) {
3613 		tmp = atoi(agc_change_factor);
3614 		if (tmp > 0) {
3615 			conference->agc_change_factor = tmp;
3616 		}
3617 	}
3618 
3619 	if (agc_period_len) {
3620 		tmp = atoi(agc_period_len);
3621 		if (tmp > 0) {
3622 			conference->agc_period_len = (1000 / conference->interval) * tmp;
3623 		}
3624 	}
3625 
3626 	if (video_auto_floor_msec) {
3627 		conference->video_floor_packets = video_auto_floor_msec / conference->interval;
3628 	}
3629 
3630 	conference->eflags = 0xFFFFFFFF;
3631 
3632 	if (!zstr(suppress_events)) {
3633 		conference_utils_clear_eflags(suppress_events, &conference->eflags);
3634 	}
3635 
3636 	if (!zstr(auto_record)) {
3637 		conference->auto_record = switch_core_strdup(conference->pool, auto_record);
3638 	}
3639 
3640 	if (!zstr(recording_metadata)) {
3641 		conference->recording_metadata = switch_core_strdup(conference->pool, recording_metadata);
3642 	}
3643 
3644 	conference->min_recording_participants = min_recording_participants;
3645 
3646 	if (!zstr(desc)) {
3647 		conference->desc = switch_core_strdup(conference->pool, desc);
3648 	}
3649 
3650 	if (!zstr(terminate_on_silence)) {
3651 		conference->terminate_on_silence = atoi(terminate_on_silence);
3652 	}
3653 	if (!zstr(endconference_grace_time)) {
3654 		conference->endconference_grace_time = atoi(endconference_grace_time);
3655 	}
3656 
3657 	if (!zstr(verbose_events) && switch_true(verbose_events)) {
3658 		conference->verbose_events = 1;
3659 	}
3660 
3661 	/* Create the conference unique identifier */
3662 	switch_uuid_get(&uuid);
3663 	switch_uuid_format(uuid_str, &uuid);
3664 	conference->uuid_str = switch_core_strdup(conference->pool, uuid_str);
3665 
3666 	/* Set enter sound and exit sound flags so that default is on */
3667 	conference_utils_set_flag(conference, CFLAG_ENTER_SOUND);
3668 	conference_utils_set_flag(conference, CFLAG_EXIT_SOUND);
3669 
3670 	/* Activate the conference mutex for exclusivity */
3671 	switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool);
3672 	switch_mutex_init(&conference->flag_mutex, SWITCH_MUTEX_NESTED, conference->pool);
3673 	switch_mutex_init(&conference->file_mutex, SWITCH_MUTEX_NESTED, conference->pool);
3674 	switch_thread_rwlock_create(&conference->rwlock, conference->pool);
3675 	switch_mutex_init(&conference->member_mutex, SWITCH_MUTEX_NESTED, conference->pool);
3676 	switch_mutex_init(&conference->canvas_mutex, SWITCH_MUTEX_NESTED, conference->pool);
3677 
3678 	switch_mutex_lock(conference_globals.hash_mutex);
3679 	conference_utils_set_flag(conference, CFLAG_INHASH);
3680 	switch_core_hash_insert(conference_globals.conference_hash, conference->name, conference);
3681 	switch_mutex_unlock(conference_globals.hash_mutex);
3682 
3683 	conference->super_canvas_label_layers = video_super_canvas_label_layers;
3684 	conference->super_canvas_show_all_layers = video_super_canvas_show_all_layers;
3685 
3686 
3687 	if (conference_utils_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
3688 		char *p;
3689 
3690 		if (strchr(conference->name, '@')) {
3691 			conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
3692 			conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s", conference->name);
3693 			conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s", conference->name);
3694 			conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s", conference->name);
3695 		} else {
3696 			conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
3697 			conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s@%s", conference->name, conference->domain);
3698 			conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s@%s", conference->name, conference->domain);
3699 			conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s@%s", conference->name, conference->domain);
3700 		}
3701 
3702 		conference->la_name = switch_core_strdup(conference->pool, conference->name);
3703 		if ((p = strchr(conference->la_name, '@'))) {
3704 			*p = '\0';
3705 		}
3706 
3707 		switch_live_array_create(conference->la_event_channel, conference->la_name, conference_globals.event_channel_id, &conference->la);
3708 		switch_live_array_set_user_data(conference->la, conference);
3709 		switch_live_array_set_command_handler(conference->la, conference_event_la_command_handler);
3710 	}
3711 
3712 
3713 
3714 	if (video_canvas_count < 1) video_canvas_count = 1;
3715 
3716 	if (conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS) && video_canvas_count > 1) {
3717 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Personal Canvas and Multi-Canvas modes are not compatable. 1 canvas will be used.\n");
3718 		video_canvas_count = 1;
3719 	}
3720 
3721 	if (conference->conference_video_mode == CONF_VIDEO_MODE_MUX) {
3722 		video_layout_t *vlayout = conference_video_get_layout(conference, conference->video_layout_name, conference->video_layout_group);
3723 
3724 		if (!vlayout) {
3725 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot find layout\n");
3726 			conference->video_layout_name = conference->video_layout_group = NULL;
3727 			conference_utils_clear_flag(conference, CFLAG_VIDEO_MUXING);
3728 		} else {
3729 			int j;
3730 
3731 			for (j = 0; j < video_canvas_count; j++) {
3732 				mcu_canvas_t *canvas = NULL;
3733 
3734 				switch_mutex_lock(conference->canvas_mutex);
3735 				conference_video_init_canvas(conference, vlayout, &canvas);
3736 				conference_video_attach_canvas(conference, canvas, 0);
3737 				conference_video_launch_muxing_thread(conference, canvas, 0);
3738 				switch_mutex_unlock(conference->canvas_mutex);
3739 			}
3740 
3741 			if (conference->canvas_count > 1) {
3742 				video_layout_t *svlayout = conference_video_get_layout(conference, NULL, CONFERENCE_MUX_DEFAULT_SUPER_LAYOUT);
3743 				mcu_canvas_t *canvas = NULL;
3744 
3745 				if (svlayout) {
3746 					switch_mutex_lock(conference->canvas_mutex);
3747 					conference_video_init_canvas(conference, svlayout, &canvas);
3748 					conference_video_set_canvas_bgcolor(canvas, conference->video_super_canvas_bgcolor);
3749 					conference_video_attach_canvas(conference, canvas, 1);
3750 					conference_video_launch_muxing_thread(conference, canvas, 1);
3751 					switch_mutex_unlock(conference->canvas_mutex);
3752 				}
3753 			}
3754 
3755 			if (cfg.profile) {
3756 				for (xml_kvp = switch_xml_child(cfg.profile, "video-codec-group"); xml_kvp; xml_kvp = xml_kvp->next) {
3757 					char *name = (char *) switch_xml_attr_soft(xml_kvp, "name");
3758 					char *bw = (char *) switch_xml_attr_soft(xml_kvp, "bandwidth");
3759 					char *fps = (char *) switch_xml_attr_soft(xml_kvp, "fps-divisor");
3760 					char *res = (char *) switch_xml_attr_soft(xml_kvp, "res-divisor");
3761 
3762 					if (name && bw) {
3763 						const char *str = switch_core_sprintf(conference->pool, "%s%s%s%s%s", bw,
3764 															  !zstr(res) ? ":" : "", res, !zstr(fps) ? ":" : "", fps);
3765 
3766 						const char *gname = switch_core_sprintf(conference->pool, "group-%s", name);
3767 
3768 						conference_set_variable(conference, gname, str);
3769 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video codec group preset %s set to [%s]\n", gname, str);
3770 					}
3771 
3772 				}
3773 
3774 			}
3775 
3776 		}
3777 	}
3778 
3779 	if (cfg.profile) {
3780 		switch_xml_t xml_profile_variables;
3781 		if ((xml_profile_variables = switch_xml_child(cfg.profile, "variables")) != NULL) {
3782 			for (xml_kvp = switch_xml_child(xml_profile_variables, "variable"); xml_kvp; xml_kvp = xml_kvp->next) {
3783 				char *var = (char *) switch_xml_attr_soft(xml_kvp, "name");
3784 				char *val = (char *) switch_xml_attr_soft(xml_kvp, "value");
3785 				if (var && val) {
3786 					conference_set_variable(conference, var, val);
3787 				}
3788 			}
3789 		}
3790 	}
3791 
3792 	switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
3793 	conference_event_add_data(conference, event);
3794 	if (conference->verbose_events && channel) {
3795 		switch_channel_event_set_data(channel, event);
3796 	}
3797 	switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create");
3798 	switch_event_fire(&event);
3799 
3800  end:
3801 
3802 	switch_mutex_unlock(conference_globals.hash_mutex);
3803 
3804 	return conference;
3805 }
3806 
conference_send_presence(conference_obj_t * conference)3807 void conference_send_presence(conference_obj_t *conference)
3808 {
3809 	switch_event_t *event;
3810 
3811 	if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
3812 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", CONF_CHAT_PROTO);
3813 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", conference->name);
3814 		if (strchr(conference->name, '@')) {
3815 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", conference->name);
3816 		} else {
3817 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", conference->name, conference->domain);
3818 		}
3819 
3820 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
3821 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
3822 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
3823 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", conference->name);
3824 
3825 		if (conference->count) {
3826 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d caller%s)", conference->count, conference->count == 1 ? "" : "s");
3827 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
3828 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", conference->count == 1 ? "early" : "confirmed");
3829 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-call-direction", conference->count == 1 ? "outbound" : "inbound");
3830 		} else {
3831 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Inactive");
3832 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
3833 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
3834 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
3835 		}
3836 
3837 
3838 
3839 		switch_event_fire(&event);
3840 	}
3841 
3842 }
3843 #if 0
3844 uint32_t conference_kickall_matching_var(conference_obj_t *conference, const char *var, const char *val)
3845 {
3846 	conference_member_t *member = NULL;
3847 	const char *vval = NULL;
3848 	uint32_t r = 0;
3849 
3850 	switch_mutex_lock(conference->mutex);
3851 	switch_mutex_lock(conference->member_mutex);
3852 
3853 	for (member = conference->members; member; member = member->next) {
3854 		switch_channel_t *channel = NULL;
3855 
3856 		if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
3857 			continue;
3858 		}
3859 
3860 		channel = switch_core_session_get_channel(member->session);
3861 		vval = switch_channel_get_variable(channel, var);
3862 
3863 		if (vval && !strcmp(vval, val)) {
3864 			conference_utils_member_set_flag_locked(member, MFLAG_KICKED);
3865 			conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);
3866 			switch_core_session_kill_channel(member->session, SWITCH_SIG_BREAK);
3867 			r++;
3868 		}
3869 
3870 	}
3871 
3872 	switch_mutex_unlock(conference->member_mutex);
3873 	switch_mutex_unlock(conference->mutex);
3874 
3875 	return r;
3876 }
3877 #endif
3878 
send_presence(switch_event_types_t id)3879 void send_presence(switch_event_types_t id)
3880 {
3881 	switch_xml_t cxml, cfg, advertise, room;
3882 	switch_event_t *params = NULL;
3883 
3884 	switch_event_create(&params, SWITCH_EVENT_COMMAND);
3885 	switch_assert(params);
3886 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "presence", "true");
3887 
3888 
3889 	/* Open the config from the xml registry */
3890 	if (!(cxml = switch_xml_open_cfg(mod_conference_cf_name, &cfg, params))) {
3891 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", mod_conference_cf_name);
3892 		goto done;
3893 	}
3894 
3895 	if ((advertise = switch_xml_child(cfg, "advertise"))) {
3896 		for (room = switch_xml_child(advertise, "room"); room; room = room->next) {
3897 			char *name = (char *) switch_xml_attr_soft(room, "name");
3898 			char *status = (char *) switch_xml_attr_soft(room, "status");
3899 			switch_event_t *event;
3900 
3901 			if (name && switch_event_create(&event, id) == SWITCH_STATUS_SUCCESS) {
3902 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", CONF_CHAT_PROTO);
3903 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", name);
3904 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", name);
3905 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", status ? status : "Available");
3906 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
3907 				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
3908 				switch_event_fire(&event);
3909 			}
3910 		}
3911 	}
3912 
3913  done:
3914 	switch_event_destroy(&params);
3915 
3916 	/* Release the config registry handle */
3917 	if (cxml) {
3918 		switch_xml_free(cxml);
3919 		cxml = NULL;
3920 	}
3921 }
3922 
3923 /* Called by FreeSWITCH when the module loads */
SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load)3924 SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load)
3925 {
3926 	char *p = NULL;
3927 	switch_chat_interface_t *chat_interface;
3928 	switch_api_interface_t *api_interface;
3929 	switch_application_interface_t *app_interface;
3930 	switch_status_t status = SWITCH_STATUS_SUCCESS;
3931 
3932 	memset(&conference_globals, 0, sizeof(conference_globals));
3933 
3934 	/* Connect my internal structure to the blank pointer passed to me */
3935 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
3936 
3937 	switch_console_add_complete_func("::conference::conference_list_conferences", conference_list_conferences);
3938 
3939 
3940 	switch_event_channel_bind("conference", conference_event_channel_handler, &conference_globals.event_channel_id, NULL);
3941 	switch_event_channel_bind("conference-liveArray", conference_event_la_channel_handler, &conference_globals.event_channel_id, NULL);
3942 	switch_event_channel_bind("conference-mod", conference_event_mod_channel_handler, &conference_globals.event_channel_id, NULL);
3943 	switch_event_channel_bind("conference-chat", conference_event_chat_channel_handler, &conference_globals.event_channel_id, NULL);
3944 
3945 	if ( conference_api_sub_syntax(&api_syntax) != SWITCH_STATUS_SUCCESS) {
3946 		return SWITCH_STATUS_TERM;
3947 	}
3948 
3949 	/* create/register custom event message type */
3950 	if (switch_event_reserve_subclass(CONF_EVENT_MAINT) != SWITCH_STATUS_SUCCESS) {
3951 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", CONF_EVENT_MAINT);
3952 		return SWITCH_STATUS_TERM;
3953 	}
3954 
3955 	/* Setup the pool */
3956 	conference_globals.conference_pool = pool;
3957 
3958 	/* Setup a hash to store conferences by name */
3959 	switch_core_hash_init(&conference_globals.conference_hash);
3960 	switch_mutex_init(&conference_globals.conference_mutex, SWITCH_MUTEX_NESTED, conference_globals.conference_pool);
3961 	switch_mutex_init(&conference_globals.id_mutex, SWITCH_MUTEX_NESTED, conference_globals.conference_pool);
3962 	switch_mutex_init(&conference_globals.hash_mutex, SWITCH_MUTEX_NESTED, conference_globals.conference_pool);
3963 	switch_mutex_init(&conference_globals.setup_mutex, SWITCH_MUTEX_NESTED, conference_globals.conference_pool);
3964 
3965 	/* Subscribe to presence request events */
3966 	if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, conference_event_pres_handler, NULL) != SWITCH_STATUS_SUCCESS) {
3967 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't subscribe to presence request events!\n");
3968 	}
3969 
3970 	if (switch_event_bind(modname, SWITCH_EVENT_CONFERENCE_DATA_QUERY, SWITCH_EVENT_SUBCLASS_ANY, conference_data_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
3971 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't subscribe to conference data query events!\n");
3972 	}
3973 
3974 	if (switch_event_bind(modname, SWITCH_EVENT_CALL_SETUP_REQ, SWITCH_EVENT_SUBCLASS_ANY, conference_event_call_setup_handler, NULL) != SWITCH_STATUS_SUCCESS) {
3975 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't subscribe to conference data query events!\n");
3976 	}
3977 
3978 	SWITCH_ADD_API(api_interface, "conference", "Conference module commands", conference_api_main, p);
3979 	SWITCH_ADD_APP(app_interface, mod_conference_app_name, mod_conference_app_name, NULL, conference_function, NULL, SAF_SUPPORT_TEXT_ONLY);
3980 	SWITCH_ADD_APP(app_interface, "conference_set_auto_outcall", "conference_set_auto_outcall", NULL, conference_auto_function, NULL, SAF_NONE);
3981 	SWITCH_ADD_CHAT(chat_interface, CONF_CHAT_PROTO, chat_send);
3982 
3983 	send_presence(SWITCH_EVENT_PRESENCE_IN);
3984 
3985 	conference_globals.running = 1;
3986 	/* indicate that the module should continue to be loaded */
3987 	return status;
3988 }
3989 
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown)3990 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown)
3991 {
3992 	if (conference_globals.running) {
3993 
3994 		/* signal all threads to shutdown */
3995 		conference_globals.running = 0;
3996 
3997 		switch_event_channel_unbind(NULL, conference_event_channel_handler, NULL);
3998 		switch_event_channel_unbind(NULL, conference_event_la_channel_handler, NULL);
3999 		switch_event_channel_unbind(NULL, conference_event_mod_channel_handler, NULL);
4000 		switch_event_channel_unbind(NULL, conference_event_chat_channel_handler, NULL);
4001 
4002 		switch_console_del_complete_func("::conference::conference_list_conferences");
4003 
4004 		/* wait for all threads */
4005 		while (conference_globals.threads) {
4006 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for %d threads\n", conference_globals.threads);
4007 			switch_yield(100000);
4008 		}
4009 
4010 		switch_event_unbind_callback(conference_event_pres_handler);
4011 		switch_event_unbind_callback(conference_data_event_handler);
4012 		switch_event_unbind_callback(conference_event_call_setup_handler);
4013 		switch_event_free_subclass(CONF_EVENT_MAINT);
4014 
4015 		/* free api interface help ".syntax" field string */
4016 		switch_safe_free(api_syntax);
4017 	}
4018 	switch_core_hash_destroy(&conference_globals.conference_hash);
4019 
4020 	return SWITCH_STATUS_SUCCESS;
4021 }
4022 
4023 /* For Emacs:
4024  * Local Variables:
4025  * mode:c
4026  * indent-tabs-mode:t
4027  * tab-width:4
4028  * c-basic-offset:4
4029  * End:
4030  * For VIM:
4031  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
4032  */
4033