Exemplo n.º 1
0
static switch_status_t route_lookup(char *dn, easyroute_results_t *results, int noat, char *separator)
{
	switch_status_t sstatus = SWITCH_STATUS_SUCCESS;
	char *sql = NULL;
	route_callback_t pdata;

	if (!switch_odbc_available()) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
						  "mod_easyroute requires core ODBC support. Please refer to the documentation on how to enable this\n");
		return sstatus;
	}

	memset(&pdata, 0, sizeof(pdata));
	if (!globals.custom_query) {
		sql = switch_mprintf(SQL_LOOKUP, dn);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Doing static Query\n[%s]\n", sql);
	} else {
		sql = switch_mprintf(globals.custom_query, dn);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Doing custom Query\n[%s]\n", sql);
	}

	if (globals.mutex) {
		switch_mutex_lock(globals.mutex);
	}
	/* Do the Query */
	if (switch_odbc_handle_callback_exec(globals.master_odbc, sql, route_callback, &pdata, NULL) == SWITCH_ODBC_SUCCESS) {
		char tmp_profile[129];
		char tmp_gateway[129];

		if (zstr(pdata.limit)) {
			switch_set_string(results->limit, "9999");
		} else {
			switch_set_string(results->limit, pdata.limit);
		}

		if (zstr(pdata.techprofile)) {
			switch_set_string(tmp_profile, globals.default_techprofile);
		} else {
			switch_set_string(tmp_profile, pdata.techprofile);
		}

		if (zstr(pdata.gateway)) {
			switch_set_string(tmp_gateway, globals.default_gateway);
		} else {
			switch_set_string(tmp_gateway, pdata.gateway);
		}

		if (zstr(pdata.translated)) {
			switch_set_string(results->translated, dn);
		} else {
			switch_set_string(results->translated, pdata.translated);
		}
		if (noat) {
			switch_snprintf(results->dialstring, 256, "%s/%s%s", tmp_profile, results->translated, tmp_gateway);
		} else if (separator) {
			switch_snprintf(results->dialstring, 256, "%s/%s%s%s", tmp_profile, results->translated, separator, tmp_gateway);
		} else {
			switch_snprintf(results->dialstring, 256, "%s/%s@%s", tmp_profile, results->translated, tmp_gateway);
		}
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "THE ROUTE [%s]\n", results->dialstring);

		if (zstr(pdata.group)) {
			switch_set_string(results->group, "");
		} else {
			switch_set_string(results->group, pdata.group);
		}

		if (zstr(pdata.acctcode)) {
			switch_set_string(results->acctcode, "");
		} else {
			switch_set_string(results->acctcode, pdata.acctcode);
		}
	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DB Error Setting Default Route!\n");
		switch_set_string(results->limit, "9999");
		if (noat) {
			switch_snprintf(results->dialstring, 256, "%s/%s%s", globals.default_techprofile, dn, globals.default_gateway);
		} else if (separator) {
			switch_snprintf(results->dialstring, 256, "%s/%s%s%s", globals.default_techprofile, dn, separator, globals.default_gateway);
		} else {
			switch_snprintf(results->dialstring, 256, "%s/%s@%s", globals.default_techprofile, dn, globals.default_gateway);
		}
		switch_set_string(results->group, "");
		switch_set_string(results->acctcode, "");
	}

	switch_safe_free(sql);

	if (globals.mutex) {
		switch_mutex_unlock(globals.mutex);
	}
	return sstatus;
}
Exemplo n.º 2
0
static switch_status_t load_config(switch_bool_t reload)
{
    switch_status_t status = SWITCH_STATUS_SUCCESS;
    switch_xml_t cfg, xml = NULL, settings, param, x_profiles, x_profile;
    switch_cache_db_handle_t *dbh = NULL;

    if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
        return SWITCH_STATUS_TERM;
    }

    switch_mutex_lock(globals.mutex);
    if ((settings = switch_xml_child(cfg, "settings"))) {
        for (param = switch_xml_child(settings, "param"); param; param = param->next) {
            char *var = (char *) switch_xml_attr_soft(param, "name");
            char *val = (char *) switch_xml_attr_soft(param, "value");

            if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
                if (switch_odbc_available()) {
                    switch_set_string(globals.odbc_dsn, val);
                    if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
                        *globals.odbc_user++ = '\0';
                        if ((globals.odbc_pass = strchr(globals.odbc_user, ':'))) {
                            *globals.odbc_pass++ = '\0';
                        }
                    }
                } else {
                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
                }
            } else if (!strcasecmp(var, "dbname") && !zstr(val)) {
                globals.dbname = switch_core_strdup(globals.pool, val);
            }

            if (!strcasecmp(var, "debug")) {
                globals.debug = atoi(val);
            }
        }
    }

    if ((x_profiles = switch_xml_child(cfg, "profiles"))) {
        for (x_profile = switch_xml_child(x_profiles, "profile"); x_profile; x_profile = x_profile->next) {
            load_profile(switch_xml_attr_soft(x_profile, "name"));
        }
    }

    if (zstr(globals.odbc_dsn) && zstr(globals.dbname)) {
        globals.dbname = switch_core_sprintf(globals.pool, "directory");
    }

    dbh = directory_get_db_handle();
    if (dbh) {
        if (!reload) {
            switch_cache_db_test_reactive(dbh, "delete from directory_search where uuid != '' and name_visible != '' ", "drop table directory_search", dir_sql);
        }
        switch_cache_db_release_db_handle(&dbh);
    } else {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!2\n");
        status = SWITCH_STATUS_TERM;
        goto end;
    }
end:
    switch_mutex_unlock(globals.mutex);

    switch_xml_free(xml);
    return status;
}
Exemplo n.º 3
0
static void *SWITCH_THREAD_FUNC switch_nat_multicast_runtime(switch_thread_t * thread, void *obj)
{
	char *buf = NULL;
	char newip[16] = "";
	char *pos;
	switch_event_t *event = NULL;

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NAT thread started\n");

	buf = (char *) malloc(MULTICAST_BUFFSIZE);
	switch_assert(buf);
	nat_globals_perm.running = 1;

	while (nat_globals_perm.running == 1) {
		size_t len = MULTICAST_BUFFSIZE;
		switch_status_t status;
		switch_bool_t do_repub = SWITCH_FALSE;
		memset(buf, 0, len);

		status = switch_socket_recvfrom(nat_globals_perm.maddress, nat_globals_perm.msocket, 0, buf, &len);

		if (!len) {
			if (SWITCH_STATUS_IS_BREAK(status)) {
				switch_yield(5000000);
				continue;
			}

			break;
		}

		if (nat_globals.nat_type == SWITCH_NAT_TYPE_UPNP) {
			/* look for our desc URL and servicetype in the packet */
			if (strstr(buf, nat_globals.descURL) && (buf == NULL || strstr(buf, nat_globals.data.servicetype))) {
				if ((pos = strstr(buf, "NTS:"))) {
					pos = pos + 4;
					while (*pos && *pos == ' ') {
						pos++;
					}
					if (!strncmp(pos, "ssdp:alive", 10)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UPnP keep alive packet: \n%s\n", buf);
						/* did pub ip change */
						newip[0] = '\0';
						if (get_upnp_pubaddr(newip) != SWITCH_STATUS_SUCCESS) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
											  "Unable to get current pubaddr after receiving UPnP keep alive packet.\n");
						}
					} else if (!strncmp(pos, "ssdp:byebye", 11)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
										  "got UPnP signoff packet.  Your NAT gateway is probably going offline.\n");
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UPnP signoff packet: \n%s\n", buf);
					} else {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UNKNOWN UPnP keep alive packet: \n%s\n", buf);
					}
				}
			}
		} else {
			/* got some data in NAT-PMP mode, treat any data as a republish event */
			if (get_pmp_pubaddr(newip) < 0) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to get current pubaddr after receiving UPnP keep alive packet.\n");
			}
		}

		if ((strlen(newip) > 0) && strcmp(newip, "0.0.0.0") && strcmp(newip, nat_globals.pub_addr)) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Public IP changed from '%s' to '%s'.\n", nat_globals.pub_addr, newip);
			do_repub = SWITCH_TRUE;

			switch_event_create(&event, SWITCH_EVENT_TRAP);
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "network-address-change");
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "network-address-previous-v4", nat_globals.pub_addr);
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "network-address-change-v4", newip);
			switch_event_fire(&event);

			switch_set_string(nat_globals.pub_addr, newip);
			switch_nat_reinit();
		}

		if (do_repub) {
			switch_nat_republish();
		}
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NAT thread ending\n");
	nat_globals_perm.running = 0;

	switch_safe_free(buf);

	return NULL;
}
static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
													switch_caller_profile_t *outbound_profile,
													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
													switch_call_cause_t *cancel_cause)
{
	char name[128];
	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;

	if ((*new_session = switch_core_session_request(modem_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool)) != 0) {
		private_t *tech_pvt;
		switch_channel_t *channel;
		switch_caller_profile_t *caller_profile;
		char *dest = switch_core_session_strdup(*new_session, outbound_profile->destination_number);
		char *modem_id_string = NULL;
		char *number = NULL;
		int modem_id = 0;
		modem_t *modem = NULL;

		if ((modem_id_string = dest)) {
			if ((number = strchr(modem_id_string, '/'))) {
				*number++ = '\0';
			}
		}

		if (zstr(modem_id_string) || zstr(number)) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Invalid dial string.\n");
			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; goto fail;
		}

		if (!strcasecmp(modem_id_string, "a")) {
			modem_id = -1;
		} else {
			modem_id = atoi(modem_id_string);
		}

		if (!(modem = acquire_modem(modem_id))) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Cannot find a modem.\n");
			cause = SWITCH_CAUSE_USER_BUSY; goto fail;
		}
		
		switch_core_session_add_stream(*new_session, NULL);

		if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
			channel = switch_core_session_get_channel(*new_session);
			switch_snprintf(name, sizeof(name), "modem/%d/%s", modem->slot, number);
			switch_channel_set_name(channel, name);

			if (tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) {
				cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
			}

			switch_set_string(modem->digits, number);
			tech_attach(tech_pvt, modem);
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
			switch_core_session_destroy(new_session);
			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
		}

		if (outbound_profile) {
			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
			caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp");
			switch_channel_set_caller_profile(channel, caller_profile);
			tech_pvt->caller_profile = caller_profile;
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n");
			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
		}

		switch_channel_set_state(channel, CS_INIT);

		return SWITCH_CAUSE_SUCCESS;

	fail:

		if (new_session) {
			switch_core_session_destroy(new_session);
		}

		if (modem) {
			modem_set_state(modem, MODEM_STATE_ONHOOK);
		}
	}

	return cause;
}
static int control_handler(modem_t *modem, const char *num, int op)
{
	switch_core_session_t *session = NULL;
	
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Control Handler op:%d state:[%s] %s\n", 
					  op, modem_state2name(modem_get_state(modem)), modem->devlink);

    switch (op) {

    case AT_MODEM_CONTROL_ANSWER:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - Answering\n", modem->devlink, modem_state2name(modem_get_state(modem)));
		modem_set_state(modem, MODEM_STATE_ANSWERED);
        break;
    case AT_MODEM_CONTROL_CALL:
		{
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
							  "Modem %s [%s] - Dialing '%s'\n", modem->devlink, modem_state2name(modem_get_state(modem)), num);
			modem_set_state(modem, MODEM_STATE_DIALING);
			switch_clear_flag(modem, MODEM_FLAG_XOFF);
			wake_modem_thread(modem);

			switch_set_string(modem->digits, num);
			
			if (create_session(&session, modem) != SWITCH_STATUS_SUCCESS) {
				t31_call_event(modem->t31_state, AT_CALL_EVENT_HANGUP);
			} else {
				switch_core_session_thread_launch(session);
			}
		}
		break;
    case AT_MODEM_CONTROL_OFFHOOK:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - Going off hook\n", modem->devlink, modem_state2name(modem_get_state(modem)));
		modem_set_state(modem, MODEM_STATE_OFFHOOK);
		break;
    case AT_MODEM_CONTROL_ONHOOK:
    case AT_MODEM_CONTROL_HANGUP: 
		{
			if (modem_get_state(modem) != MODEM_STATE_RINGING) {
				int set_state = 1;
				
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
								  "Modem %s [%s] - Hanging up\n", modem->devlink, modem_state2name(modem_get_state(modem)));
				switch_clear_flag(modem, MODEM_FLAG_XOFF);
				wake_modem_thread(modem);
				

				modem_set_state(modem, MODEM_STATE_HANGUP);
			

				if (!zstr(modem->uuid_str)) {
					switch_core_session_t *session;
					
					if ((session = switch_core_session_force_locate(modem->uuid_str))) {
						switch_channel_t *channel = switch_core_session_get_channel(session);
						
						if (switch_channel_up(channel)) {
							switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
							set_state = 0;
						}
						switch_core_session_rwunlock(session);
					}
				}
				

				if (set_state) {
					modem_set_state(modem, MODEM_STATE_ONHOOK);
				}
			}
		}
        break;
    case AT_MODEM_CONTROL_DTR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - DTR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_RTS:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - RTS %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_CTS:
		{
			u_char x[1];
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1,
							  "Modem %s [%s] - CTS %s\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num ? "XON" : "XOFF");

			if (num) {
				x[0] = 0x11;
				t31_at_tx_handler(&modem->t31_state->at_state, modem, x, 1);
				switch_clear_flag(modem, MODEM_FLAG_XOFF);
				wake_modem_thread(modem);
			} else {
				x[0] = 0x13;
				t31_at_tx_handler(&modem->t31_state->at_state, modem, x, 1);
				switch_set_flag(modem, MODEM_FLAG_XOFF);
			}
		}
        break;
    case AT_MODEM_CONTROL_CAR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - CAR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_RNG:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - RNG %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_DSR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - DSR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    default:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - operation %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), op);
        break;
    }
    /*endswitch*/
    return 0;
}
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
{
	local_stream_source_t *source = obj;
	switch_file_handle_t fh = { 0 };
	local_stream_context_t *cp;
	char file_buf[128] = "", path_buf[512] = "", last_path[512], png_buf[512] = "", tmp_buf[512] = "";
	switch_timer_t timer = { 0 };
	int fd = -1;
	switch_buffer_t *audio_buffer;
	switch_byte_t *dist_buf;
	switch_size_t used;
	int skip = 0;
	switch_memory_pool_t *temp_pool = NULL;
	uint32_t dir_count = 0, do_shuffle = 0;
	char *p;

	switch_mutex_lock(globals.mutex);
	THREADS++;
	switch_mutex_unlock(globals.mutex);

	if (!source->prebuf) {
		source->prebuf = DEFAULT_PREBUFFER_SIZE;
	}

	if (source->shuffle) {
		do_shuffle = 1;
	}

	switch_queue_create(&source->video_q, 500, source->pool);
	switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0);
	dist_buf = switch_core_alloc(source->pool, source->prebuf + 10);

	switch_thread_rwlock_create(&source->rwlock, source->pool);

	if (RUNNING) {
		switch_mutex_lock(globals.mutex);
		switch_core_hash_insert(globals.source_hash, source->name, source);
		switch_mutex_unlock(globals.mutex);
		source->ready = 1;
	}

	while (RUNNING && !source->stopped) {
		const char *fname;

		if (temp_pool) {
			switch_core_destroy_memory_pool(&temp_pool);
		}

		if (switch_core_new_memory_pool(&temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error creating pool");
			goto done;
		}

		if (switch_dir_open(&source->dir_handle, source->location, temp_pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location);
			goto done;
		}

		if (fd > -1) {
			dir_count = 0;
			while (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
				dir_count++;
			}
			lseek(fd, 0, SEEK_SET);
		} else {
			dir_count = switch_dir_count(source->dir_handle);
		}

		if (do_shuffle) {
			skip = do_rand(dir_count);
			do_shuffle = 0;
		}

		switch_yield(1000000);

		while (RUNNING && !source->stopped) {
			switch_size_t olen;
			uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
			const char *artist = NULL, *title = NULL;

			if (fd > -1) {
				char *pb;
				if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) {
					if ((pb = strchr(path_buf, '\r')) || (pb = strchr(path_buf, '\n'))) {
						*pb = '\0';
					}
				} else {
					close(fd);
					fd = -1;
					continue;
				}
			} else {
				if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) {
					break;
				}

				switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname);

				if (switch_stristr(".loc", path_buf)) {
					if ((fd = open(path_buf, O_RDONLY)) < 0) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
						switch_yield(1000000);
					}
					continue;
				}
			}

			if (dir_count > 1 && !strcmp(last_path, path_buf)) {
				continue;
			}

			if (skip > 0) {
				skip--;
				continue;
			}

			switch_set_string(last_path, path_buf);

			fname = path_buf;
			fh.prebuf = source->prebuf;
			fh.pre_buffer_datalen = source->prebuf;

			if (switch_core_file_open(&fh,
									  (char *) fname,
									  source->channels, source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname);
				switch_yield(1000000);
				continue;
			}

			if (switch_core_file_has_video(&fh)) {
				flush_video_queue(source->video_q);
			}

			if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
				switch_dir_close(source->dir_handle);
				source->dir_handle = NULL;
				goto done;
			}

			switch_img_free(&source->cover_art);
			switch_set_string(tmp_buf, path_buf);
			if ((p = strrchr(tmp_buf, '/'))) {
				*p++ = '\0';
				switch_snprintf(png_buf, sizeof(png_buf), "%s/art/%s.png", tmp_buf, p);				
				if (switch_file_exists(png_buf, source->pool) == SWITCH_STATUS_SUCCESS) {
					source->cover_art = switch_img_read_png(png_buf, SWITCH_IMG_FMT_I420);
				}
			}

			source->serno++;
			switch_safe_free(source->banner_txt);
			title = artist = NULL;
			
			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_ARTIST, &artist);
			switch_core_file_get_string(&fh, SWITCH_AUDIO_COL_STR_TITLE, &title);
			
			if (title && (source->cover_art || switch_core_file_has_video(&fh))) {
				const char *format = "#cccccc:#333333:FreeSans.ttf:3%:";

				if (artist) {
					source->banner_txt = switch_mprintf("%s%s (%s)", format, title, artist);
				} else {
					source->banner_txt = switch_mprintf("%s%s", format, title);
				}
			}

			while (RUNNING && !source->stopped) {
				int is_open;
				switch_file_handle_t *use_fh = &fh;

				switch_core_timer_next(&timer);
				olen = source->samples;
				
				if (source->chime_total) {

					if (source->chime_counter > 0) {
						source->chime_counter -= (int32_t)source->samples;
					}

					if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
						char *val;

						val = source->chime_list[source->chime_cur++];

						if (source->chime_cur >= source->chime_total) {
							source->chime_cur = 0;
						}

						if (switch_core_file_open(&source->chime_fh,
												  (char *) val,
												  source->channels,
												  source->rate, SWITCH_FILE_FLAG_VIDEO | SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", val);
						}


						if (switch_core_file_has_video(&source->chime_fh)) {
							flush_video_queue(source->video_q);
						}

					}

					if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
						use_fh = &source->chime_fh;
					}
				}

			retry:

				source->has_video = switch_core_file_has_video(use_fh) || source->cover_art || source->banner_txt;

				is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN);

				if (source->hup) {
					source->hup = 0;
					if (is_open) {
						is_open = 0;

						switch_core_file_close(use_fh);
						flush_video_queue(source->video_q);
						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
							switch_core_file_close(&fh);
							use_fh = &fh;							
						}
						goto retry;
					}
				}
				
				if (is_open) {
					if (switch_core_has_video() && switch_core_file_has_video(use_fh)) {
						switch_frame_t vid_frame = { 0 };

						if (use_fh == &source->chime_fh && switch_core_file_has_video(&fh)) {
							if (switch_core_file_read_video(&fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
								switch_img_free(&vid_frame.img);
							}
						}

						if (switch_core_file_read_video(use_fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
							if (vid_frame.img) {
								int flush = 1;

								source->has_video = 1;
								
								if (source->total) {
									if (switch_queue_trypush(source->video_q, vid_frame.img) == SWITCH_STATUS_SUCCESS) {
										flush = 0;
									}
								}

								if (flush) {
									switch_img_free(&vid_frame.img);
									flush_video_queue(source->video_q);
								}
							}
						}
					} else {
						source->has_video = 0;
					}

					if (use_fh == &source->chime_fh) {
						olen = source->samples;
						switch_core_file_read(&fh, abuf, &olen);
						olen = source->samples;
					}

					if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
						switch_core_file_close(use_fh);
						flush_video_queue(source->video_q);

						if (use_fh == &source->chime_fh) {
							source->chime_counter = source->rate * source->chime_freq;
							use_fh = &fh;
						} else {
							is_open = 0;
						}
					} else {
						if (use_fh == &source->chime_fh && source->chime_max) {
							source->chime_max_counter += (int32_t)source->samples;
							if (source->chime_max_counter >= source->chime_max) {
								source->chime_max_counter = 0;
								switch_core_file_close(use_fh);
								flush_video_queue(source->video_q);
								source->chime_counter = source->rate * source->chime_freq;
								use_fh = &fh;
								goto retry;
							}
						}
						
						if (source->total) {
							switch_buffer_write(audio_buffer, abuf, olen * 2 * source->channels);
						} else {
							switch_buffer_zero(audio_buffer);
						}
					}
				}

				used = switch_buffer_inuse(audio_buffer);

				if (!used && !is_open) {
					break;
				}

				if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) {
					void *pop;

					used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels);

					if (!source->total) {
						flush_video_queue(source->video_q);
					} else {
						uint32_t bused = 0;

						switch_mutex_lock(source->mutex);
						for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
							
							if (source->has_video) {
								switch_set_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
							} else {
								switch_clear_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
							}
							
							if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
								continue;
							}
							
							switch_mutex_lock(cp->audio_mutex);
							bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
							if (bused > source->samples * 768) {
								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n", 
												  cp->func, cp->file, cp->line, bused, (long)source->samples);
								switch_buffer_zero(cp->audio_buffer);
							} else {
								switch_buffer_write(cp->audio_buffer, dist_buf, used);
							}
							switch_mutex_unlock(cp->audio_mutex);
						}
						switch_mutex_unlock(source->mutex);

						
						while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
							switch_image_t *img = (switch_image_t *) pop;
							switch_image_t *imgcp = NULL;

							if (source->total == 1) {
								switch_queue_push(source->context_list->video_q, img);
							} else {
								if (source->context_list) {
									switch_mutex_lock(source->mutex);
									for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
										if (cp->video_q) {
											imgcp = NULL;
											switch_img_copy(img, &imgcp);
											if (imgcp) {
												if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) {
													flush_video_queue(cp->video_q);
												}
											}
										}
									}
									switch_mutex_unlock(source->mutex);
								}
								switch_img_free(&img);
							}
						}
					}
				}
			}

			switch_core_timer_destroy(&timer);
			if (RUNNING && source->shuffle) {
				skip = do_rand(dir_count);
			}
		}

		switch_dir_close(source->dir_handle);
		source->dir_handle = NULL;

		if (source->full_reload) {
			if (source->rwlock && switch_thread_rwlock_trywrlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot stop local_stream://%s because it is in use.\n",source->name);
				if (source->part_reload) {
					switch_xml_t cfg, xml, directory, param;
					if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
					}
					if ((directory = switch_xml_find_child(cfg, "directory", "name", source->name))) {
						for (param = switch_xml_child(directory, "param"); param; param = param->next) {
							char *var = (char *) switch_xml_attr_soft(param, "name");
							char *val = (char *) switch_xml_attr_soft(param, "value");
							if (!strcasecmp(var, "shuffle")) {
								source->shuffle = switch_true(val);
							} else if (!strcasecmp(var, "chime-freq")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_freq = tmp;
								}
							} else if (!strcasecmp(var, "chime-max")) {
								int tmp = atoi(val);
								if (tmp > 1) {
									source->chime_max = tmp;
								}
							} else if (!strcasecmp(var, "chime-list")) {
								char *list_dup = switch_core_strdup(source->pool, val);
								source->chime_total =
									switch_separate_string(list_dup, ',', source->chime_list, (sizeof(source->chime_list) / sizeof(source->chime_list[0])));
							} else if (!strcasecmp(var, "interval")) {
								int tmp = atoi(val);
								if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
									source->interval = tmp;
								} else {
									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
													  "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
								}
							}
							if (source->chime_max) {
								source->chime_max *= source->rate;
							}
							if (source->chime_total) {
								source->chime_counter = source->rate * source->chime_freq;
							}
						}
					}
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name);
					source->part_reload = 0;
				}
			} else {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name);
				launch_streams(source->name);
				goto done;
			}
		}
	}

  done:

	switch_safe_free(source->banner_txt);
	
	if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&fh);
	}

	if (switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) {
		switch_core_file_close(&source->chime_fh);
	}

	source->ready = 0;
	switch_mutex_lock(globals.mutex);
	switch_core_hash_delete(globals.source_hash, source->name);
	switch_mutex_unlock(globals.mutex);

	switch_thread_rwlock_wrlock(source->rwlock);
	switch_thread_rwlock_unlock(source->rwlock);

	switch_buffer_destroy(&audio_buffer);

	flush_video_queue(source->video_q);

	if (fd > -1) {
		close(fd);
	}

	if (temp_pool) {
		switch_core_destroy_memory_pool(&temp_pool);
	}

	switch_core_destroy_memory_pool(&source->pool);

	switch_mutex_lock(globals.mutex);
	THREADS--;
	switch_mutex_unlock(globals.mutex);

	return NULL;
}