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  * Cesar Cepeda <cesar@auronix.com>
28  * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
29  *
30  *
31  * mod_local_stream.c -- Local Streaming Audio
32  *
33  */
34 #include <switch.h>
35 /* for apr_pstrcat */
36 #define DEFAULT_PREBUFFER_SIZE 1024 * 64
37 
38 SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load);
39 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_local_stream_shutdown);
40 SWITCH_MODULE_DEFINITION(mod_local_stream, mod_local_stream_load, mod_local_stream_shutdown, NULL);
41 
42 static int launch_streams(const char *name);
43 static void launch_thread(const char *name, const char *path, switch_xml_t directory);
44 
45 static const char *global_cf = "local_stream.conf";
46 
47 struct local_stream_source;
48 
49 static struct {
50 	switch_mutex_t *mutex;
51 	switch_hash_t *source_hash;
52 } globals;
53 
54 static int RUNNING = 1;
55 static int THREADS = 0;
56 
57 struct local_stream_context {
58 	struct local_stream_source *source;
59 	switch_mutex_t *audio_mutex;
60 	switch_buffer_t *audio_buffer;
61 	int err;
62 	const char *file;
63 	const char *func;
64 	int line;
65 	switch_file_handle_t *handle;
66 	switch_queue_t *video_q;
67 	int ready;
68 	int sent_png;
69 	int last_w;
70 	int last_h;
71 	int newres;
72 	int serno;
73 	int pop_count;
74 	int video_flushes;
75 	switch_size_t blank;
76 	switch_image_t *banner_img;
77 	switch_time_t banner_timeout;
78 	switch_memory_pool_t *pool;
79 	struct local_stream_context *next;
80 };
81 
82 typedef struct local_stream_context local_stream_context_t;
83 
84 #define MAX_CHIME 100
85 struct local_stream_source {
86 	char *name;
87 	char *location;
88 	uint8_t channels;
89 	int rate;
90 	int interval;
91 	switch_size_t samples;
92 	uint32_t prebuf;
93 	char *timer_name;
94 	local_stream_context_t *context_list;
95 	int total;
96 	int vol;
97 	switch_agc_t *agc;
98 	int energy_avg;
99 	int energy_low;
100 	int first;
101 	switch_dir_t *dir_handle;
102 	switch_mutex_t *mutex;
103 	switch_memory_pool_t *pool;
104 	int shuffle;
105 	switch_thread_rwlock_t *rwlock;
106 	int hup;
107 	int ready;
108 	int stopped;
109 	int part_reload;
110 	int full_reload;
111 	int chime_freq;
112 	int chime_total;
113 	int chime_max;
114 	int chime_cur;
115 	char *chime_list[MAX_CHIME];
116 	int32_t chime_counter;
117 	int32_t chime_max_counter;
118 	switch_file_handle_t chime_fh;
119 	switch_queue_t *video_q;
120 	int has_video;
121 	switch_image_t *blank_img;
122 	switch_image_t *logo_img;
123 	switch_image_t *cover_art;
124 	char *banner_txt;
125 	int serno;
126 	switch_size_t abuflen;
127 	switch_byte_t *abuf;
128 	switch_timer_t timer;
129 	int logo_always;
130 	switch_img_position_t logo_pos;
131 	uint8_t logo_opacity;
132 	uint8_t text_opacity;
133 	switch_mm_t mm;
134 };
135 
136 typedef struct local_stream_source local_stream_source_t;
137 
get_source(const char * path)138 local_stream_source_t *get_source(const char *path)
139 {
140 	local_stream_source_t *source = NULL;
141 
142 	switch_mutex_lock(globals.mutex);
143 	if ((source = switch_core_hash_find(globals.source_hash, path))) {
144 		if (!RUNNING || source->stopped || switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
145 			source = NULL;
146 		}
147 	}
148 	switch_mutex_unlock(globals.mutex);
149 
150 	return source;
151 }
152 
153 
list_streams_full(const char * line,const char * cursor,switch_console_callback_match_t ** matches,switch_bool_t show_aliases)154 switch_status_t list_streams_full(const char *line, const char *cursor, switch_console_callback_match_t **matches, switch_bool_t show_aliases)
155 {
156 	local_stream_source_t *source;
157 	switch_hash_index_t *hi;
158 	void *val;
159 	const void *vvar;
160 	switch_console_callback_match_t *my_matches = NULL;
161 	switch_status_t status = SWITCH_STATUS_FALSE;
162 
163 	switch_mutex_lock(globals.mutex);
164 	for (hi = switch_core_hash_first(globals.source_hash); hi; hi = switch_core_hash_next(&hi)) {
165 		switch_core_hash_this(hi, &vvar, NULL, &val);
166 
167 		source = (local_stream_source_t *) val;
168 		if (!show_aliases && strcmp((char *)vvar, source->name)) {
169 			continue;
170 		}
171 
172 		switch_console_push_match(&my_matches, (const char *) vvar);
173 	}
174 	switch_mutex_unlock(globals.mutex);
175 
176 	if (my_matches) {
177 		*matches = my_matches;
178 		status = SWITCH_STATUS_SUCCESS;
179 	}
180 
181 	return status;
182 }
183 
list_streams(const char * line,const char * cursor,switch_console_callback_match_t ** matches)184 switch_status_t list_streams(const char *line, const char *cursor, switch_console_callback_match_t **matches)
185 {
186 	return list_streams_full(line, cursor, matches, SWITCH_TRUE);
187 }
188 
do_rand(uint32_t count)189 static int do_rand(uint32_t count)
190 {
191 	int r = 0;
192 
193 	if (count == 0) return 0;
194 
195 	switch_mutex_lock(globals.mutex);
196 	r = (rand() % count) + 1;
197 	switch_mutex_unlock(globals.mutex);
198 
199 	return r;
200 }
201 
flush_video_queue(switch_queue_t * q)202 static void flush_video_queue(switch_queue_t *q)
203 {
204 	void *pop = NULL;
205 
206 	if (switch_queue_size(q) == 0) {
207 		return;
208 	}
209 
210 	while (switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS) {
211 		if (pop) {
212 			switch_image_t *img = (switch_image_t *) pop;
213 			switch_img_free(&img);
214 		} else {
215 			break;
216 		}
217 	}
218 
219 }
220 
read_stream_thread(switch_thread_t * thread,void * obj)221 static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
222 {
223 	volatile local_stream_source_t *s = (local_stream_source_t *) obj;
224 	local_stream_source_t *source = (local_stream_source_t *) s;
225 	switch_file_handle_t fh = { 0 };
226 	char file_buf[128] = "", path_buf[512] = "", last_path[512] = "", png_buf[512] = "", tmp_buf[512] = "";
227 	int fd = -1;
228 	switch_buffer_t *audio_buffer;
229 	switch_byte_t *dist_buf;
230 	switch_size_t used;
231 	int skip = 0;
232 	switch_memory_pool_t *temp_pool = NULL;
233 	uint32_t dir_count = 0, do_shuffle = 0;
234 	char *p;
235 
236 	switch_mutex_lock(globals.mutex);
237 	THREADS++;
238 	switch_mutex_unlock(globals.mutex);
239 
240 	if (!source->prebuf) {
241 		source->prebuf = DEFAULT_PREBUFFER_SIZE;
242 	}
243 
244 	if (source->shuffle) {
245 		do_shuffle = 1;
246 	}
247 
248 	if (source->prebuf < source->abuflen) {
249 		source->prebuf = source->abuflen;
250 	}
251 
252 	switch_queue_create(&source->video_q, 500, source->pool);
253 	switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0);
254 	dist_buf = switch_core_alloc(source->pool, source->prebuf + 10);
255 
256 	switch_thread_rwlock_create(&source->rwlock, source->pool);
257 
258 	if (switch_core_timer_init(&source->timer, source->timer_name, source->interval, (int)source->samples, source->pool) != SWITCH_STATUS_SUCCESS) {
259 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
260 		RUNNING = 0;
261 	}
262 
263 	if (RUNNING) {
264 		source->ready = 1;
265 		switch_mutex_lock(globals.mutex);
266 		switch_core_hash_insert(globals.source_hash, source->name, source);
267 		switch_mutex_unlock(globals.mutex);
268 	}
269 
270 	while (RUNNING && !source->stopped && source->ready) {
271 		const char *fname;
272 
273 		if (source->dir_handle) {
274 			switch_dir_close(source->dir_handle);
275 			source->dir_handle = NULL;
276 		}
277 
278 		if (temp_pool) {
279 			switch_core_destroy_memory_pool(&temp_pool);
280 		}
281 
282 		if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) {
283 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool");
284 			goto done;
285 		}
286 
287 		if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) {
288 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location);
289 			goto done;
290 		}
291 
292 		if (fd > -1) {
293 			dir_count = 0;
294 			while (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
295 				dir_count++;
296 			}
297 			lseek(fd, 0, SEEK_SET);
298 		} else {
299 			dir_count = switch_dir_count(source->dir_handle);
300 		}
301 
302 		if (do_shuffle) {
303 			skip = do_rand(dir_count);
304 			do_shuffle = 0;
305 		}
306 
307 		switch_yield(1000000);
308 
309 		while (RUNNING && !source->stopped) {
310 			switch_size_t olen;
311 			const char *artist = NULL, *title = NULL;
312 			char tmp_space[128] = "";
313 
314 			if (fd > -1) {
315 				char *pb;
316 				if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
317 					if ((pb = strchr(path_buf, '\r')) || (pb = strchr(path_buf, '\n'))) {
318 						*pb = '\0';
319 					}
320 				} else {
321 					close(fd);
322 					fd = -1;
323 					continue;
324 				}
325 			} else {
326 				if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) {
327 					break;
328 				}
329 
330 				switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname);
331 
332 				if (switch_stristr(".loc", path_buf)) {
333 					if ((fd = open(path_buf, O_RDONLY)) < 0) {
334 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
335 						switch_yield(1000000);
336 					}
337 					continue;
338 				}
339 			}
340 
341 
342 			if (dir_count > 1 && !strcmp(last_path, path_buf)) {
343 				continue;
344 			}
345 
346 			if (skip > 0) {
347 				skip--;
348 				continue;
349 			}
350 
351 			switch_set_string(last_path, path_buf);
352 
353 			fname = path_buf;
354 			fh.prebuf = source->prebuf;
355 			fh.pre_buffer_datalen = source->prebuf;
356 
357 			if (switch_core_file_open(&fh,
358 									  (char *) fname,
359 									  source->channels, source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
360 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
361 				switch_yield(1000000);
362 				continue;
363 			}
364 
365 			switch_buffer_zero(audio_buffer);
366 
367 			if (switch_core_file_has_video(&fh, SWITCH_FALSE)) {
368 				flush_video_queue(source->video_q);
369 			}
370 
371 			switch_img_free(&source->cover_art);
372 			switch_set_string(tmp_buf, path_buf);
373 
374 			if ((p = strrchr(tmp_buf, '/'))) {
375 				*p++ = '\0';
376 				switch_snprintf(png_buf, sizeof(png_buf), "%s/art/%s.png", tmp_buf, p);
377 				if (switch_file_exists(png_buf, temp_pool) == SWITCH_STATUS_SUCCESS) {
378 					source->cover_art = switch_img_read_png(png_buf, SWITCH_IMG_FMT_I420);
379 				}
380 			}
381 
382 			source->serno++;
383 			switch_safe_free(source->banner_txt);
384 			title = artist = NULL;
385 
386 			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_ARTIST, &artist);
387 			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_TITLE, &title);
388 
389 			if (!title && !artist) {
390 				char *e, *p, *args[3];
391 				int argc;
392 
393 				switch_set_string(tmp_space, path_buf);
394 				p = tmp_space;
395 
396 				while((e = strchr(p, '/'))) {
397 					*e = '\0';
398 					p = e+1;
399 				}
400 
401 				argc = switch_split(p, '-', args);
402 
403 				if (argc > 0) {
404 					while(*args[0] == ' ') {
405 						args[0]++;
406 					}
407 
408 					while(end_of(args[0]) == ' ') {
409 						end_of(args[0]) = '\0';
410 					}
411 
412 					artist = args[0];
413 
414 					if (argc > 1) {
415 						while(*args[1] == ' ') {
416 							args[1]++;
417 						}
418 						while(end_of(args[1]) == ' ') {
419 							end_of(args[1]) = '\0';
420 						}
421 						title = args[1];
422 					}
423 
424 					if (!title) {
425 						title = artist;
426 						artist = NULL;
427 					}
428 				} else {
429 					title = p;
430 					artist = NULL;
431 				}
432 			}
433 
434 			if (title && (source->cover_art || switch_core_file_has_video(&fh, SWITCH_TRUE))) {
435 				const char *format = "#cccccc:#333333:FreeSans.ttf:3%:";
436 
437 				if (artist) {
438 					source->banner_txt = switch_mprintf("%s%s (%s)", format, title, artist);
439 				} else {
440 					source->banner_txt = switch_mprintf("%s%s", format, title);
441 				}
442 			}
443 
444 
445 			while (RUNNING && !source->stopped) {
446 				int is_open;
447 				switch_file_handle_t *use_fh = &fh;
448 
449 				switch_core_timer_next(&source->timer);
450 				olen = source->samples;
451 
452 				if (source->chime_total) {
453 
454 					if (source->chime_counter > 0) {
455 						source->chime_counter -= (int32_t)source->samples;
456 					}
457 
458 					if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
459 						char *val;
460 
461 						val = source->chime_list[source->chime_cur++];
462 
463 						if (source->chime_cur >= source->chime_total) {
464 							source->chime_cur = 0;
465 						}
466 
467 						if (switch_core_file_open(&source->chime_fh,
468 												  (char *) val,
469 												  source->channels,
470 												  source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
471 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val);
472 						}
473 
474 
475 						if (switch_core_file_has_video(&source->chime_fh, SWITCH_FALSE)) {
476 							flush_video_queue(source->video_q);
477 						}
478 
479 					}
480 
481 					if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
482 						use_fh = &source->chime_fh;
483 					}
484 				}
485 
486 			retry:
487 
488 				if (switch_core_file_has_video(use_fh, SWITCH_TRUE)) {
489 					source->mm = use_fh->mm;
490 				}
491 
492 				source->has_video = switch_core_file_has_video(use_fh, SWITCH_TRUE) || source->cover_art || source->banner_txt;
493 
494 				is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN);
495 
496 				if (source->hup) {
497 					source->hup = 0;
498 					if (is_open) {
499 
500 						switch_core_file_close(use_fh);
501 						flush_video_queue(source->video_q);
502 						switch_buffer_zero(audio_buffer);
503 						if (use_fh == &source->chime_fh) {
504 							source->chime_counter = source->rate * source->chime_freq;
505 							switch_core_file_close(&fh);
506 							use_fh = &fh;
507 						}
508 						goto retry;
509 					}
510 				}
511 
512 				if (is_open) {
513 					int svr = 0;
514 
515 					if (switch_core_has_video() && switch_core_file_has_video(use_fh, SWITCH_TRUE)) {
516 						switch_frame_t vid_frame = { 0 };
517 
518 						if (use_fh == &source->chime_fh && switch_test_flag(&fh, SWITCH_FILE_OPEN) && switch_core_file_has_video(&fh, SWITCH_TRUE)) {
519 							if (switch_core_file_read_video(&fh, &vid_frame, svr) == SWITCH_STATUS_SUCCESS) {
520 								switch_img_free(&vid_frame.img);
521 							}
522 						}
523 
524 						while (switch_core_file_read_video(use_fh, &vid_frame, svr) == SWITCH_STATUS_SUCCESS) {
525 							if (vid_frame.img) {
526 								int flush = 1;
527 
528 								source->has_video = 1;
529 								if (source->total) {
530 									if (switch_queue_trypush(source->video_q, vid_frame.img) == SWITCH_STATUS_SUCCESS) {
531 										vid_frame.img = NULL;
532 										flush = 0;
533 									}
534 								}
535 
536 								if (flush) {
537 									switch_img_free(&vid_frame.img);
538 									flush_video_queue(source->video_q);
539 								}
540 							}
541 						}
542 					} else {
543 						source->has_video = 0;
544 					}
545 
546 					if (switch_test_flag(&fh, SWITCH_FILE_OPEN) && use_fh == &source->chime_fh) {
547 						olen = source->samples;
548 						if (switch_core_file_read(&fh, source->abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
549 							switch_core_file_close(&fh);
550 						}
551 						olen = source->samples;
552 					}
553 
554 					switch_assert(source->abuflen >= olen * 2 * source->channels);
555 
556 					if (switch_core_file_read(use_fh, source->abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
557 						switch_core_file_close(use_fh);
558 						flush_video_queue(source->video_q);
559 
560 						if (use_fh == &source->chime_fh) {
561 							source->chime_counter = source->rate * source->chime_freq;
562 						} else {
563 							is_open = 0;
564 						}
565 					} else {
566 						if (use_fh == &source->chime_fh && source->chime_max) {
567 							source->chime_max_counter += (int32_t)source->samples;
568 							if (source->chime_max_counter >= source->chime_max) {
569 								source->chime_max_counter = 0;
570 								switch_core_file_close(use_fh);
571 								flush_video_queue(source->video_q);
572 								source->chime_counter = source->rate * source->chime_freq;
573 								use_fh = &fh;
574 								goto retry;
575 							}
576 						}
577 
578 						if (source->total) {
579 
580 							if (source->energy_avg && source->agc) {
581 								switch_agc_feed(source->agc, (int16_t *)source->abuf, olen, source->channels);
582 							} else if (source->vol) {
583 								switch_change_sln_volume_granular((int16_t *)source->abuf, olen * source->channels, source->vol);
584 							}
585 
586 							switch_buffer_write(audio_buffer, source->abuf, olen * 2 * source->channels);
587 						} else {
588 							switch_buffer_zero(audio_buffer);
589 						}
590 					}
591 				}
592 
593 				used = switch_buffer_inuse(audio_buffer);
594 
595 				if (!used && !is_open) {
596 					break;
597 				}
598 
599 				if (!source->total) {
600 					flush_video_queue(source->video_q);
601 					switch_buffer_zero(audio_buffer);
602 				} else if (used && (!is_open || used >= source->abuflen)) {
603 					void *pop;
604 					uint32_t bused = 0;
605 					local_stream_context_t *cp = NULL;
606 
607 					switch_assert(source->abuflen <= source->prebuf);
608 					used = switch_buffer_read(audio_buffer, dist_buf, source->abuflen);
609 
610 					switch_mutex_lock(source->mutex);
611 					for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
612 
613 						if (!cp->ready) {
614 							continue;
615 						}
616 
617 						switch_mutex_lock(cp->audio_mutex);
618 
619 						if (switch_test_flag(cp->handle, SWITCH_FILE_OPEN)) {
620 							if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
621 								switch_mutex_unlock(cp->audio_mutex);
622 								continue;
623 							}
624 						}
625 
626 						bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
627 
628 						if (bused > source->samples * 768) {
629 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n",
630 											  cp->func, cp->file, cp->line, bused, (long)source->samples);
631 							switch_buffer_zero(cp->audio_buffer);
632 						} else {
633 							switch_buffer_write(cp->audio_buffer, dist_buf, used);
634 						}
635 						switch_mutex_unlock(cp->audio_mutex);
636 					}
637 					switch_mutex_unlock(source->mutex);
638 
639 
640 					while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
641 						switch_image_t *img;
642 						switch_image_t *imgcp = NULL;
643 
644 						if (!pop) break;
645 
646 						img = (switch_image_t *) pop;
647 
648 						switch_mutex_lock(source->mutex);
649 						if (source->context_list) {
650 							if (source->total == 1) {
651 								if (!switch_test_flag(source->context_list->handle, SWITCH_FILE_FLAG_VIDEO)) {
652 									flush_video_queue(source->context_list->video_q);
653 								} else if (switch_queue_trypush(source->context_list->video_q, img) != SWITCH_STATUS_SUCCESS) {
654 									flush_video_queue(source->context_list->video_q);
655 
656 									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Flushing video queue\n");
657 									if (++source->context_list->video_flushes > 1) {
658 										switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Disconnecting file\n");
659 										source->context_list->ready = 0;
660 									}
661 								} else {
662 									source->context_list->video_flushes = 0;
663 									img = NULL;
664 								}
665 							} else {
666 								for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
667 
668 									if (!cp->ready) {
669 										continue;
670 									}
671 
672 									if (cp->video_q) {
673 										imgcp = NULL;
674 										switch_img_copy(img, &imgcp);
675 										if (imgcp) {
676 											if (!switch_test_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO)) {
677 												flush_video_queue(cp->video_q);
678 											} else if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) {
679 												flush_video_queue(cp->video_q);
680 												switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Flushing video queue\n");
681 												if (++cp->video_flushes > 1) {
682 													switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Disconnecting file\n");
683 													cp->ready = 0;
684 												}
685 											} else {
686 												cp->video_flushes = 0;
687 											}
688 										}
689 									}
690 								}
691 							}
692 						}
693 						switch_mutex_unlock(source->mutex);
694 						switch_img_free(&img);
695 					}
696 				}
697 			}
698 
699 			if (RUNNING && source->shuffle) {
700 				skip = do_rand(dir_count);
701 			}
702 		}
703 
704 		if (source->full_reload) {
705 			if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
706 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name);
707 				if (source->part_reload) {
708 					switch_xml_t cfg, xml, directory, param;
709 					if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
710 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
711 					}
712 					if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) {
713 						for (param = switch_xml_child(directory, "param"); param; param = param->next) {
714 							char *var = (char *) switch_xml_attr_soft(param, "name");
715 							char *val = (char *) switch_xml_attr_soft(param, "value");
716 							if (!strcasecmp(var, "shuffle")) {
717 								source->shuffle = switch_true(val);
718 							} else if (!strcasecmp(var, "chime-freq")) {
719 								int tmp = atoi(val);
720 								if (tmp > 1) {
721 									source->chime_freq = tmp;
722 								}
723 							} else if (!strcasecmp(var, "chime-max")) {
724 								int tmp = atoi(val);
725 								if (tmp > 1) {
726 									source->chime_max = tmp;
727 								}
728 							} else if (!strcasecmp(var, "chime-list")) {
729 								char *list_dup = switch_core_strdup(source->pool, val);
730 								source->chime_total =
731 									switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
732 							} else if (!strcasecmp(var, "interval")) {
733 								int tmp = atoi(val);
734 								if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
735 									source->interval = tmp;
736 								} else {
737 									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
738 													  "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
739 								}
740 							} else if (!strcasecmp(var, "volume")) {
741 								source->vol = atoi(val);
742 								switch_normalize_volume_granular(source->vol);
743 							} else if (!strcasecmp(var, "auto-volume")) {
744 								source->energy_avg = atoi(val);
745 
746 								if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
747 									source->energy_avg = 0;
748 								}
749 							} else if (!strcasecmp(var, "auto-volume-low-point")) {
750 								source->energy_low = atoi(val);
751 
752 								if (!(source->energy_low > -1 && source->energy_avg <= 20000)) {
753 									source->energy_low = 0;
754 								}
755 							}
756 							if (source->chime_max) {
757 								source->chime_max *= source->rate;
758 							}
759 							if (source->chime_total) {
760 								source->chime_counter = source->rate * source->chime_freq;
761 							}
762 						}
763 					}
764 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name);
765 					source->part_reload = 0;
766 					source->full_reload = 0;
767 
768 					if (xml) {
769 						switch_xml_free(xml);
770 					}
771 				}
772 			} else {
773 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name);
774 				switch_thread_rwlock_unlock(source->rwlock);
775 				source->full_reload = 0;
776 				source->part_reload = 0;
777 				if (source->timer.interval) {
778 					switch_core_timer_destroy(&source->timer);
779 				}
780 				launch_streams(source->name);
781 				goto done;
782 			}
783 		}
784 	}
785 
786   done:
787 
788 	if (source->dir_handle) {
789 		switch_dir_close(source->dir_handle);
790 		source->dir_handle = NULL;
791 	}
792 
793 	if (source->timer.interval) {
794 		switch_core_timer_destroy(&source->timer);
795 	}
796 
797 	switch_safe_free(source->banner_txt);
798 
799 	if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) {
800 		switch_core_file_close(&fh);
801 	}
802 
803 	if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
804 		switch_core_file_close(&source->chime_fh);
805 	}
806 
807 	switch_img_free(&source->blank_img);
808 	switch_img_free(&source->logo_img);
809 
810 	source->ready = 0;
811 	switch_mutex_lock(globals.mutex);
812 	switch_core_hash_delete(globals.source_hash, source->name);
813 	switch_mutex_unlock(globals.mutex);
814 
815 	if (source->agc) {
816 		switch_agc_destroy(&source->agc);
817 	}
818 
819 	switch_thread_rwlock_wrlock(source->rwlock);
820 	switch_thread_rwlock_unlock(source->rwlock);
821 
822 	switch_buffer_destroy(&audio_buffer);
823 
824 	flush_video_queue(source->video_q);
825 
826 	if (fd > -1) {
827 		close(fd);
828 	}
829 
830 	if (temp_pool) {
831 		switch_core_destroy_memory_pool(&temp_pool);
832 	}
833 
834 	switch_core_destroy_memory_pool(&source->pool);
835 
836 	switch_mutex_lock(globals.mutex);
837 	THREADS--;
838 	switch_mutex_unlock(globals.mutex);
839 
840 	return NULL;
841 }
842 
local_stream_file_open(switch_file_handle_t * handle,const char * path)843 static switch_status_t local_stream_file_open(switch_file_handle_t *handle, const char *path)
844 {
845 	local_stream_context_t *context;
846 	local_stream_source_t *source;
847 	char *alt_path = NULL;
848 	switch_status_t status = SWITCH_STATUS_SUCCESS;
849 	switch_memory_pool_t *pool;
850 
851 	/* already buffering a step back, so always disable it */
852 	handle->pre_buffer_datalen = 0;
853 
854 	if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
855 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n");
856 		return SWITCH_STATUS_FALSE;
857 	}
858 
859   top:
860 
861 	alt_path = switch_mprintf("%s/%d", path, handle->samplerate);
862 
863 	if ((source = get_source(alt_path))) {
864 		path = alt_path;
865 	} else {
866 		source = get_source(path);
867 	}
868 
869 
870 	if (!source) {
871 		if (!switch_stristr("default", alt_path) && !switch_stristr("default", path)) {
872 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown source %s, trying 'default'\n", path);
873 			free(alt_path);
874 			path = "default";
875 			goto top;
876 		}
877 	}
878 
879 	if (!source) {
880 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path);
881 		status = SWITCH_STATUS_FALSE;
882 		goto end;
883 	}
884 
885 	//if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
886 	//	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
887 	//	abort();
888 	//}
889 
890 	pool = handle->memory_pool;
891 
892 	if ((context = switch_core_alloc(pool, sizeof(*context))) == 0) {
893 		abort();
894 	}
895 
896 	context->pool = pool;
897 
898 	switch_queue_create(&context->video_q, 40, context->pool);
899 
900 	handle->samples = 0;
901 	handle->samplerate = source->rate;
902 	handle->channels = source->channels;
903 	handle->format = 0;
904 	handle->sections = 0;
905 	handle->seekable = 0;
906 	handle->speed = 0;
907 	handle->private_info = context;
908 	handle->interval = source->interval;
909 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening Stream [%s] %dhz\n", path, handle->samplerate);
910 
911 	switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool);
912 	if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) {
913 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
914 		status = SWITCH_STATUS_MEMERR;
915 		goto end;
916 	}
917 
918 	if (!switch_core_has_video() || !source->has_video ||
919 		(switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) && !source->has_video && !source->blank_img && !source->cover_art && !source->banner_txt)) {
920 		switch_clear_flag_locked(handle, SWITCH_FILE_FLAG_VIDEO);
921 	}
922 
923 	context->source = source;
924 	context->file = handle->file;
925 	context->func = handle->func;
926 	context->line = handle->line;
927 	context->handle = handle;
928 	context->ready = 1;
929 	switch_mutex_lock(source->mutex);
930 	context->next = source->context_list;
931 	source->context_list = context;
932 	source->total++;
933 	if (source->total == 1) {
934 		source->first = 1;
935 	}
936 	switch_mutex_unlock(source->mutex);
937 
938   end:
939 
940 	switch_safe_free(alt_path);
941 	return status;
942 }
943 
local_stream_file_close(switch_file_handle_t * handle)944 static switch_status_t local_stream_file_close(switch_file_handle_t *handle)
945 {
946 	local_stream_context_t *context = NULL, *last = NULL, *cp = NULL;
947 	local_stream_source_t *source;
948 
949 	context = handle->private_info;
950 	switch_assert(context);
951 
952 	//pool = context->pool;
953 	source = context->source;
954 
955 	switch_mutex_lock(source->mutex);
956 	switch_clear_flag_locked(handle, SWITCH_FILE_OPEN);
957 	context->ready = 0;
958 
959 	for (cp = source->context_list; cp; cp = cp->next) {
960 		if (cp == context) {
961 			if (last) {
962 				last->next = cp->next;
963 			} else {
964 				source->context_list = cp->next;
965 			}
966 			break;
967 		}
968 		last = cp;
969 	}
970 
971 	switch_mutex_lock(context->audio_mutex);
972 
973 	if (source->has_video) {
974 		flush_video_queue(context->video_q);
975 		switch_queue_trypush(context->video_q, NULL);
976 		switch_queue_interrupt_all(context->video_q);
977 		flush_video_queue(context->video_q);
978 	}
979 
980 	source->total--;
981 
982 	switch_img_free(&context->banner_img);
983 	switch_buffer_destroy(&context->audio_buffer);
984 	switch_mutex_unlock(context->audio_mutex);
985 	//switch_core_destroy_memory_pool(&pool);
986 
987 	context->handle = NULL;
988 	handle->private_info = NULL;
989 	switch_mutex_unlock(source->mutex);
990 
991 	switch_thread_rwlock_unlock(source->rwlock);
992 
993 	return SWITCH_STATUS_SUCCESS;
994 }
995 
local_stream_file_read_video(switch_file_handle_t * handle,switch_frame_t * frame,switch_video_read_flag_t flags)996 static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
997 {
998 	void *pop;
999 	local_stream_context_t *context = handle->private_info;
1000 	switch_status_t status;
1001 	switch_time_t now;
1002 	unsigned int fps = (unsigned int)ceil(handle->mm.fps);
1003 	unsigned int min_qsize = fps / 2;
1004 	unsigned int buf_qsize = 5;
1005 
1006 	if (!(context->ready && context->source->ready)) {
1007 		return SWITCH_STATUS_FALSE;
1008 	}
1009 
1010 	if (!context->source->has_video) {
1011 		if (frame) {
1012 			switch_image_t *src_img = context->source->cover_art;
1013 
1014 			if (!src_img) {
1015 				src_img = context->source->blank_img;
1016 			}
1017 
1018 			if (src_img) {
1019 				switch_image_t *img = NULL;
1020 
1021 				if (context->sent_png && --context->sent_png > 0) {
1022 					return SWITCH_STATUS_BREAK;
1023 				}
1024 
1025 				context->sent_png = 50;
1026 				switch_img_copy(src_img, &img);
1027 
1028 				if (context->last_w && context->last_h) {
1029 					switch_img_fit(&img, context->last_w, context->last_h, SWITCH_FIT_SIZE);
1030 				}
1031 
1032 				frame->img = img;
1033 				goto got_img;
1034 			}
1035 		}
1036 		return SWITCH_STATUS_IGNORE;
1037 	}
1038 
1039 	if ((flags & SVR_CHECK)) {
1040 		return SWITCH_STATUS_BREAK;
1041 	}
1042 
1043 	if (handle->mm.fps >= context->source->mm.source_fps) {
1044 		min_qsize = 1;
1045 		buf_qsize = 1;
1046 	}
1047 
1048 	while(context->ready && context->source->ready && switch_queue_size(context->video_q) > min_qsize) {
1049 		if (switch_queue_trypop(context->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
1050 			switch_image_t *img = (switch_image_t *) pop;
1051 			switch_img_free(&img);
1052 		}
1053 	}
1054 
1055 	if (!(context->ready && context->source->ready)) {
1056 		return SWITCH_STATUS_FALSE;
1057 	}
1058 
1059 	while (!(flags & SVR_BLOCK) && switch_queue_size(context->video_q) < buf_qsize) {
1060 		return SWITCH_STATUS_BREAK;
1061 	}
1062 
1063 	if ((flags & SVR_BLOCK)) {
1064 		status = switch_queue_pop(context->video_q, &pop);
1065 	} else {
1066 		status = switch_queue_trypop(context->video_q, &pop);
1067 	}
1068 
1069 	if (status == SWITCH_STATUS_SUCCESS) {
1070 		if (!pop) {
1071 			return SWITCH_STATUS_FALSE;
1072 		}
1073 
1074 		frame->img = (switch_image_t *) pop;
1075 		context->sent_png = 0;
1076 		if (frame->img->d_w != context->last_w || frame->img->d_h != context->last_h) {
1077 			context->newres = 1;
1078 		}
1079 		context->last_w = frame->img->d_w;
1080 		context->last_h = frame->img->d_h;
1081 		goto got_img;
1082 	}
1083 
1084 	return (flags & SVR_FLUSH) ? SWITCH_STATUS_BREAK : status;
1085 
1086  got_img:
1087 
1088 	if (context->pop_count > 0) {
1089 		switch_rgb_color_t bgcolor = { 0 };
1090 		switch_color_set_rgb(&bgcolor, "#000000");
1091 		switch_img_fill(frame->img, 0, 0, frame->img->d_w, frame->img->d_h, &bgcolor);
1092 		context->pop_count--;
1093 	}
1094 
1095 	now = switch_micro_time_now();
1096 
1097 	if (context->banner_img) {
1098 		if (now >= context->banner_timeout) {
1099 			switch_img_free(&context->banner_img);
1100 		}
1101 	}
1102 
1103 	if (context->serno != context->source->serno) {
1104 		switch_img_free(&context->banner_img);
1105 		context->banner_timeout = 0;
1106 		context->serno = context->source->serno;
1107 		context->pop_count = 5;
1108 	}
1109 
1110 	if (context->source->banner_txt) {
1111 		if (!context->banner_timeout || context->banner_timeout >= now) {
1112 			if (context->newres) {
1113 				switch_img_free(&context->banner_img);
1114 				context->newres = 0;
1115 			}
1116 			if (!context->banner_img) {
1117 				context->banner_img = switch_img_write_text_img(context->last_w, context->last_h, SWITCH_TRUE, context->source->banner_txt);
1118 				context->banner_timeout = now + 5000000;
1119 			}
1120 		}
1121 	} else {
1122 		if (context->banner_img) {
1123 			switch_img_free(&context->banner_img);
1124 		}
1125 		context->banner_timeout = 0;
1126 	}
1127 
1128 	if (frame->img && context->banner_img && frame->img->d_w >= context->banner_img->d_w) {
1129 		switch_img_overlay(frame->img, context->banner_img, 0, frame->img->d_h - context->banner_img->d_h, context->source->text_opacity);
1130 	}
1131 
1132 	if (frame->img && context->source->logo_img &&
1133 		(context->source->logo_always || context->banner_img) && frame->img->d_w >= context->source->logo_img->d_w) {
1134 		int x = 0, y = 0;
1135 
1136 		switch_img_find_position(context->source->logo_pos,
1137 								 frame->img->d_w, frame->img->d_h,
1138 								 context->source->logo_img->d_w, context->source->logo_img->d_h,
1139 								 &x, &y);
1140 
1141 		if (context->banner_img) {
1142 			y -= context->banner_img->d_h;
1143 		}
1144 
1145 		switch_img_overlay(frame->img, context->source->logo_img, x, y, context->source->logo_opacity);
1146 	}
1147 
1148 	return SWITCH_STATUS_SUCCESS;
1149 }
1150 
local_stream_file_read(switch_file_handle_t * handle,void * data,size_t * len)1151 static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void *data, size_t *len)
1152 {
1153 	local_stream_context_t *context = handle->private_info;
1154 	switch_size_t bytes = 0;
1155 	size_t need;
1156 
1157 	if (!(context->ready && context->source->ready)) {
1158 		*len = 0;
1159 		return SWITCH_STATUS_FALSE;
1160 	}
1161 
1162 	if (!context->source->has_video)  {
1163 		if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
1164 			switch_clear_flag_locked(handle, SWITCH_FILE_FLAG_VIDEO);
1165 		}
1166 	}
1167 
1168 	switch_mutex_lock(context->audio_mutex);
1169 	need = *len * 2 * context->source->channels;
1170 
1171 	if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) {
1172 		*len = bytes / 2 / context->source->channels;
1173 	} else {
1174 		size_t blank;
1175 
1176 		switch_assert(handle->samplerate <= 48000);
1177 		switch_assert(handle->real_channels <= 2);
1178 
1179 		blank = (handle->samplerate / 4) * 2 * handle->real_channels;
1180 
1181 		if (need > blank) {
1182 			need = blank;
1183 		}
1184 
1185 		memset(data, 0, need);
1186 		*len = need / 2 / context->source->channels;
1187 	}
1188 	switch_mutex_unlock(context->audio_mutex);
1189 	handle->sample_count += *len;
1190 
1191 	return SWITCH_STATUS_SUCCESS;
1192 }
1193 
1194 /* Registration */
1195 
1196 static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
1197 
launch_thread(const char * name,const char * path,switch_xml_t directory)1198 static void launch_thread(const char *name, const char *path, switch_xml_t directory)
1199 {
1200 	local_stream_source_t *source = NULL;
1201 	switch_memory_pool_t *pool;
1202 	switch_xml_t param;
1203 	switch_thread_t *thread;
1204 	switch_threadattr_t *thd_attr = NULL;
1205 
1206 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
1207 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
1208 		abort();
1209 	}
1210 	source = switch_core_alloc(pool, sizeof(*source));
1211 	assert(source != NULL);
1212 	source->pool = pool;
1213 
1214 	source->name = switch_core_strdup(source->pool, name);
1215 	source->location = switch_core_strdup(source->pool, path);
1216 	source->rate = 8000;
1217 	source->interval = 20;
1218 	source->channels = 1;
1219 	source->timer_name = "soft";
1220 	source->prebuf = DEFAULT_PREBUFFER_SIZE;
1221 	source->stopped = 0;
1222 	source->hup = 0;
1223 	source->chime_freq = 30;
1224 	source->logo_opacity = source->text_opacity = 100;
1225 
1226 	for (param = switch_xml_child(directory, "param"); param; param = param->next) {
1227 		char *var = (char *) switch_xml_attr_soft(param, "name");
1228 		char *val = (char *) switch_xml_attr_soft(param, "value");
1229 
1230 		if (!strcasecmp(var, "rate")) {
1231 			int tmp = atoi(val);
1232 			if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
1233 				source->rate = tmp;
1234 			}
1235 		} else if (!strcasecmp(var, "shuffle")) {
1236 			source->shuffle = switch_true(val);
1237 		} else if (!strcasecmp(var, "prebuf")) {
1238 			int tmp = atoi(val);
1239 			if (tmp > 0) {
1240 				source->prebuf = (uint32_t) tmp;
1241 			}
1242 		} else if (!strcasecmp(var, "channels")) {
1243 			int tmp = atoi(val);
1244 			if (tmp == 1 || tmp == 2) {
1245 				source->channels = (uint8_t) tmp;
1246 			}
1247 		} else if (!strcasecmp(var, "chime-freq")) {
1248 			int tmp = atoi(val);
1249 			if (tmp > 1) {
1250 				source->chime_freq = tmp;
1251 			}
1252 		} else if (!strcasecmp(var, "chime-max")) {
1253 			int tmp = atoi(val);
1254 			if (tmp > 1) {
1255 				source->chime_max = tmp;
1256 			}
1257 		} else if (!strcasecmp(var, "chime-list")) {
1258 			char *list_dup = switch_core_strdup(source->pool, val);
1259 			source->chime_total =
1260 				switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
1261 		} else if (!strcasecmp(var, "interval")) {
1262 			int tmp = atoi(val);
1263 			if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
1264 				source->interval = tmp;
1265 			} else {
1266 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
1267 								  "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
1268 			}
1269 		} else if (!strcasecmp(var, "timer-name")) {
1270 			source->timer_name = switch_core_strdup(source->pool, val);
1271 		} else if (!strcasecmp(var, "blank-img") && !zstr(val)) {
1272 			source->blank_img = switch_img_read_png(val, SWITCH_IMG_FMT_I420);
1273 		} else if (!strcasecmp(var, "logo-img") && !zstr(val)) {
1274 			source->logo_img = switch_img_read_png(val, SWITCH_IMG_FMT_ARGB);
1275 		} else if (!strcasecmp(var, "logo-always") && !zstr(val)) {
1276 			source->logo_always = switch_true(val);
1277 		} else if (!strcasecmp(var, "logo-position") && !zstr(val)) {
1278 			source->logo_pos = parse_img_position(val);
1279 		} else if (!strcasecmp(var, "logo-opacity") && !zstr(val)) {
1280 			source->logo_opacity = atoi(val);
1281 			if (source->logo_opacity < 0 || source->logo_opacity > 100) {
1282 				source->logo_opacity = 0;
1283 			}
1284 		} else if (!strcasecmp(var, "text-opacity") && !zstr(val)) {
1285 			source->text_opacity = atoi(val);
1286 			if (source->text_opacity < 0 || source->text_opacity > 100) {
1287 				source->text_opacity = 0;
1288 			}
1289 		} else if (!strcasecmp(var, "volume")) {
1290 			source->vol = atoi(val);
1291 			switch_normalize_volume_granular(source->vol);
1292 		} else if (!strcasecmp(var, "auto-volume")) {
1293 			source->energy_avg = atoi(val);
1294 
1295 			if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
1296 				source->energy_avg = 0;
1297 			}
1298 		} else if (!strcasecmp(var, "auto-volume-low-point")) {
1299 			source->energy_low = atoi(val);
1300 
1301 			if (!(source->energy_low > -1 && source->energy_avg <= 20000)) {
1302 				source->energy_low = 0;
1303 			}
1304 		}
1305 	}
1306 
1307 	if (source->chime_max) {
1308 		source->chime_max *= source->rate;
1309 	}
1310 
1311 	if (source->chime_total) {
1312 		source->chime_counter = source->rate * source->chime_freq;
1313 	}
1314 
1315 	source->samples = switch_samples_per_packet(source->rate, source->interval);
1316 	source->abuflen = (source->samples * 2 * source->channels);
1317 	source->abuf = switch_core_alloc(source->pool, source->abuflen + 1024);
1318 	switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool);
1319 	switch_threadattr_create(&thd_attr, source->pool);
1320 	switch_threadattr_detach_set(thd_attr, 1);
1321 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
1322 	switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool);
1323 }
1324 
launch_streams(const char * name)1325 static int launch_streams(const char *name)
1326 {
1327 	switch_xml_t cfg, xml, directory;
1328 	int x = 0;
1329 
1330 	if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
1331 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
1332 		return 0;
1333 	}
1334 
1335 	if (zstr(name)) {
1336 		for (directory = switch_xml_child(cfg, "directory"); directory; directory = directory->next) {
1337 			char *name_attr = (char *) switch_xml_attr(directory, "name");
1338 			char *path = (char *) switch_xml_attr(directory, "path");
1339 			launch_thread(name_attr, path, directory);
1340 			x++;
1341 		}
1342 	} else if ((directory = switch_xml_find_child(cfg, "directory", "name", name))) {
1343 		char *path = (char *) switch_xml_attr(directory, "path");
1344 		launch_thread(name, path, directory);
1345 		x++;
1346 	}
1347 	switch_xml_free(xml);
1348 
1349 	return x;
1350 }
1351 
event_handler(switch_event_t * event)1352 static void event_handler(switch_event_t *event)
1353 {
1354 	RUNNING = 0;
1355 }
1356 
1357 #define LOCAL_STREAM_SYNTAX "<show|start|reload|stop|hup> <local_stream_name>"
SWITCH_STANDARD_API(local_stream_function)1358 SWITCH_STANDARD_API(local_stream_function)
1359 {
1360 	local_stream_source_t *source = NULL;
1361 	char *mycmd = NULL, *argv[5] = { 0 };
1362 	char *local_stream_name = NULL;
1363 	int argc = 0;
1364 	int ok = 0;
1365 
1366 	if (zstr(cmd)) {
1367 		goto usage;
1368 	}
1369 
1370 	if (!(mycmd = strdup(cmd))) {
1371 		goto usage;
1372 	}
1373 
1374 	if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
1375 		goto usage;
1376 	}
1377 
1378 	local_stream_name = argv[1];
1379 
1380 
1381 	if (!strcasecmp(argv[0], "hup") && local_stream_name) {
1382 		if ((source = get_source(local_stream_name))) {
1383 			source->hup = 1;
1384 			stream->write_function(stream, "+OK hup stream: %s", source->name);
1385 			switch_thread_rwlock_unlock(source->rwlock);
1386 		}
1387 	} else if (!strcasecmp(argv[0], "vol") && local_stream_name) {
1388 		if ((source = get_source(local_stream_name))) {
1389 			if (argv[2]) {
1390 				if (!strncasecmp(argv[2], "auto:", 5)) {
1391 					char *p;
1392 					source->energy_avg = atoi(argv[2] + 5);
1393 
1394 					if ((p = strchr(argv[2] + 5, ':'))) {
1395 						int tmp = 0;
1396 						p++;
1397 						tmp = atoi(p);
1398 
1399 						if ((tmp > -1 && tmp <= 20000)) {
1400 							source->energy_low = tmp;
1401 						} else {
1402 							stream->write_function(stream, "-ERR invalid auto-volume low-energy level for stream: %s\n", source->name);
1403 						}
1404 					}
1405 
1406 					if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
1407 						source->energy_avg = 0;
1408 						stream->write_function(stream, "-ERR invalid auto-volume level for stream: %s\n", source->name);
1409 					} else {
1410 						if (!source->agc) {
1411 							switch_agc_create(&source->agc, source->energy_avg, source->energy_low, 500, 3, (1000 / source->interval) * 2);
1412 						} else {
1413 							switch_agc_set_energy_avg(source->agc, source->energy_avg);
1414 							switch_agc_set_energy_low(source->agc, source->energy_low);
1415 						}
1416 					}
1417 				} else {
1418 					source->vol = atoi(argv[2]);
1419 					switch_normalize_volume_granular(source->vol);
1420 					if (source->agc) {
1421 						switch_agc_destroy(&source->agc);
1422 					}
1423 					source->energy_avg = 0;
1424 				}
1425 			}
1426 
1427 			if (source->energy_avg) {
1428 				stream->write_function(stream, "+OK Auto-Volume stream: %s is %d/%d", source->name, source->energy_avg, source->energy_low);
1429 			} else {
1430 				stream->write_function(stream, "+OK vol stream: %s is %d", source->name, source->vol);
1431 			}
1432 			switch_thread_rwlock_unlock(source->rwlock);
1433 		}
1434 	} else if (!strcasecmp(argv[0], "stop") && local_stream_name) {
1435 		if ((source = get_source(local_stream_name))) {
1436 			source->stopped = 1;
1437 			stream->write_function(stream, "+OK");
1438 			switch_thread_rwlock_unlock(source->rwlock);
1439 		} else {
1440 			stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
1441 		}
1442 	} else if (!strcasecmp(argv[0], "reload") && local_stream_name) {
1443 		if ((source = get_source(local_stream_name))) {
1444 			source->full_reload = 1;
1445 			source->part_reload = 1;
1446 			source->hup = 1;
1447 			stream->write_function(stream, "+OK");
1448 			switch_thread_rwlock_unlock(source->rwlock);
1449 		} else {
1450 			stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
1451 		}
1452 	} else if (!strcasecmp(argv[0], "start") && local_stream_name) {
1453 		if ((source = get_source(local_stream_name))) {
1454 			source->stopped = 0;
1455 			stream->write_function(stream, "+OK stream: %s", source->name);
1456 			switch_thread_rwlock_unlock(source->rwlock);
1457 		} else {
1458 			if ((ok = launch_streams(local_stream_name))) {
1459 				stream->write_function(stream, "+OK stream: %s", local_stream_name);
1460 			}
1461 		}
1462 
1463 	} else if (!strcasecmp(argv[0], "show")) {
1464 		switch_hash_index_t *hi;
1465 		const void *var;
1466 		void *val;
1467 		switch_bool_t xml = SWITCH_FALSE;
1468 
1469 		if (argc == 1) {
1470 			switch_mutex_lock(globals.mutex);
1471 			for (hi = switch_core_hash_first(globals.source_hash); hi; hi = switch_core_hash_next(&hi)) {
1472 				switch_core_hash_this(hi, &var, NULL, &val);
1473 				if ((source = (local_stream_source_t *) val)) {
1474 					stream->write_function(stream, "%s,%s\n", source->name, source->location);
1475 				}
1476 			}
1477 			switch_mutex_unlock(globals.mutex);
1478 		} else {
1479 			if (argc == 4 && !strcasecmp("xml", argv[3])) {
1480 				xml = SWITCH_TRUE;
1481 			}
1482 
1483 			if ((source = get_source(local_stream_name))) {
1484 				if (xml) {
1485 					stream->write_function(stream, "<?xml version=\"1.0\"?>\n<local_stream name=\"%s\">\n", source->name);
1486 					stream->write_function(stream, "  <location>%s</location>\n", source->location);
1487 					stream->write_function(stream, "  <channels>%d</channels>\n", source->channels);
1488 					stream->write_function(stream, "  <rate>%d</rate>\n", source->rate);
1489 					stream->write_function(stream, "  <interval>%d<interval>\n", source->interval);
1490 					stream->write_function(stream, "  <samples>%d</samples>\n", source->samples);
1491 					stream->write_function(stream, "  <prebuf>%d</prebuf>\n", source->prebuf);
1492 					stream->write_function(stream, "  <timer>%s</timer>\n", source->timer_name);
1493 					stream->write_function(stream, "  <total>%d</total>\n", source->total);
1494 					stream->write_function(stream, "  <shuffle>%s</shuffle>\n", (source->shuffle) ? "true" : "false");
1495 					stream->write_function(stream, "  <ready>%s</ready>\n", (source->ready) ? "true" : "false");
1496 					stream->write_function(stream, "  <stopped>%s</stopped>\n", (source->stopped) ? "true" : "false");
1497 					stream->write_function(stream, "</local_stream>\n");
1498 				} else {
1499 					stream->write_function(stream, "%s\n", source->name);
1500 					stream->write_function(stream, "  location: %s\n", source->location);
1501 					stream->write_function(stream, "  channels: %d\n", source->channels);
1502 					stream->write_function(stream, "  rate:     %d\n", source->rate);
1503 					stream->write_function(stream, "  interval: %d\n", source->interval);
1504 					stream->write_function(stream, "  samples:  %d\n", source->samples);
1505 					stream->write_function(stream, "  prebuf:   %d\n", source->prebuf);
1506 					stream->write_function(stream, "  timer:    %s\n", source->timer_name);
1507 					stream->write_function(stream, "  total:    %d\n", source->total);
1508 					stream->write_function(stream, "  shuffle:  %s\n", (source->shuffle) ? "true" : "false");
1509 					stream->write_function(stream, "  ready:    %s\n", (source->ready) ? "true" : "false");
1510 					stream->write_function(stream, "  stopped:  %s\n", (source->stopped) ? "true" : "false");
1511 					stream->write_function(stream, "  reloading: %s\n", (source->full_reload) ? "true" : "false");
1512 				}
1513 				switch_thread_rwlock_unlock(source->rwlock);
1514 			} else {
1515 				stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
1516 			}
1517 		}
1518 	}
1519 
1520 	goto done;
1521 
1522  usage:
1523 	stream->write_function(stream, "-USAGE: %s\n", LOCAL_STREAM_SYNTAX);
1524 
1525   done:
1526 
1527 	switch_safe_free(mycmd);
1528 	return SWITCH_STATUS_SUCCESS;
1529 }
1530 
SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load)1531 SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load)
1532 {
1533 	switch_api_interface_t *commands_api_interface;
1534 	switch_file_interface_t *file_interface;
1535 
1536 	supported_formats[0] = "local_stream";
1537 
1538 
1539 	memset(&globals, 0, sizeof(globals));
1540 	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool);
1541 	switch_core_hash_init(&globals.source_hash);
1542 	if (!launch_streams(NULL)) {
1543 		return SWITCH_STATUS_GENERR;
1544 	}
1545 
1546 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
1547 	file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
1548 	file_interface->interface_name = modname;
1549 	file_interface->extens = supported_formats;
1550 	file_interface->file_open = local_stream_file_open;
1551 	file_interface->file_close = local_stream_file_close;
1552 	file_interface->file_read = local_stream_file_read;
1553 
1554 	if (switch_core_has_video()) {
1555 		file_interface->file_read_video = local_stream_file_read_video;
1556 	}
1557 
1558 	if (switch_event_bind(modname, SWITCH_EVENT_SHUTDOWN, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
1559 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind event handler!\n");
1560 	}
1561 
1562 	SWITCH_ADD_API(commands_api_interface, "local_stream", "manage local streams", local_stream_function, LOCAL_STREAM_SYNTAX);
1563 	//	switch_console_set_complete("add sofia profile ::sofia::list_profiles start");
1564 	switch_console_set_complete("add local_stream show ::console::list_streams as xml");
1565 	switch_console_set_complete("add local_stream start");
1566 	switch_console_set_complete("add local_stream reload ::console::list_streams");
1567 	switch_console_set_complete("add local_stream stop ::console::list_streams");
1568 	switch_console_set_complete("add local_stream hup ::console::list_streams");
1569 	switch_console_add_complete_func("::console::list_streams", list_streams);
1570 	/* indicate that the module should continue to be loaded */
1571 
1572 	return SWITCH_STATUS_SUCCESS;
1573 }
1574 
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_local_stream_shutdown)1575 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_local_stream_shutdown)
1576 {
1577 	RUNNING = 0;
1578 	switch_event_unbind_callback(event_handler);
1579 
1580 	while (THREADS > 0) {
1581 		switch_yield(100000);
1582 	}
1583 
1584 	switch_core_hash_destroy(&globals.source_hash);
1585 	return SWITCH_STATUS_SUCCESS;
1586 }
1587 
1588 /* For Emacs:
1589  * Local Variables:
1590  * mode:c
1591  * indent-tabs-mode:t
1592  * tab-width:4
1593  * c-basic-offset:4
1594  * End:
1595  * For VIM:
1596  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1597  */
1598