/** * Empties the cache */ static void url_cache_clear(url_cache_t *cache, switch_core_session_t *session) { url_cache_lock(cache, session); // remove each cached URL from the hash and the queue for (int i = 0; i < cache->queue.max_size; i++) { cached_url_t *url = cache->queue.data[i]; if (url) { switch_core_hash_delete(cache->map, url->url); cached_url_destroy(url, cache->pool); cache->queue.data[i] = NULL; } } cache->queue.pos = 0; cache->queue.size = 0; // reset cache stats cache->size = 0; cache->hits = 0; cache->misses = 0; cache->errors = 0; url_cache_unlock(cache, session); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Emptied cache\n"); }
SWITCH_DECLARE(switch_status_t) switch_core_hash_delete_multi(switch_hash_t *hash, switch_hash_delete_callback_t callback, void *pData) { switch_hash_index_t *hi = NULL; switch_event_t *event = NULL; switch_event_header_t *header = NULL; switch_status_t status = SWITCH_STATUS_GENERR; switch_event_create_subclass(&event, SWITCH_EVENT_CLONE, NULL); switch_assert(event); /* iterate through the hash, call callback, if callback returns NULL or true, put the key on the list (event) When done, iterate through the list deleting hash entries */ for (hi = switch_hash_first(NULL, hash); hi; hi = switch_hash_next(hi)) { const void *key; void *val; switch_hash_this(hi, &key, NULL, &val); if (!callback || callback(key, val, pData)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delete", (const char *) key); } } /* now delete them */ for (header = event->headers; header; header = header->next) { if (switch_core_hash_delete(hash, header->value) == SWITCH_STATUS_SUCCESS) { status = SWITCH_STATUS_SUCCESS; } } switch_event_destroy(&event); return status; }
/** * Close file. * @param handle * @return SWITCH_STATUS_SUCCESS */ static switch_status_t fileman_file_close(switch_file_handle_t *handle) { struct fileman_file_context *context = (struct fileman_file_context *)handle->private_info; switch_file_handle_t *fh = &context->fh; if (context->id) { switch_mutex_lock(fileman_globals.mutex); switch_core_hash_delete(fileman_globals.hash, context->id); switch_mutex_unlock(fileman_globals.mutex); } if (switch_test_flag(fh, SWITCH_FILE_OPEN)) { free(context->abuf); if (fh->audio_buffer) { switch_buffer_destroy(&fh->audio_buffer); } if (fh->sp_audio_buffer) { switch_buffer_destroy(&fh->sp_audio_buffer); } return switch_core_file_close(fh); } return SWITCH_STATUS_SUCCESS; }
static void check_timeouts(void) { switch_hash_index_t *hi; const void *var; void *val; time_t now; valet_lot_t *lot; switch_console_callback_match_t *matches = NULL; switch_console_callback_match_node_t *m; switch_hash_index_t *i_hi; const void *i_var; void *i_val; char *i_ext; valet_token_t *token; now = switch_epoch_time_now(NULL); switch_mutex_lock(globals.mutex); if (now - globals.last_timeout_check < TOKEN_FREQ) { switch_mutex_unlock(globals.mutex); return; } globals.last_timeout_check = now; for (hi = switch_hash_first(NULL, globals.hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); switch_console_push_match(&matches, (const char *) var); } switch_mutex_unlock(globals.mutex); if (matches) { for (m = matches->head; m; m = m->next) { lot = valet_find_lot(m->val, SWITCH_FALSE); switch_mutex_lock(lot->mutex); top: for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) { switch_hash_this(i_hi, &i_var, NULL, &i_val); i_ext = (char *) i_var; token = (valet_token_t *) i_val; if (token->timeout > 0 && (token->timeout < now || token->timeout == 1)) { switch_core_hash_delete(lot->hash, i_ext); switch_safe_free(token); goto top; } } switch_mutex_unlock(lot->mutex); } switch_console_free_matches(&matches); } }
static switch_status_t handle_msg_session_nixevent(listener_t *listener, erlang_msg *msg, int arity, ei_x_buff * buf, ei_x_buff * rbuf) { char atom[MAXATOMLEN]; if (arity == 1) { ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badarg"); } else { session_elem_t *session; if ((session = find_session_elem_by_pid(listener, &msg->from))) { int custom = 0; int i = 0; switch_event_types_t type; switch_thread_rwlock_wrlock(session->event_rwlock); for (i = 1; i < arity; i++) { if (!ei_decode_atom(buf->buff, &buf->index, atom)) { if (custom) { switch_core_hash_delete(session->event_hash, atom); } else if (switch_name_event(atom, &type) == SWITCH_STATUS_SUCCESS) { uint32_t x = 0; if (type == SWITCH_EVENT_CUSTOM) { custom++; } else if (type == SWITCH_EVENT_ALL) { for (x = 0; x <= SWITCH_EVENT_ALL; x++) { session->event_list[x] = 0; } } else { if (session->event_list[SWITCH_EVENT_ALL]) { session->event_list[SWITCH_EVENT_ALL] = 0; for (x = 0; x < SWITCH_EVENT_ALL; x++) { session->event_list[x] = 1; } } session->event_list[type] = 0; } } } } switch_thread_rwlock_unlock(session->event_rwlock); ei_x_encode_atom(rbuf, "ok"); } else { /* no session for this pid */ ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "notlistening"); } } return SWITCH_STATUS_SUCCESS; }
/** * Stop receiving signals */ static void unsubscribe(const char *uuid, const char *signal_type, const char *jid) { char *key = switch_mprintf("%s:%s", uuid, signal_type); switch_mutex_lock(globals.subscribers_mutex); { switch_hash_t *signal_subscribers = switch_core_hash_find(globals.subscribers, key); if (signal_subscribers) { switch_core_hash_delete(signal_subscribers, jid); switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Unsubscribe %s => %s\n", signal_type, jid); /* clean up hash if empty */ if (!switch_core_hash_first(signal_subscribers)) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Destroy %s subscriber hash\n", signal_type); switch_core_hash_destroy(&signal_subscribers); switch_core_hash_delete(globals.subscribers, key); } } } switch_mutex_unlock(globals.subscribers_mutex); switch_safe_free(key); }
SWITCH_DECLARE(switch_status_t) switch_core_hash_delete_locked(switch_hash_t *hash, const char *key, switch_mutex_t *mutex) { if (mutex) { switch_mutex_lock(mutex); } switch_core_hash_delete(hash, key); if (mutex) { switch_mutex_unlock(mutex); } return SWITCH_STATUS_SUCCESS; }
SWITCH_DECLARE(switch_status_t) switch_core_hash_delete_wrlock(switch_hash_t *hash, const char *key, switch_thread_rwlock_t *rwlock) { if (rwlock) { switch_thread_rwlock_wrlock(rwlock); } switch_core_hash_delete(hash, key); if (rwlock) { switch_thread_rwlock_unlock(rwlock); } return SWITCH_STATUS_SUCCESS; }
static switch_status_t do_config(switch_bool_t reload) { /* Load up blacklists */ switch_xml_t xml, cfg, lists, list; switch_hash_index_t *hi = NULL; if (!(xml = switch_xml_open_cfg("mod_blacklist.conf", &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load configuration section\n"); return SWITCH_STATUS_FALSE; } switch_mutex_lock(globals.lists_mutex); /* Destroy any active lists */ while ((hi = switch_core_hash_first_iter( globals.lists, hi))) { const void *key; void *val; switch_core_hash_this(hi, &key, NULL, &val); blacklist_free((blacklist_t*)val); switch_core_hash_delete(globals.lists, (const char*)key); } if ((lists = switch_xml_child(cfg, "lists"))) { for (list = switch_xml_child(lists, "list"); list; list = list->next) { const char *name = switch_xml_attr_soft(list, "name"); const char *filename = switch_xml_attr_soft(list, "filename"); if (zstr(name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "list has no name\n"); continue; } if (zstr(filename)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "list [%s] has no filename\n", name); continue; } load_list(name, filename); } } switch_mutex_unlock(globals.lists_mutex); if (xml) { switch_xml_free(xml); xml = NULL; } return SWITCH_STATUS_SUCCESS; }
switch_status_t mod_amqp_logging_destroy(mod_amqp_logging_profile_t **prof) { mod_amqp_message_t *msg = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; mod_amqp_connection_t *conn = NULL, *conn_next = NULL; switch_memory_pool_t *pool; mod_amqp_logging_profile_t *profile; if (!prof || !*prof) { return SWITCH_STATUS_SUCCESS; } profile = *prof; pool = profile->pool; if (profile->name) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Profile[%s] shutting down...\n", profile->name); switch_core_hash_delete(globals.logging_hash, profile->name); } profile->running = 0; if (profile->logging_thread) { switch_thread_join(&status, profile->logging_thread); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Profile[%s] closing AMQP socket...\n", profile->name); for (conn = profile->conn_root; conn; conn = conn_next) { conn_next = conn->next; mod_amqp_connection_destroy(&conn); } profile->conn_active = NULL; profile->conn_root = NULL; while (profile->send_queue && switch_queue_trypop(profile->send_queue, (void**)&msg) == SWITCH_STATUS_SUCCESS) { mod_amqp_util_msg_destroy(&msg); } if (pool) { switch_core_destroy_memory_pool(&pool); } *prof = NULL; return SWITCH_STATUS_SUCCESS; }
static switch_status_t spy_on_hangup(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); char *data = switch_channel_get_private(channel, "_userspy_"); switch_thread_rwlock_wrlock(globals.spy_hash_lock); if ((switch_core_hash_delete(globals.spy_hash, data) != SWITCH_STATUS_SUCCESS)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No such key in userspy: %s \n", data); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Userspy deactivated on %s\n", data); globals.spy_count--; } switch_thread_rwlock_unlock(globals.spy_hash_lock); return SWITCH_STATUS_SUCCESS; }
static switch_status_t handle_msg_nixevent(listener_t *listener, int arity, ei_x_buff * buf, ei_x_buff * rbuf) { char atom[MAXATOMLEN]; if (arity == 1) { ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badarg"); } else { int custom = 0; int i = 0; switch_event_types_t type; for (i = 1; i < arity; i++) { if (!ei_decode_atom(buf->buff, &buf->index, atom)) { if (custom) { switch_core_hash_delete(listener->event_hash, atom); } else if (switch_name_event(atom, &type) == SWITCH_STATUS_SUCCESS) { uint32_t x = 0; if (type == SWITCH_EVENT_CUSTOM) { custom++; } else if (type == SWITCH_EVENT_ALL) { for (x = 0; x <= SWITCH_EVENT_ALL; x++) { listener->event_list[x] = 0; } } else { if (listener->event_list[SWITCH_EVENT_ALL]) { listener->event_list[SWITCH_EVENT_ALL] = 0; for (x = 0; x < SWITCH_EVENT_ALL; x++) { listener->event_list[x] = 1; } } listener->event_list[type] = 0; } } } } ei_x_encode_atom(rbuf, "ok"); } return SWITCH_STATUS_SUCCESS; }
switch_status_t mod_amqp_command_destroy(mod_amqp_command_profile_t **prof) { switch_status_t ret; mod_amqp_connection_t *conn = NULL, *conn_next = NULL; switch_memory_pool_t *pool; mod_amqp_command_profile_t *profile; if (!prof || !*prof) { return SWITCH_STATUS_SUCCESS; } profile = *prof; pool = profile->pool; if (profile->name) { switch_core_hash_delete(globals.command_hash, profile->name); } profile->running = 0; if (profile->command_thread) { switch_thread_join(&ret, profile->command_thread); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Profile[%s] closing AMQP socket...\n", profile->name); for (conn = profile->conn_root; conn; conn = conn_next) { mod_amqp_connection_destroy(&conn); } profile->conn_active = NULL; profile->conn_root = NULL; if (pool) { switch_core_destroy_memory_pool(&pool); } *prof = NULL; return SWITCH_STATUS_SUCCESS; }
static switch_status_t switch_sangoma_destroy(switch_codec_t *codec) { struct sangoma_transcoding_session *sess = codec->private_info; /* things that you may do here is closing files, sockets or other resources used during the codec session * no need to free memory allocated from the pool though, the owner of the pool takes care of that */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma destroy called.\n"); switch_mutex_lock(g_sessions_lock); if (sess->encoder.reply.codec_rtp_session) { sngtc_destroy_transcoding_session(sess->encoder.reply.codec_rtp_session); } if (sess->decoder.reply.codec_rtp_session) { sngtc_destroy_transcoding_session(sess->decoder.reply.codec_rtp_session); } switch_core_hash_delete(g_sessions_hash, sess->hashkey); switch_mutex_unlock(g_sessions_lock); return SWITCH_STATUS_SUCCESS; }
/** * Remove a URL from the hash map and mark it as eligible for replacement from the queue. */ static void url_cache_remove_soft(url_cache_t *cache, switch_core_session_t *session, cached_url_t *url) { switch_core_hash_delete(cache->map, url->url); url->used = 0; url->status = CACHED_URL_REMOVE; }
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] = ""; 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; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); if (source->shuffle) { skip = do_rand(); } 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; } switch_yield(1000000); while (RUNNING) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; if (fd > -1) { char *p; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) { *p = '\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 (skip > 0) { skip--; continue; } 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_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_timer_init(&timer, source->timer_name, source->interval, 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; } while (RUNNING) { 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 -= 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_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_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (is_open) { if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } is_open = 0; } else { if (use_fh == &source->chime_fh && source->chime_max) { source->chime_max_counter += source->samples; if (source->chime_max_counter >= source->chime_max) { source->chime_max_counter = 0; switch_core_file_close(use_fh); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } switch_buffer_write(audio_buffer, abuf, olen * 2); } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) { continue; } switch_mutex_lock(cp->audio_mutex); if (switch_buffer_inuse(cp->audio_buffer) > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d]\n", cp->func, cp->file, cp->line); 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); } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(); } } switch_dir_close(source->dir_handle); source->dir_handle = NULL; } done: 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); 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; }
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; }
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { portaudio_stream_source_t *source = obj; portaudio_stream_context_t *cp; int samples = 0; int bused, bytesToWrite; switch_mutex_lock(globals.mutex); globals.threads++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.source_hash, source->sourcename, source); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_create(&source->rwlock, source->pool); if (engage_device(source, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Dev %d cant be engaged !\n", (int) source->sourcedev); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Dev %d engaged at %d rate!\n", (int) source->sourcedev, (int) source->rate); if (globals.running && !source->stopped) { source->ready = 1; if (!source->audio_stream) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Audio Stream wops!\n"); source->stopped = 0; source->ready = 0; } else { while (globals.running && !source->stopped) { samples = 0; switch_mutex_lock(source->device_lock); samples = ReadAudioStream(source->audio_stream, source->databuf, source->read_codec.implementation->samples_per_packet, 0, &source->timer); switch_mutex_unlock(source->device_lock); if (samples) { bytesToWrite = source->samples; if (samples < bytesToWrite) { bytesToWrite = samples; } bytesToWrite *= source->audio_stream->bytesPerFrame; if (source->total) { switch_mutex_lock(source->mutex); for (cp = source->context_list; cp; cp = cp->next) { switch_mutex_lock(cp->audio_mutex); bused = switch_buffer_inuse(cp->audio_buffer); if (bused > source->samples * 768) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d] %d used %d max\n", cp->func, cp->file, cp->line, (int) bused, (int) (source->samples * 768)); switch_buffer_zero(cp->audio_buffer); } else { switch_buffer_write(cp->audio_buffer, source->databuf, bytesToWrite); } switch_mutex_unlock(cp->audio_mutex); } switch_mutex_unlock(source->mutex); } } } } } } source->ready = 0; switch_mutex_lock(globals.mutex); switch_core_hash_delete(globals.source_hash, source->sourcename); switch_mutex_unlock(globals.mutex); switch_thread_rwlock_wrlock(source->rwlock); switch_thread_rwlock_unlock(source->rwlock); switch_mutex_lock(source->device_lock); CloseAudioStream(source->audio_stream); if (switch_core_codec_ready(&source->read_codec)) { switch_core_codec_destroy(&source->read_codec); switch_core_codec_destroy(&source->write_codec); } if (switch_core_codec_ready(&source->write_codec)) { switch_core_codec_destroy(&source->write_codec); } switch_mutex_unlock(source->device_lock); switch_core_destroy_memory_pool(&source->pool); switch_mutex_lock(globals.mutex); globals.threads--; switch_mutex_unlock(globals.mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " thread ending succesfully !\n"); switch_thread_exit(thread, SWITCH_STATUS_SUCCESS); return NULL; }
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] = ""; 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; switch_mutex_lock(globals.mutex); THREADS++; switch_mutex_unlock(globals.mutex); if (!source->prebuf) { source->prebuf = DEFAULT_PREBUFFER_SIZE; } switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); if (source->shuffle) { skip = do_rand(); } 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; } switch_yield(1000000); while (RUNNING && !source->stopped) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; if (fd > -1) { char *p; if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { if ((p = strchr(path_buf, '\r')) || (p = strchr(path_buf, '\n'))) { *p = '\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 (skip > 0) { skip--; continue; } 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_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_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; } 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_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_test_flag((&source->chime_fh), SWITCH_FILE_OPEN)) { use_fh = &source->chime_fh; } } retry: 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); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; //switch_core_file_close(&fh); } } } if (is_open) { if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } 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); source->chime_counter = source->rate * source->chime_freq; use_fh = &fh; goto retry; } } switch_buffer_write(audio_buffer, abuf, olen * 2); } } used = switch_buffer_inuse(audio_buffer); if (!used && !is_open) { break; } if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); if (source->total) { uint32_t bused = 0; switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { 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); } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { skip = do_rand(); } } 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: 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); 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; }