From 66fe6e5a4610845be404259eed38bd32946acc9d Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 3 Mar 2016 18:37:42 -0600 Subject: [PATCH] FS-8811 #comment please test --- .../applications/mod_dptools/mod_dptools.c | 2 + .../mod_local_stream/mod_local_stream.c | 285 +++++++++++++----- src/switch_core_file.c | 15 +- 3 files changed, 213 insertions(+), 89 deletions(-) diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index cf31deea75..6ea1cefd4d 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -2808,6 +2808,8 @@ SWITCH_STANDARD_APP(playback_function) switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, ""); status = switch_ivr_play_file(session, &fh, file, &args); + switch_assert(!(fh.flags & SWITCH_FILE_OPEN)); + switch (status) { case SWITCH_STATUS_SUCCESS: diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index eb465cdaf6..c84d003c38 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -68,10 +68,13 @@ struct local_stream_context { int sent_png; int last_w; int last_h; + int newres; int serno; int pop_count; + switch_size_t blank; switch_image_t *banner_img; switch_time_t banner_timeout; + switch_memory_pool_t *pool; struct local_stream_context *next; }; @@ -116,6 +119,7 @@ struct local_stream_source { int serno; switch_size_t abuflen; switch_byte_t *abuf; + switch_timer_t timer; }; typedef struct local_stream_source local_stream_source_t; @@ -173,28 +177,30 @@ switch_status_t list_streams(const char *line, const char *cursor, switch_consol static int do_rand(uint32_t count) { - double r; - int index; + int r = 0; - if (count < 3) return 0; + switch_mutex_lock(globals.mutex); + r = (rand() % count) + 1; + switch_mutex_unlock(globals.mutex); - r = ((double) rand() / ((double) (RAND_MAX) + (double) (1))); - index = (int) (r * count) + 1; - - return index; + return r; } static void flush_video_queue(switch_queue_t *q) { - void *pop; + void *pop = NULL; if (switch_queue_size(q) == 0) { return; } while (switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS) { - switch_image_t *img = (switch_image_t *) pop; - switch_img_free(&img); + if (pop) { + switch_image_t *img = (switch_image_t *) pop; + switch_img_free(&img); + } else { + break; + } } } @@ -204,8 +210,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void volatile local_stream_source_t *s = (local_stream_source_t *) obj; local_stream_source_t *source = (local_stream_source_t *) s; switch_file_handle_t fh = { 0 }; - char file_buf[128] = "", path_buf[512] = "", last_path[512], png_buf[512] = "", tmp_buf[512] = ""; - switch_timer_t timer = { 0 }; + char file_buf[128] = "", path_buf[512] = "", last_path[512] = "", png_buf[512] = "", tmp_buf[512] = ""; int fd = -1; switch_buffer_t *audio_buffer; switch_byte_t *dist_buf; @@ -227,12 +232,21 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void do_shuffle = 1; } + if (source->prebuf < source->abuflen) { + source->prebuf = source->abuflen; + } + 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 (switch_core_timer_init(&source->timer, source->timer_name, source->interval, (int)source->samples, source->pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); + RUNNING = 0; + } + if (RUNNING) { source->ready = 1; switch_mutex_lock(globals.mutex); @@ -242,6 +256,11 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void while (RUNNING && !source->stopped && source->ready) { const char *fname; + + if (source->dir_handle) { + switch_dir_close(source->dir_handle); + source->dir_handle = NULL; + } if (temp_pool) { switch_core_destroy_memory_pool(&temp_pool); @@ -277,6 +296,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void while (RUNNING && !source->stopped) { switch_size_t olen; const char *artist = NULL, *title = NULL; + char tmp_space[128] = ""; if (fd > -1) { char *pb; @@ -305,6 +325,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } + if (dir_count > 1 && !strcmp(last_path, path_buf)) { continue; } @@ -328,25 +349,19 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void continue; } + switch_buffer_zero(audio_buffer); + if (switch_core_file_has_video(&fh)) { flush_video_queue(source->video_q); } - switch_buffer_zero(audio_buffer); - - 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) { + if (switch_file_exists(png_buf, temp_pool) == SWITCH_STATUS_SUCCESS) { source->cover_art = switch_img_read_png(png_buf, SWITCH_IMG_FMT_I420); } } @@ -357,22 +372,68 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void 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 && !artist) { + char *e, *p, *args[3]; + int argc; + + switch_set_string(tmp_space, path_buf); + p = tmp_space; + + while((e = strchr(p, '/'))) { + *e = '\0'; + p = e+1; + } + + argc = switch_split(p, '-', args); + + if (argc > 0) { + while(*args[0] == ' ') { + args[0]++; + } + + while(end_of(args[0]) == ' ') { + end_of(args[0]) = '\0'; + } + + artist = args[0]; + + if (argc > 1) { + while(*args[1] == ' ') { + args[1]++; + } + while(end_of(args[1]) == ' ') { + end_of(args[1]) = '\0'; + } + title = args[1]; + } + + if (!title) { + title = artist; + artist = NULL; + } + } else { + title = p; + artist = NULL; + } + } 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); + switch_core_timer_next(&source->timer); olen = source->samples; if (source->chime_total) { @@ -419,9 +480,10 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void source->hup = 0; if (is_open) { is_open = 0; - + switch_core_file_close(use_fh); flush_video_queue(source->video_q); + switch_buffer_zero(audio_buffer); if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; switch_core_file_close(&fh); @@ -431,10 +493,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } - if (!is_open) { - switch_buffer_zero(audio_buffer); - break; - } else { + if (is_open) { int svr = 0; if (switch_core_has_video() && switch_core_file_has_video(use_fh)) { @@ -473,6 +532,8 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void olen = source->samples; } + switch_assert(source->abuflen >= olen * 2 * source->channels); + if (switch_core_file_read(use_fh, source->abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); flush_video_queue(source->video_q); @@ -510,35 +571,41 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void break; } - source->prebuf = (uint32_t)(source->samples * 2 * source->channels); - if (!source->total) { flush_video_queue(source->video_q); switch_buffer_zero(audio_buffer); - } else if (used > source->samples * 2 * source->channels) { - //if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) { + } else if (used && (!is_open || used >= source->abuflen)) { void *pop; - uint32_t bused; + uint32_t bused = 0; local_stream_context_t *cp = NULL; + + switch_assert(source->abuflen <= source->prebuf); + used = switch_buffer_read(audio_buffer, dist_buf, source->abuflen); - used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels); - - 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)) { + + if (!cp->ready) { continue; } - + switch_mutex_lock(cp->audio_mutex); + + if (switch_test_flag(cp->handle, SWITCH_FILE_OPEN)) { + 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)) { + switch_mutex_unlock(cp->audio_mutex); + continue; + } + } + 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); @@ -552,15 +619,24 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) { - switch_image_t *img = (switch_image_t *) pop; + switch_image_t *img; 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); + if (!pop) break; + + img = (switch_image_t *) pop; + + switch_mutex_lock(source->mutex); + if (source->context_list) { + if (source->total == 1) { + switch_queue_push(source->context_list->video_q, img); + } else { for (cp = source->context_list; cp && RUNNING; cp = cp->next) { + + if (!cp->ready) { + continue; + } + if (cp->video_q) { imgcp = NULL; switch_img_copy(img, &imgcp); @@ -570,24 +646,20 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } } - } - switch_mutex_unlock(source->mutex); + } + switch_img_free(&img); } - switch_img_free(&img); } + switch_mutex_unlock(source->mutex); } } } - 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); @@ -635,6 +707,9 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s partially reloaded.\n",source->name); source->part_reload = 0; + if (source->timer.interval) { + switch_core_timer_destroy(&source->timer); + } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "local_stream://%s fully reloaded.\n",source->name); @@ -647,6 +722,15 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void done: + if (source->dir_handle) { + switch_dir_close(source->dir_handle); + source->dir_handle = NULL; + } + + if (source->timer.interval) { + switch_core_timer_destroy(&source->timer); + } + switch_safe_free(source->banner_txt); if (switch_test_flag((&fh), SWITCH_FILE_OPEN)) { @@ -692,6 +776,7 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons local_stream_source_t *source; char *alt_path = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_memory_pool_t *pool; /* already buffering a step back, so always disable it */ handle->pre_buffer_datalen = 0; @@ -727,11 +812,20 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons goto end; } - if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { + //if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n"); + // abort(); + //} + + pool = handle->memory_pool; + + if ((context = switch_core_alloc(pool, sizeof(*context))) == 0) { abort(); } - switch_queue_create(&context->video_q, 500, handle->memory_pool); + context->pool = pool; + + switch_queue_create(&context->video_q, 500, context->pool); handle->samples = 0; handle->samplerate = source->rate; @@ -744,7 +838,7 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons handle->interval = source->interval; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening Stream [%s] %dhz\n", path, handle->samplerate); - switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); + switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); status = SWITCH_STATUS_MEMERR; @@ -779,36 +873,50 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons static switch_status_t local_stream_file_close(switch_file_handle_t *handle) { - local_stream_context_t *cp, *last = NULL, *context = handle->private_info; + local_stream_context_t *context = NULL, *last = NULL, *cp = NULL; + local_stream_source_t *source; + context = handle->private_info; + switch_assert(context); + + //pool = context->pool; + source = context->source; context->ready = 0; - switch_mutex_lock(context->source->mutex); - for (cp = context->source->context_list; cp; cp = cp->next) { + switch_mutex_lock(source->mutex); + for (cp = source->context_list; cp; cp = cp->next) { if (cp == context) { if (last) { last->next = cp->next; } else { - context->source->context_list = cp->next; - } + source->context_list = cp->next; + } break; } last = cp; } + + switch_mutex_lock(context->audio_mutex); - if (context->source->has_video) { + if (source->has_video) { 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); } + + source->total--; 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); + switch_mutex_unlock(context->audio_mutex); + //switch_core_destroy_memory_pool(&pool); + + context->handle = NULL; + handle->private_info = NULL; + switch_mutex_unlock(source->mutex); + + switch_thread_rwlock_unlock(source->rwlock); return SWITCH_STATUS_SUCCESS; } @@ -887,6 +995,9 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle frame->img = (switch_image_t *) pop; context->sent_png = 0; + if (frame->img->d_w != context->last_w || frame->img->d_h != context->last_h) { + context->newres = 1; + } context->last_w = frame->img->d_w; context->last_h = frame->img->d_h; goto got_img; @@ -920,6 +1031,10 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle if (context->source->banner_txt) { if ((!context->banner_timeout || context->banner_timeout >= now)) { + if (context->newres) { + switch_img_free(&context->banner_img); + context->newres = 0; + } if (!context->banner_img) { context->banner_img = switch_img_write_text_img(context->last_w, context->last_h, SWITCH_TRUE, context->source->banner_txt); context->banner_timeout = now + 5000000; @@ -935,6 +1050,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle if (frame->img && context->banner_img && frame->img->d_w >= context->banner_img->d_w) { //switch_img_overlay(frame->img, context->banner_img, 0, frame->img->d_h - context->banner_img->d_h, 100); switch_img_patch(frame->img, context->banner_img, 0, frame->img->d_h - context->banner_img->d_h); + //switch_img_patch(frame->img, context->banner_img, 0, 0); } return SWITCH_STATUS_SUCCESS; @@ -944,29 +1060,36 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void { local_stream_context_t *context = handle->private_info; switch_size_t bytes = 0; - size_t need = *len * 2 * handle->real_channels; + size_t need; - if (!context->source->ready) { + if (!(context->ready && context->source->ready)) { *len = 0; return SWITCH_STATUS_FALSE; } switch_mutex_lock(context->audio_mutex); + need = *len * 2 * context->source->channels; + if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) { - *len = bytes / 2 / handle->real_channels; + *len = bytes / 2 / context->source->channels; } else { - size_t blank = (handle->samplerate / 20) * 2 * handle->real_channels; + size_t blank; + + switch_assert(handle->samplerate <= 48000); + switch_assert(handle->real_channels <= 2); + + blank = (handle->samplerate / 4) * 2 * handle->real_channels; if (need > blank) { need = blank; } + memset(data, 0, need); - *len = need / 2 / handle->real_channels; + *len = need / 2 / context->source->channels; } - - switch_mutex_unlock(context->audio_mutex); handle->sample_count += *len; + return SWITCH_STATUS_SUCCESS; } @@ -1059,8 +1182,8 @@ static void launch_thread(const char *name, const char *path, switch_xml_t direc } source->samples = switch_samples_per_packet(source->rate, source->interval); - source->abuflen = (source->samples * 2 * source->channels) + 1024; - source->abuf = switch_core_alloc(source->pool, source->abuflen); + source->abuflen = (source->samples * 2 * source->channels); + source->abuf = switch_core_alloc(source->pool, source->abuflen + 1024); switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool); switch_threadattr_create(&thd_attr, source->pool); switch_threadattr_detach_set(thd_attr, 1); diff --git a/src/switch_core_file.c b/src/switch_core_file.c index b241fce0cb..7143074c5d 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -782,6 +782,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh) switch_resample_destroy(&fh->resampler); + if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) { + switch_core_destroy_memory_pool(&fh->memory_pool); + } + + fh->memory_pool = NULL; + + switch_safe_free(fh->dbuf); if (fh->spool_path) { char *command; @@ -799,16 +806,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh) free(command); } - UNPROTECT_INTERFACE(fh->file_interface); - if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) { - switch_core_destroy_memory_pool(&fh->memory_pool); - } - - switch_safe_free(fh->dbuf); - - return status; }