summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/res_musiconhold.c74
1 files changed, 46 insertions, 28 deletions
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 9a66b7518..2badd520c 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -149,6 +149,9 @@ struct mohclass {
int srcfd;
/*! FD for timing source */
int pseudofd;
+ /*! Number of users */
+ int inuse;
+ unsigned int delete:1;
AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list;
};
@@ -167,6 +170,8 @@ AST_RWLIST_HEAD_STATIC(mohclasses, mohclass);
#define MPG_123 "/usr/bin/mpg123"
#define MAX_MP3S 256
+static int ast_moh_destroy_one(struct mohclass *moh);
+static int reload(void);
static void ast_moh_free_class(struct mohclass **mohclass)
{
@@ -209,6 +214,8 @@ static void moh_files_release(struct ast_channel *chan, void *data)
}
state->save_pos = state->pos;
}
+ if (state->class->delete && ast_atomic_dec_and_test(&state->class->inuse))
+ ast_moh_destroy_one(state->class);
}
@@ -713,6 +720,8 @@ static void moh_release(struct ast_channel *chan, void *data)
close(moh->pipe[0]);
close(moh->pipe[1]);
oldwfmt = moh->origwfmt;
+ if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse))
+ ast_moh_destroy_one(moh->parent);
ast_free(moh);
if (chan) {
if (oldwfmt && ast_set_write_format(chan, oldwfmt))
@@ -871,8 +880,11 @@ static int moh_register(struct mohclass *moh, int reload)
#ifdef HAVE_ZAPTEL
int x;
#endif
+ struct mohclass *mohclass = NULL;
+
AST_RWLIST_WRLOCK(&mohclasses);
- if (get_mohbyname(moh->name, 0)) {
+ if ((mohclass = get_mohbyname(moh->name, 0))) {
+ mohclass->delete = 0;
if (reload) {
ast_debug(1, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
} else {
@@ -971,6 +983,8 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
mohclass = get_mohbyname(interpclass, 1);
if (!mohclass)
mohclass = get_mohbyname("default", 1);
+ if (mohclass)
+ ast_atomic_fetchadd_int(&mohclass->inuse, +1);
AST_RWLIST_UNLOCK(&mohclasses);
if (!mohclass)
@@ -1000,7 +1014,7 @@ static struct mohclass *moh_class_malloc(void)
{
struct mohclass *class;
- if ((class = ast_calloc(1, sizeof(*class))))
+ if ((class = ast_calloc(1, sizeof(*class))))
class->format = AST_FORMAT_SLINEAR;
return class;
@@ -1020,6 +1034,14 @@ static int load_moh_classes(int reload)
if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
return 0;
+ if (reload) {
+ AST_RWLIST_WRLOCK(&mohclasses);
+ AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
+ class->delete = 1;
+ }
+ AST_RWLIST_UNLOCK(&mohclasses);
+ }
+
cat = ast_category_browse(cfg, NULL);
for (; cat; cat = ast_category_browse(cfg, cat)) {
/* These names were deprecated in 1.4 and should not be used until after the next major release. */
@@ -1082,16 +1104,12 @@ static int load_moh_classes(int reload)
return numclasses;
}
-static void ast_moh_destroy(void)
+static int ast_moh_destroy_one(struct mohclass *moh)
{
- struct mohclass *moh;
char buff[8192];
int bytes, tbytes = 0, stime = 0, pid = 0;
- ast_verb(2, "Destroying musiconhold processes\n");
-
- AST_RWLIST_WRLOCK(&mohclasses);
- while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) {
+ if (moh) {
if (moh->pid > 1) {
ast_debug(1, "killing %d!\n", moh->pid);
stime = time(NULL) + 2;
@@ -1112,33 +1130,27 @@ static void ast_moh_destroy(void)
}
ast_moh_free_class(&moh);
}
- AST_RWLIST_UNLOCK(&mohclasses);
+
+ return 0;
}
-static void moh_on_off(int on)
+static void ast_moh_destroy(void)
{
- struct ast_channel *chan = NULL;
-
- while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
- if (ast_test_flag(chan, AST_FLAG_MOH)) {
- if (on)
- local_ast_moh_start(chan, NULL, NULL);
- else
- ast_deactivate_generator(chan);
- }
- ast_channel_unlock(chan);
+ struct mohclass *moh;
+
+ ast_verb(2, "Destroying musiconhold processes\n");
+
+ AST_RWLIST_WRLOCK(&mohclasses);
+ while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) {
+ ast_moh_destroy_one(moh);
}
+ AST_RWLIST_UNLOCK(&mohclasses);
}
static int moh_cli(int fd, int argc, char *argv[])
{
- int x;
+ reload();
- moh_on_off(0);
- ast_moh_destroy();
- x = load_moh_classes(1);
- moh_on_off(1);
- ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
return 0;
}
@@ -1170,6 +1182,7 @@ static int moh_classes_show(int fd, int argc, char *argv[])
ast_cli(fd, "Class: %s\n", class->name);
ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
+ ast_cli(fd, "\tUse Count: %d\n", class->inuse);
if (class->digit)
ast_cli(fd, "\tDigit: %c\n", class->digit);
if (ast_test_flag(class, MOH_CUSTOM))
@@ -1204,10 +1217,15 @@ static int init_classes(int reload)
return 0; /* Return if nothing is found */
AST_RWLIST_WRLOCK(&mohclasses);
- AST_RWLIST_TRAVERSE(&mohclasses, moh, list) {
- if (moh->total_files)
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
+ if (reload && moh->delete) {
+ AST_RWLIST_REMOVE_CURRENT(&mohclasses, list);
+ if (!moh->inuse)
+ ast_moh_destroy_one(moh);
+ } else if (moh->total_files)
moh_scan_files(moh);
}
+ AST_RWLIST_TRAVERSE_SAFE_END
AST_RWLIST_UNLOCK(&mohclasses);
return 1;