diff options
-rw-r--r-- | apps/app_meetme.c | 172 |
1 files changed, 148 insertions, 24 deletions
diff --git a/apps/app_meetme.c b/apps/app_meetme.c index f40d6b491..7b49e0147 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -54,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/translate.h" #include "asterisk/ulaw.h" +#include "asterisk/astobj2.h" #include "asterisk/devicestate.h" #include "asterisk/dial.h" #include "asterisk/causes.h" @@ -362,6 +363,20 @@ static const char *slatrunk_desc = #define MAX_PIN 80 #define OPTIONS_LEN 32 +enum announcetypes { + CONF_HASJOIN, + CONF_HASLEFT +}; + +struct announce_listitem { + AST_LIST_ENTRY(announce_listitem) entry; + char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */ + char language[MAX_LANGUAGE]; + struct ast_channel *confchan; + int confusers; + enum announcetypes announcetype; +}; + /*! \brief The MeetMe Conference object */ struct ast_conference { ast_mutex_t playlock; /*!< Conference specific lock (players) */ @@ -397,6 +412,13 @@ struct ast_conference { struct ast_trans_pvt *transpath[32]; AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist; AST_LIST_ENTRY(ast_conference) list; + /* announce_thread related data */ + pthread_t announcethread; + ast_mutex_t announcethreadlock; + unsigned int announcethread_stop:1; + ast_cond_t announcelist_addition; + AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist; + ast_mutex_t announcelistlock; }; static AST_LIST_HEAD_STATIC(confs, ast_conference); @@ -834,6 +856,8 @@ static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin ast_mutex_init(&cnf->listenlock); cnf->recordthread = AST_PTHREADT_NULL; ast_mutex_init(&cnf->recordthreadlock); + cnf->announcethread = AST_PTHREADT_NULL; + ast_mutex_init(&cnf->announcethreadlock); ast_copy_string(cnf->confno, confno, sizeof(cnf->confno)); ast_copy_string(cnf->pin, pin, sizeof(cnf->pin)); ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin)); @@ -1398,6 +1422,7 @@ static void conf_flush(int fd, struct ast_channel *chan) static int conf_free(struct ast_conference *conf) { int x; + struct announce_listitem *item; AST_LIST_REMOVE(&confs, conf, list); manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno); @@ -1420,6 +1445,20 @@ static int conf_free(struct ast_conference *conf) if (conf->transpath[x]) ast_translator_free_path(conf->transpath[x]); } + if (conf->announcethread != AST_PTHREADT_NULL) { + ast_mutex_lock(&conf->announcelistlock); + conf->announcethread_stop = 1; + ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT); + ast_cond_signal(&conf->announcelist_addition); + ast_mutex_unlock(&conf->announcelistlock); + pthread_join(conf->announcethread, NULL); + + while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) { + ast_filedelete(item->namerecloc, NULL); + ao2_ref(item, -1); + } + ast_mutex_destroy(&conf->announcelistlock); + } if (conf->origframe) ast_frfree(conf->origframe); if (conf->lchan) @@ -1437,6 +1476,7 @@ static int conf_free(struct ast_conference *conf) ast_mutex_destroy(&conf->playlock); ast_mutex_destroy(&conf->listenlock); ast_mutex_destroy(&conf->recordthreadlock); + ast_mutex_destroy(&conf->announcethreadlock); ast_free(conf); return 0; @@ -1618,6 +1658,73 @@ static void conf_start_moh(struct ast_channel *chan, const char *musicclass) ast_channel_unlock(chan); } +static const char *get_announce_filename(enum announcetypes type) +{ + switch (type) { + case CONF_HASLEFT: + return "conf-hasleft"; + break; + case CONF_HASJOIN: + return "conf-hasjoin"; + break; + default: + return ""; + } +} + +static void *announce_thread(void *data) +{ + struct announce_listitem *current; + struct ast_conference *conf = data; + int res; + char filename[PATH_MAX] = ""; + AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list; + AST_LIST_HEAD_INIT_NOLOCK(&local_list); + + while (!conf->announcethread_stop) { + ast_mutex_lock(&conf->announcelistlock); + if (conf->announcethread_stop) { + ast_mutex_unlock(&conf->announcelistlock); + break; + } + if (AST_LIST_EMPTY(&conf->announcelist)) + ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock); + + AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry); + AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); + + ast_mutex_unlock(&conf->announcelistlock); + if (conf->announcethread_stop) { + break; + } + + for (; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) { + ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc); + if (!ast_fileexists(current->namerecloc, NULL, NULL)) + continue; + if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) { + if (!ast_streamfile(current->confchan, current->namerecloc, current->language)) + res = ast_waitstream(current->confchan, ""); + if (!res) { + ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename)); + if (!ast_streamfile(current->confchan, filename, current->language)) + ast_waitstream(current->confchan, ""); + } + } + if (current->announcetype == CONF_HASLEFT) { + ast_filedelete(current->namerecloc, NULL); + } + } + } + + /* thread marked to stop, clean up */ + while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) { + ast_filedelete(current->namerecloc, NULL); + ao2_ref(current, -1); + } + return NULL; +} + static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[]) { struct ast_conf_user *user = NULL; @@ -1800,6 +1907,14 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c } ast_mutex_unlock(&conf->recordthreadlock); + ast_mutex_lock(&conf->announcethreadlock); + if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { + ast_mutex_init(&conf->announcelistlock); + AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist); + ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf); + } + ast_mutex_unlock(&conf->announcethreadlock); + time(&user->jointime); user->timelimit = timelimit; @@ -2040,15 +2155,25 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c dahdic.chan = 0; dahdic.confno = conf->dahdiconf; - ast_mutex_lock(&conf->playlock); - if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { - if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) { - if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) - ast_waitstream(conf->chan, ""); - if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language)) - ast_waitstream(conf->chan, ""); + struct announce_listitem *item; + if (!(item = ao2_alloc(sizeof(*item), NULL))) + return -1; + ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); + ast_copy_string(item->language, chan->language, sizeof(item->language)); + item->confchan = conf->chan; + item->confusers = conf->users; + item->announcetype = CONF_HASJOIN; + ast_mutex_lock(&conf->announcelistlock); + ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */ + AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); + ast_cond_signal(&conf->announcelist_addition); + ast_mutex_unlock(&conf->announcelistlock); + + while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) { + ; } + ao2_ref(item, -1); } if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers) @@ -2063,7 +2188,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { ast_log(LOG_WARNING, "Error setting conference\n"); close(fd); - ast_mutex_unlock(&conf->playlock); goto outrun; } ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf); @@ -2091,8 +2215,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c conf_play(chan, conf, ENTER); } - ast_mutex_unlock(&conf->playlock); - conf_flush(fd, chan); if (confflags & CONFFLAG_AGI) { @@ -2886,25 +3008,27 @@ bailoutandtrynormal: reset_volumes(user); - AST_LIST_LOCK(&confs); if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { conf_play(chan, conf, LEAVE); } - if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) { - if (ast_fileexists(user->namerecloc, NULL, NULL)) { - if ((conf->chan) && (conf->users > 1)) { - if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) { - ast_waitstream(conf->chan, ""); - } - if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language)) { - ast_waitstream(conf->chan, ""); - } - } - ast_filedelete(user->namerecloc, NULL); - } + if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { + struct announce_listitem *item; + if (!(item = ao2_alloc(sizeof(*item), NULL))) + return -1; + ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc)); + ast_copy_string(item->language, chan->language, sizeof(item->language)); + item->confchan = conf->chan; + item->confusers = conf->users; + item->announcetype = CONF_HASLEFT; + ast_mutex_lock(&conf->announcelistlock); + AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry); + ast_cond_signal(&conf->announcelist_addition); + ast_mutex_unlock(&conf->announcelistlock); + } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) { + /* Last person is leaving, so no reason to try and announce, but should delete the name recording */ + ast_filedelete(user->namerecloc, NULL); } - AST_LIST_UNLOCK(&confs); outrun: AST_LIST_LOCK(&confs); |