From eb6025a49adc54718b4afccbbea462bb6ba9e38e Mon Sep 17 00:00:00 2001 From: David Vossel Date: Thu, 19 Nov 2009 21:26:21 +0000 Subject: Merged revisions 230508 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r230508 | dvossel | 2009-11-19 15:22:46 -0600 (Thu, 19 Nov 2009) | 10 lines fixes MixMonitor thread not exiting when StopMixMonitor is used (closes issue #16152) Reported by: AlexMS Patches: stopmixmonitor_1.4.diff uploaded by dvossel (license 671) Tested by: dvossel, AlexMS Review: https://reviewboard.asterisk.org/r/424/ ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@230509 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_mixmonitor.c | 96 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 26 deletions(-) (limited to 'apps/app_mixmonitor.c') diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 45b2da913..0e08977f6 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -177,19 +177,21 @@ struct mixmonitor_ds { * immediately during stop_mixmonitor or channel destruction. */ int fs_quit; struct ast_filestream *fs; - + struct ast_audiohook *audiohook; }; +/*! + * \internal + * \pre mixmonitor_ds must be locked before calling this function + */ static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds) { - ast_mutex_lock(&mixmonitor_ds->lock); if (mixmonitor_ds->fs) { ast_closestream(mixmonitor_ds->fs); mixmonitor_ds->fs = NULL; mixmonitor_ds->fs_quit = 1; ast_verb(2, "MixMonitor close filestream\n"); } - ast_mutex_unlock(&mixmonitor_ds->lock); } static void mixmonitor_ds_destroy(void *data) @@ -197,6 +199,7 @@ static void mixmonitor_ds_destroy(void *data) struct mixmonitor_ds *mixmonitor_ds = data; ast_mutex_lock(&mixmonitor_ds->lock); + mixmonitor_ds->audiohook = NULL; mixmonitor_ds->destruction_ok = 1; ast_cond_signal(&mixmonitor_ds->destruction_condition); ast_mutex_unlock(&mixmonitor_ds->lock); @@ -207,6 +210,20 @@ static struct ast_datastore_info mixmonitor_ds_info = { .destroy = mixmonitor_ds_destroy, }; +static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor) +{ + if (mixmonitor->mixmonitor_ds) { + ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); + mixmonitor->mixmonitor_ds->audiohook = NULL; + ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); + } + /* kill the audiohook.*/ + ast_audiohook_lock(&mixmonitor->audiohook); + ast_audiohook_detach(&mixmonitor->audiohook); + ast_audiohook_unlock(&mixmonitor->audiohook); + ast_audiohook_destroy(&mixmonitor->audiohook); +} + static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) { struct ast_channel *peer = NULL; @@ -246,10 +263,10 @@ static void *mixmonitor_thread(void *obj) ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); - ast_audiohook_lock(&mixmonitor->audiohook); - fs = &mixmonitor->mixmonitor_ds->fs; + /* The audiohook must enter and exit the loop locked */ + ast_audiohook_lock(&mixmonitor->audiohook); while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { struct ast_frame *fr = NULL; @@ -261,6 +278,10 @@ static void *mixmonitor_thread(void *obj) if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) continue; + /* audiohook lock is not required for the next block. + * Unlock it, but remember to lock it before looping or exiting */ + ast_audiohook_unlock(&mixmonitor->audiohook); + if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) { ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); /* Initialize the file if not already done so */ @@ -292,28 +313,27 @@ static void *mixmonitor_thread(void *obj) /* All done! free it. */ ast_frame_free(fr, 0); + ast_audiohook_lock(&mixmonitor->audiohook); } - - ast_audiohook_detach(&mixmonitor->audiohook); ast_audiohook_unlock(&mixmonitor->audiohook); - ast_audiohook_destroy(&mixmonitor->audiohook); - - mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); - - - if (mixmonitor->post_process) { - ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); - ast_safe_system(mixmonitor->post_process); - } ast_autochan_destroy(mixmonitor->autochan); + /* Datastore cleanup. close the filestream and wait for ds destruction */ ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); + mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); if (!mixmonitor->mixmonitor_ds->destruction_ok) { ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); } ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); + /* kill the audiohook */ + destroy_monitor_audiohook(mixmonitor); + + if (mixmonitor->post_process) { + ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); + ast_safe_system(mixmonitor->post_process); + } ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); mixmonitor_free(mixmonitor); @@ -339,6 +359,7 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel return -1; } + mixmonitor_ds->audiohook = &mixmonitor->audiohook; datastore->data = mixmonitor_ds; ast_channel_lock(chan); @@ -380,6 +401,12 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename return; } + /* Setup the actual spy before creating our thread */ + if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { + mixmonitor_free(mixmonitor); + return; + } + /* Copy over flags and channel name */ mixmonitor->flags = flags; if (!(mixmonitor->autochan = ast_autochan_setup(chan))) { @@ -402,12 +429,6 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; strcpy(mixmonitor->filename, filename); - /* Setup the actual spy before creating our thread */ - if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { - mixmonitor_free(mixmonitor); - return; - } - ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); if (readvol) @@ -511,13 +532,36 @@ static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data) { struct ast_datastore *datastore = NULL; - /* closing the filestream here guarantees the file is avaliable to the dialplan - * after calling StopMixMonitor */ + ast_channel_lock(chan); + ast_audiohook_detach_source(chan, mixmonitor_spy_type); if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { - mixmonitor_ds_close_fs(datastore->data); + struct mixmonitor_ds *mixmonitor_ds = datastore->data; + + ast_mutex_lock(&mixmonitor_ds->lock); + + /* closing the filestream here guarantees the file is avaliable to the dialplan + * after calling StopMixMonitor */ + mixmonitor_ds_close_fs(mixmonitor_ds); + + /* The mixmonitor thread may be waiting on the audiohook trigger. + * In order to exit from the mixmonitor loop before waiting on channel + * destruction, poke the audiohook trigger. */ + if (mixmonitor_ds->audiohook) { + ast_audiohook_lock(mixmonitor_ds->audiohook); + ast_cond_signal(&mixmonitor_ds->audiohook->trigger); + ast_audiohook_unlock(mixmonitor_ds->audiohook); + mixmonitor_ds->audiohook = NULL; + } + + ast_mutex_unlock(&mixmonitor_ds->lock); + + /* Remove the datastore so the monitor thread can exit */ + if (!ast_channel_datastore_remove(chan, datastore)) { + ast_datastore_free(datastore); + } } + ast_channel_unlock(chan); - ast_audiohook_detach_source(chan, mixmonitor_spy_type); return 0; } -- cgit v1.2.3