diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-19 21:33:37 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-19 21:33:37 +0000 |
commit | e66896a7c7bd656646aeffd947f27c8245ee8ced (patch) | |
tree | bd07aeb22c21a5ccb6f6fae3f7adbb89536db5ef | |
parent | 7dad1223227103cbd5a3603e5a8fd847effa5a96 (diff) |
Merged revisions 230509 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
................
r230509 | dvossel | 2009-11-19 15:26:21 -0600 (Thu, 19 Nov 2009) | 17 lines
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: http://svn.digium.com/svn/asterisk/branches/1.6.0@230512 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | apps/app_mixmonitor.c | 94 |
1 files changed, 70 insertions, 24 deletions
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index e78cb1b7f..d30130748 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -140,18 +140,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) @@ -160,6 +163,7 @@ static void mixmonitor_ds_destroy(void *data) ast_mutex_lock(&mixmonitor_ds->lock); mixmonitor_ds->chan = NULL; + mixmonitor_ds->audiohook = NULL; mixmonitor_ds->destruction_ok = 1; ast_cond_signal(&mixmonitor_ds->destruction_condition); ast_mutex_unlock(&mixmonitor_ds->lock); @@ -180,6 +184,20 @@ static struct ast_datastore_info mixmonitor_ds_info = { .chan_fixup = mixmonitor_ds_chan_fixup, }; +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; @@ -219,11 +237,11 @@ static void *mixmonitor_thread(void *obj) int errflag = 0; 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; @@ -235,6 +253,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); + ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { /* Initialize the file if not already done so */ @@ -266,26 +288,26 @@ 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); + /* 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_mutex_lock(&mixmonitor->mixmonitor_ds->lock); - 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); - ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); mixmonitor_free(mixmonitor); return NULL; @@ -312,6 +334,7 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ mixmonitor_ds->chan = chan; + mixmonitor_ds->audiohook = &mixmonitor->audiohook; datastore->data = mixmonitor_ds; ast_channel_lock(chan); @@ -353,6 +376,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 (setup_mixmonitor_ds(mixmonitor, chan)) { @@ -369,12 +398,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) @@ -478,13 +501,36 @@ static int stop_mixmonitor_exec(struct ast_channel *chan, void *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_channel_datastore_free(datastore); + } } + ast_channel_unlock(chan); - ast_audiohook_detach_source(chan, mixmonitor_spy_type); return 0; } |