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; }
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"); } }
/** * 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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }