static switch_status_t local_stream_file_close(switch_file_handle_t *handle)
{
	local_stream_context_t *cp, *last = NULL, *context = handle->private_info;

	context->ready = 0;

	switch_mutex_lock(context->source->mutex);
	for (cp = context->source->context_list; cp; cp = cp->next) {
		if (cp == context) {
			if (last) {
				last->next = cp->next;
			} else {
				context->source->context_list = cp->next;
			}
			break;
		}
		last = cp;
	}
	
	if (context->video_q) {
		flush_video_queue(context->video_q);
		switch_queue_trypush(context->video_q, NULL);
		switch_queue_interrupt_all(context->video_q);
		flush_video_queue(context->video_q);
	}

	switch_img_free(&context->banner_img);
	
	context->source->total--;
	switch_mutex_unlock(context->source->mutex);
	switch_buffer_destroy(&context->audio_buffer);
	switch_thread_rwlock_unlock(context->source->rwlock);

	return SWITCH_STATUS_SUCCESS;
}
Example #2
0
static void event_handler(switch_event_t *event)
{
	EventConsumer *E = (EventConsumer *) event->bind_user_data;
	switch_event_t *dup;
	
	switch_event_dup(&dup, event);

	if (switch_queue_trypush(E->events, dup) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot queue any more events.....\n");
	}

}
Example #3
0
/**
 * Handle log from core
 * @param node the log
 * @param level the log level
 */
static switch_status_t mod_graylog2_logger(const switch_log_node_t *node, switch_log_level_t level)
{
	if (!globals.shutdown && level <= globals.log_level && level != SWITCH_LOG_CONSOLE) {
		if (!zstr(node->content) && !zstr(node->content + 1)) {
			char *log = to_gelf(node, level);
			if (switch_queue_trypush(globals.log_queue, log) != SWITCH_STATUS_SUCCESS) {
				free(log);
			}
		}
	}
	return SWITCH_STATUS_SUCCESS;
}
Example #4
0
SWITCH_DECLARE(void) switch_log_node_free(switch_log_node_t **pnode)
{
	switch_log_node_t *node;

	if (!pnode) {
		return;
	}

	node = *pnode;

	if (node) {
		switch_safe_free(node->userdata);
		switch_safe_free(node->data);
#ifdef SWITCH_LOG_RECYCLE
		if (switch_queue_trypush(LOG_RECYCLE_QUEUE, node) != SWITCH_STATUS_SUCCESS) {
			free(node);
		}
#else
		free(node);
#endif
	}
	*pnode = NULL;
}
Example #5
0
static switch_xml_t fetch_handler(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data) {
    switch_xml_t xml = NULL;
    switch_uuid_t uuid;
    switch_time_t now = 0;
    ei_xml_agent_t *agent = (ei_xml_agent_t *) user_data;
    ei_xml_client_t *client;
    fetch_handler_t *fetch_handler;
    xml_fetch_reply_t reply, *pending, *prev = NULL;

    now = switch_micro_time_now();

    if (!switch_test_flag(&globals, LFLAG_RUNNING)) {
        return xml;
    }

    /* read-lock the agent */
    switch_thread_rwlock_rdlock(agent->lock);

    /* serialize access to current, used to round-robin requests */
    /* TODO: check globals for round-robin boolean or loop all clients */
    switch_mutex_lock(agent->current_client_mutex);
    if (!agent->current_client) {
        client = agent->clients;
    } else {
        client = agent->current_client;
    }
    if (client) {
        agent->current_client = client->next;
    }
    switch_mutex_unlock(agent->current_client_mutex);

    /* no client, no work required */
    if (!client || !client->fetch_handlers) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "No %s XML erlang handler currently available\n"
                          ,section);
        switch_thread_rwlock_unlock(agent->lock);
        return xml;
    }

    /* prepare the reply collector */
    switch_uuid_get(&uuid);
    switch_uuid_format(reply.uuid_str, &uuid);
    reply.next = NULL;
    reply.xml_str = NULL;

    /* add our reply placeholder to the replies list */
    switch_mutex_lock(agent->replies_mutex);
    if (!agent->replies) {
        agent->replies = &reply;
    } else {
        reply.next = agent->replies;
        agent->replies = &reply;
    }
    switch_mutex_unlock(agent->replies_mutex);

    fetch_handler = client->fetch_handlers;
    while (fetch_handler != NULL) {
        ei_send_msg_t *send_msg;

        switch_malloc(send_msg, sizeof(*send_msg));
        memcpy(&send_msg->pid, &fetch_handler->pid, sizeof(erlang_pid));

        ei_x_new_with_version(&send_msg->buf);

        ei_x_encode_tuple_header(&send_msg->buf, 7);
        ei_x_encode_atom(&send_msg->buf, "fetch");
        ei_x_encode_atom(&send_msg->buf, section);
        _ei_x_encode_string(&send_msg->buf, tag_name ? tag_name : "undefined");
        _ei_x_encode_string(&send_msg->buf, key_name ? key_name : "undefined");
        _ei_x_encode_string(&send_msg->buf, key_value ? key_value : "undefined");
        _ei_x_encode_string(&send_msg->buf, reply.uuid_str);

        if (params) {
            ei_encode_switch_event_headers(&send_msg->buf, params);
        } else {
            ei_x_encode_empty_list(&send_msg->buf);
        }

        if (switch_queue_trypush(client->ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send %s XML request to %s <%d.%d.%d>\n"
                              ,section
                              ,fetch_handler->pid.node
                              ,fetch_handler->pid.creation
                              ,fetch_handler->pid.num
                              ,fetch_handler->pid.serial);
            ei_x_free(&send_msg->buf);
            switch_safe_free(send_msg);
        } else {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending %s XML request (%s) to %s <%d.%d.%d>\n"
                              ,section
                              ,reply.uuid_str
                              ,fetch_handler->pid.node
                              ,fetch_handler->pid.creation
                              ,fetch_handler->pid.num
                              ,fetch_handler->pid.serial);
        }

        fetch_handler = fetch_handler->next;
    }

    /* wait for a reply (if there isnt already one...amazingly improbable but lets not take shortcuts */
    switch_mutex_lock(agent->replies_mutex);

    switch_thread_rwlock_unlock(agent->lock);

    if (!reply.xml_str) {
        switch_time_t timeout;

        timeout = switch_micro_time_now() + 3000000;
        while (switch_micro_time_now() < timeout) {
            /* unlock the replies list and go to sleep, calculate a three second timeout before we started the loop
             * plus 100ms to add a little hysteresis between the timeout and the while loop */
            switch_thread_cond_timedwait(agent->new_reply, agent->replies_mutex, (timeout - switch_micro_time_now() + 100000));

            /* if we woke up (and therefore have locked replies again) check if we got our reply
             * otherwise we either timed-out (the while condition will fail) or one of
             * our sibling processes got a reply and we should go back to sleep */
            if (reply.xml_str) {
                break;
            }
        }
    }

    /* find our reply placeholder in the linked list and remove it */
    pending = agent->replies;
    while (pending != NULL) {
        if (pending->uuid_str == reply.uuid_str) {
            break;
        }

        prev = pending;
        pending = pending->next;
    }

    if (pending) {
        if (!prev) {
            agent->replies = reply.next;
        } else {
            prev->next = reply.next;
        }
    }

    /* we are done with the replies link-list */
    switch_mutex_unlock(agent->replies_mutex);

    /* after all that did we get what we were after?! */
    if (reply.xml_str) {
        /* HELL YA WE DID */
        reply.xml_str = expand_vars(reply.xml_str);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received %s XML (%s) after %dms: %s\n"
                          ,section
                          ,reply.uuid_str
                          ,(unsigned int) (switch_micro_time_now() - now) / 1000
                          ,reply.xml_str);

        xml = switch_xml_parse_str_dynamic(reply.xml_str, SWITCH_FALSE);
    } else {
        /* facepalm */
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Request for %s XML (%s) timed-out after %dms\n"
                          ,section
                          ,reply.uuid_str
                          ,(unsigned int) (switch_micro_time_now() - now) / 1000);
    }

    return xml;
}
Example #6
0
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;
	switch_status_t status = SWITCH_STATUS_FALSE;

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);

	if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || switch_test_flag(tech_pvt, TFLAG_BOWOUT)) {
		return SWITCH_STATUS_SUCCESS;
	}

	switch_mutex_lock(tech_pvt->mutex);
	if (!switch_test_flag(tech_pvt, TFLAG_BOWOUT) &&
		tech_pvt->other_tech_pvt &&
		switch_test_flag(tech_pvt, TFLAG_BRIDGE) &&
		switch_test_flag(tech_pvt->other_tech_pvt, TFLAG_BRIDGE) &&
		switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) &&
		switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) &&
		switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) &&
		switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && !--tech_pvt->bowout_frame_count <= 0) {
		const char *a_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
		const char *b_uuid = switch_channel_get_variable(tech_pvt->other_channel, SWITCH_SIGNAL_BOND_VARIABLE);
		const char *vetoa, *vetob;

		switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT);
		switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT);

		vetoa = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout");
		vetob = switch_channel_get_variable(tech_pvt->other_tech_pvt->channel, "loopback_bowout");

		if ((!vetoa || switch_true(vetoa)) && (!vetob || switch_true(vetob))) {
			switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
			switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);

			if (a_uuid && b_uuid) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
								  "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));

				/* channel_masquerade eat your heart out....... */
				switch_ivr_uuid_bridge(a_uuid, b_uuid);
				switch_mutex_unlock(tech_pvt->mutex);
				return SWITCH_STATUS_SUCCESS;
			}
		}
	}

	if (switch_test_flag(tech_pvt, TFLAG_LINKED) && tech_pvt->other_tech_pvt) {
		switch_frame_t *clone;

		if (frame->codec->implementation != tech_pvt->write_codec.implementation) {
			/* change codecs to match */
			tech_init(tech_pvt, session, frame->codec);
			tech_init(tech_pvt->other_tech_pvt, tech_pvt->other_session, frame->codec);
		}

		if (switch_queue_size(tech_pvt->other_tech_pvt->frame_queue) < FRAME_QUEUE_LEN) {
			if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) {
				abort();
			}

			if (switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone) != SWITCH_STATUS_SUCCESS) {
				switch_frame_free(&clone);
			}

			switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
		}

		status = SWITCH_STATUS_SUCCESS;
	}

	switch_mutex_unlock(tech_pvt->mutex);

	return status;
}
Example #7
0
SWITCH_DECLARE(void) switch_log_vprintf(switch_text_channel_t channel, const char *file, const char *func, int line,
										const char *userdata, switch_log_level_t level, const char *fmt, va_list ap)
{
	char *data = NULL;
	char *new_fmt = NULL;
	int ret = 0;
	FILE *handle;
	const char *filep = (file ? switch_cut_path(file) : "");
	const char *funcp = (func ? func : "");
	char *content = NULL;
	switch_time_t now = switch_micro_time_now();
	uint32_t len;
#ifdef SWITCH_FUNC_IN_LOG
	const char *extra_fmt = "%s [%s] %s:%d %s()%c%s";
#else
	const char *extra_fmt = "%s [%s] %s:%d%c%s";
#endif
	switch_log_level_t limit_level = runtime.hard_log_level;

	if (channel == SWITCH_CHANNEL_ID_SESSION && userdata) {
		switch_core_session_t *session = (switch_core_session_t *) userdata;
		if (limit_level < session->loglevel) {
			limit_level = session->loglevel;
		}
	}

	if (level > 100) {
		if ((uint32_t) (level - 100) > runtime.debug_level) {
			return;
		}

		level = 7;
	}

	if (level > limit_level) {
		return;
	}

	switch_assert(level < SWITCH_LOG_INVALID);

	handle = switch_core_data_channel(channel);

	if (channel != SWITCH_CHANNEL_ID_LOG_CLEAN) {
		char date[80] = "";
		//switch_size_t retsize;
		switch_time_exp_t tm;

		switch_time_exp_lt(&tm, now);
		switch_snprintf(date, sizeof(date), "%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d.%0.6d",
						tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec);

		//switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm);

#ifdef SWITCH_FUNC_IN_LOG
		len = (uint32_t) (strlen(extra_fmt) + strlen(date) + strlen(filep) + 32 + strlen(funcp) + strlen(fmt));
#else
		len = (uint32_t) (strlen(extra_fmt) + strlen(date) + strlen(filep) + 32 + strlen(fmt));
#endif
		new_fmt = malloc(len + 1);
		switch_assert(new_fmt);
#ifdef SWITCH_FUNC_IN_LOG
		switch_snprintf(new_fmt, len, extra_fmt, date, switch_log_level2str(level), filep, line, funcp, 128, fmt);
#else
		switch_snprintf(new_fmt, len, extra_fmt, date, switch_log_level2str(level), filep, line, 128, fmt);
#endif

		fmt = new_fmt;
	}

	ret = switch_vasprintf(&data, fmt, ap);

	if (ret == -1) {
		fprintf(stderr, "Memory Error\n");
		goto end;
	}

	if (channel == SWITCH_CHANNEL_ID_LOG_CLEAN) {
		content = data;
	} else {
		if ((content = strchr(data, 128))) {
			*content = ' ';
		}
	}

	if (channel == SWITCH_CHANNEL_ID_EVENT) {
		switch_event_t *event;
		if (switch_event_running() == SWITCH_STATUS_SUCCESS && switch_event_create(&event, SWITCH_EVENT_LOG) == SWITCH_STATUS_SUCCESS) {
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-Data", data);
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-File", filep);
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-Function", funcp);
			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Log-Line", "%d", line);
			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Log-Level", "%d", (int) level);
			if (!zstr(userdata)) {
				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "User-Data", userdata);
			}
			switch_event_fire(&event);
			data = NULL;
		}

		goto end;
	}

	if (console_mods_loaded == 0 || !do_mods) {
		if (handle) {
			int aok = 1;
#ifndef WIN32

			fd_set can_write;
			int fd;
			struct timeval to;

			fd = fileno(handle);
			memset(&to, 0, sizeof(to));
			FD_ZERO(&can_write);
			FD_SET(fd, &can_write);
			to.tv_sec = 0;
			to.tv_usec = 100000;
			if (select(fd + 1, NULL, &can_write, NULL, &to) > 0) {
				aok = FD_ISSET(fd, &can_write);
			} else {
				aok = 0;
			}
#endif
			if (aok) {
				if (COLORIZE) {

#ifdef WIN32
					SetConsoleTextAttribute(hStdout, COLORS[level]);
					WriteFile(hStdout, data, (DWORD) strlen(data), NULL, NULL);
					SetConsoleTextAttribute(hStdout, wOldColorAttrs);
#else
					fprintf(handle, "%s%s%s", COLORS[level], data, SWITCH_SEQ_DEFAULT_COLOR);
#endif
				} else {
					fprintf(handle, "%s", data);
				}
			}
		}
	}

	if (do_mods && level <= MAX_LEVEL) {
		switch_log_node_t *node = switch_log_node_alloc();

		node->data = data;
		data = NULL;
		switch_set_string(node->file, filep);
		switch_set_string(node->func, funcp);
		node->line = line;
		node->level = level;
		node->content = content;
		node->timestamp = now;
		node->channel = channel;
		if (channel == SWITCH_CHANNEL_ID_SESSION) {
			node->userdata = userdata ? strdup(switch_core_session_get_uuid((switch_core_session_t *) userdata)) : NULL;
		} else {
			node->userdata = !zstr(userdata) ? strdup(userdata) : NULL;
		}

		if (switch_queue_trypush(LOG_QUEUE, node) != SWITCH_STATUS_SUCCESS) {
			switch_log_node_free(&node);
		}
	}

  end:

	switch_safe_free(data);
	switch_safe_free(new_fmt);

}
Example #8
0
static void *SWITCH_THREAD_FUNC pool_thread(switch_thread_t *thread, void *obj)
{
	memory_manager.pool_thread_running = 1;

	while (memory_manager.pool_thread_running == 1) {
		int len = switch_queue_size(memory_manager.pool_queue);

		if (len) {
			int x = len, done = 0;

			switch_yield(1000000);
#ifdef USE_MEM_LOCK
			switch_mutex_lock(memory_manager.mem_lock);
#endif
			while (x > 0) {
				void *pop = NULL;
				if (switch_queue_pop(memory_manager.pool_queue, &pop) != SWITCH_STATUS_SUCCESS || !pop) {
					done = 1;
					break;
				}
#if defined(PER_POOL_LOCK) || defined(DESTROY_POOLS)
#ifdef USE_MEM_LOCK
				switch_mutex_lock(memory_manager.mem_lock);
#endif

#ifdef DEBUG_ALLOC
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%p DESTROY POOL\n", (void *) pop);	
#endif
				apr_pool_destroy(pop);
#ifdef USE_MEM_LOCK
				switch_mutex_unlock(memory_manager.mem_lock);
#endif
#else
				apr_pool_mutex_set(pop, NULL);
#ifdef DEBUG_ALLOC
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%p DESTROY POOL\n", (void *) pop);	
#endif
				apr_pool_clear(pop);
				if (switch_queue_trypush(memory_manager.pool_recycle_queue, pop) != SWITCH_STATUS_SUCCESS) {
#ifdef USE_MEM_LOCK
					switch_mutex_lock(memory_manager.mem_lock);
#endif
#ifdef DEBUG_ALLOC
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%p DESTROY POOL\n", (void *) pop);	
#endif
					apr_pool_destroy(pop);
#ifdef USE_MEM_LOCK
					switch_mutex_unlock(memory_manager.mem_lock);
#endif

				}
#endif
				x--;
			}
#ifdef USE_MEM_LOCK
			switch_mutex_unlock(memory_manager.mem_lock);
#endif
			if (done) {
				goto done;
			}
		} else {
			switch_yield(1000000);
		}
	}

  done:
	switch_core_memory_reclaim();

	{
		void *pop = NULL;
		while (switch_queue_trypop(memory_manager.pool_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
#ifdef USE_MEM_LOCK
			switch_mutex_lock(memory_manager.mem_lock);
#endif
			apr_pool_destroy(pop);
			pop = NULL;
#ifdef USE_MEM_LOCK
			switch_mutex_unlock(memory_manager.mem_lock);
#endif

		}
	}

	memory_manager.pool_thread_running = 0;

	return NULL;
}
Example #9
0
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;
	switch_status_t status = SWITCH_STATUS_FALSE;

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);

	if (switch_test_flag(frame, SFF_CNG) || 
		(switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
		switch_core_timer_sync(&tech_pvt->timer);
		switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer);
		return SWITCH_STATUS_SUCCESS;
	}

	switch_mutex_lock(tech_pvt->mutex);
	if (!switch_test_flag(tech_pvt, TFLAG_BOWOUT) &&
		tech_pvt->other_tech_pvt &&
		switch_test_flag(tech_pvt, TFLAG_BRIDGE) &&
		switch_test_flag(tech_pvt->other_tech_pvt, TFLAG_BRIDGE) &&
		switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) &&
		switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) &&
		switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) &&
		switch_channel_test_flag(tech_pvt->other_channel, CF_ANSWERED) && --tech_pvt->bowout_frame_count <= 0) {
		const char *a_uuid = NULL;
		const char *b_uuid = NULL;
		const char *vetoa, *vetob;


		vetoa = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout");
		vetob = switch_channel_get_variable(tech_pvt->other_tech_pvt->channel, "loopback_bowout");

		if ((!vetoa || switch_true(vetoa)) && (!vetob || switch_true(vetob))) {
			switch_core_session_t *br_a, *br_b;
			switch_channel_t *ch_a = NULL, *ch_b = NULL;
			int good_to_go = 0;

			switch_mutex_unlock(tech_pvt->mutex);
			find_non_loopback_bridge(session, &br_a, &a_uuid);
			find_non_loopback_bridge(tech_pvt->other_session, &br_b, &b_uuid);
			switch_mutex_lock(tech_pvt->mutex);

			
			if (br_a) {
				ch_a = switch_core_session_get_channel(br_a);
				switch_core_media_bug_transfer_recordings(session, br_a);
			}

			if (br_b) {
				ch_b = switch_core_session_get_channel(br_b);
				switch_core_media_bug_transfer_recordings(tech_pvt->other_session, br_b);
			}
			
			if (ch_a && ch_b && switch_channel_test_flag(ch_a, CF_BRIDGED) && switch_channel_test_flag(ch_b, CF_BRIDGED)) {

				switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT);
				switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT);

				switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
				switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);

				switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED);
				switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED);

				if (a_uuid && b_uuid) {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
									  "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));
					
					/* channel_masquerade eat your heart out....... */
					switch_ivr_uuid_bridge(a_uuid, b_uuid);
					good_to_go = 1;
					switch_mutex_unlock(tech_pvt->mutex);
				}
			}

			if (br_a) switch_core_session_rwunlock(br_a);
			if (br_b) switch_core_session_rwunlock(br_b);
			
			if (good_to_go) {
				return SWITCH_STATUS_SUCCESS;
			}

		}
	}

	if (switch_test_flag(tech_pvt, TFLAG_LINKED) && tech_pvt->other_tech_pvt) {
		switch_frame_t *clone;
		
		if (frame->codec->implementation != tech_pvt->write_codec.implementation) {
			/* change codecs to match */
			tech_init(tech_pvt, session, frame->codec);
			tech_init(tech_pvt->other_tech_pvt, tech_pvt->other_session, frame->codec);
		}


		if (switch_frame_dup(frame, &clone) != SWITCH_STATUS_SUCCESS) {
			abort();
		}
		
		if ((status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone)) != SWITCH_STATUS_SUCCESS) { 
			clear_queue(tech_pvt->other_tech_pvt);
			status = switch_queue_trypush(tech_pvt->other_tech_pvt->frame_queue, clone);
		}

		if (status == SWITCH_STATUS_SUCCESS) {
			switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
		} else {
			switch_frame_free(&clone);
		}

		status = SWITCH_STATUS_SUCCESS;
	}

	switch_mutex_unlock(tech_pvt->mutex);

	return status;
}
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;
}
Example #11
0
switch_status_t mod_amqp_logging_recv(const switch_log_node_t *node, switch_log_level_t level)
{
	switch_hash_index_t *hi = NULL;
	mod_amqp_message_t *msg = NULL;
	mod_amqp_logging_profile_t *logging = NULL;
	char *json = NULL;

	if (!strcmp(node->file, "mod_amqp_logging.c")) {
		return SWITCH_STATUS_SUCCESS;
	}

	/*
	  1. Loop through logging hash of profiles. Check for a profile that accepts this logging level, and file regex.
	  2. If event not already parsed/created, then create it now
	  3. Queue copy of event into logging profile send queue
	  4. Destroy local event copy
	*/
	for (hi = switch_core_hash_first(globals.logging_hash); hi; hi = switch_core_hash_next(&hi)) {
		switch_core_hash_this(hi, NULL, NULL, (void **)&logging);

		if ( logging && switch_log_check_mask(logging->log_level_mask, level) ) {
			char file[128] = {0};
			if ( !json ) {
				cJSON *body = NULL;
				char date[80] = "";
				switch_time_exp_t tm;

				switch_time_exp_lt(&tm, node->timestamp);
				switch_snprintf(date, sizeof(date), "%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d.%0.6d",
								tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec);

				/* Create cJSON body */
				body = cJSON_CreateObject();

				cJSON_AddItemToObject(body, "file", cJSON_CreateString((const char *) node->file));
				cJSON_AddItemToObject(body, "function", cJSON_CreateString((const char *) node->func));
				cJSON_AddItemToObject(body, "line", cJSON_CreateNumber((double) node->line));
				cJSON_AddItemToObject(body, "level", cJSON_CreateString(switch_log_level2str(node->level)));
				cJSON_AddItemToObject(body, "timestamp", cJSON_CreateString((const char *)date));
				cJSON_AddItemToObject(body, "timestamp_epoch", cJSON_CreateNumber((double) node->timestamp / 1000000));
				cJSON_AddItemToObject(body, "content", cJSON_CreateString(node->content ));

				json = cJSON_Print(body);
				cJSON_Delete(body);
			}

			/* Create message */
			switch_malloc(msg, sizeof(mod_amqp_message_t));
			msg->pjson = strdup(json);
			strcpy(file, node->file);
			switch_replace_char(file, '.', '_', 0);

			snprintf(msg->routing_key, sizeof(msg->routing_key), "%s.%s.%s.%s", switch_core_get_hostname(), node->userdata, switch_log_level2str(node->level), file);

			if (switch_queue_trypush(logging->send_queue, msg) != SWITCH_STATUS_SUCCESS) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMQP logging message queue full. Messages will be dropped!\n");
				return SWITCH_STATUS_SUCCESS;
			}
		}
	}


	switch_safe_free(json);
	return SWITCH_STATUS_SUCCESS;
}