merge Russell's 'hold_handling' branch, finally implementing music-on-hold handling...
authorKevin P. Fleming <kpfleming@digium.com>
Wed, 19 Jul 2006 20:44:39 +0000 (20:44 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Wed, 19 Jul 2006 20:44:39 +0000 (20:44 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@37988 65c4cc65-6c06-0410-ace0-fbb531ad65f3

30 files changed:
apps/app_dial.c
apps/app_followme.c
apps/app_meetme.c
apps/app_queue.c
channel.c
channels/chan_agent.c
channels/chan_alsa.c
channels/chan_h323.c
channels/chan_iax2.c
channels/chan_jingle.c
channels/chan_mgcp.c
channels/chan_misdn.c
channels/chan_oss.c
channels/chan_phone.c
channels/chan_sip.c
channels/chan_skinny.c
channels/chan_vpb.cc
channels/chan_zap.c
configs/alsa.conf.sample
configs/features.conf.sample
configs/iax.conf.sample
configs/queues.conf.sample
configs/sip.conf.sample
configs/skinny.conf.sample
configs/zapata.conf.sample
include/asterisk/musiconhold.h
pbx.c
res/res_agi.c
res/res_features.c
res/res_musiconhold.c

index f283488..24fe9b7 100644 (file)
@@ -1214,8 +1214,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                /* Our status will at least be NOANSWER */
                strcpy(status, "NOANSWER");
                if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
-                       moh=1;
-                       ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
+                       moh = 1;
+                       ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
                } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
                        ast_indicate(chan, AST_CONTROL_RINGING);
                        sentringing++;
@@ -1273,7 +1273,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 
                        if (ast_test_flag(&opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
                                ast_indicate(chan, -1);
-                               ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
+                               ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
                        } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
                                ast_indicate(chan, AST_CONTROL_RINGING);
                                sentringing++;
@@ -1701,7 +1701,7 @@ static int retrydial_exec(struct ast_channel *chan, void *data)
                                        res = ast_waitstream(chan, AST_DIGIT_ANY);
                                if (!res && sleep) {
                                        if (!ast_test_flag(chan, AST_FLAG_MOH))
-                                               ast_moh_start(chan, NULL);
+                                               ast_moh_start(chan, NULL, NULL);
                                        res = ast_waitfordigit(chan, sleep);
                                }
                        } else {
@@ -1709,7 +1709,7 @@ static int retrydial_exec(struct ast_channel *chan, void *data)
                                        res = ast_waitstream(chan, "");
                                if (sleep) {
                                        if (!ast_test_flag(chan, AST_FLAG_MOH))
-                                               ast_moh_start(chan, NULL);
+                                               ast_moh_start(chan, NULL, NULL);
                                        if (!res) 
                                                res = ast_waitfordigit(chan, sleep);
                                }
index 85dda00..42986c9 100644 (file)
@@ -1010,10 +1010,7 @@ static int app_exec(struct ast_channel *chan, void *data)
                                        goto outrun;
                                if (ast_waitstream(chan, "") < 0)
                                        goto outrun;
-                               if (!strcmp(targs.mohclass, ""))
-                                       ast_moh_start(chan, NULL);
-                               else
-                                       ast_moh_start(chan, targs.mohclass);
+                               ast_moh_start(chan, S_OR(targs.mohclass, NULL), NULL);
 
 
                                targs.status = 0;
index 698995d..6b5355a 100644 (file)
@@ -1407,7 +1407,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
                                                }
                                        }
                                        if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
-                                               ast_moh_start(chan, NULL);
+                                               ast_moh_start(chan, NULL, NULL);
                                                musiconhold = 1;
                                        } else {
                                                ztc.confmode = ZT_CONF_CONF;
@@ -1445,7 +1445,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
                        if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
                                if (conf->users == 1) {
                                        if (musiconhold == 0) {
-                                               ast_moh_start(chan, NULL);
+                                               ast_moh_start(chan, NULL, NULL);
                                                musiconhold = 1;
                                        } 
                                } else {
@@ -1749,7 +1749,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
                                                }
                                        }
                                        if (musiconhold)
-                                               ast_moh_start(chan, NULL);
+                                               ast_moh_start(chan, NULL, NULL);
 
                                        if (ioctl(fd, ZT_SETCONF, &ztc)) {
                                                ast_log(LOG_WARNING, "Error setting conference\n");
index b9b578d..8458325 100644 (file)
@@ -761,7 +761,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
        char *c, *lastc;
        char buff[80];
 
-       if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
+       if (!strcasecmp(param, "musicclass") || 
+               !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
                ast_copy_string(q->moh, val, sizeof(q->moh));
        } else if (!strcasecmp(param, "announce")) {
                ast_copy_string(q->announce, val, sizeof(q->announce));
@@ -1343,7 +1344,7 @@ playout:
 
        /* Don't restart music on hold if we're about to exit the caller from the queue */
        if (!res)
-               ast_moh_start(qe->chan, qe->moh);
+               ast_moh_start(qe->chan, qe->moh, NULL);
 
        return res;
 }
@@ -1782,7 +1783,7 @@ static int say_periodic_announcement(struct queue_ent *qe)
 
        /* Resume Music on Hold if the caller is going to stay in the queue */
        if (!res)
-               ast_moh_start(qe->chan, qe->moh);
+               ast_moh_start(qe->chan, qe->moh, NULL);
 
        /* update last_periodic_announce_time */
        qe->last_periodic_announce_time = now;
@@ -3311,7 +3312,7 @@ check_turns:
                if (ringing) {
                        ast_indicate(chan, AST_CONTROL_RINGING);
                } else {
-                       ast_moh_start(chan, qe.moh);
+                       ast_moh_start(chan, qe.moh, NULL);
                }
                for (;;) {
                        /* This is the wait loop for callers 2 through maxlen */
index c14c47c..a3fe86f 100644 (file)
--- a/channel.c
+++ b/channel.c
@@ -3881,11 +3881,11 @@ ast_group_t ast_get_group(char *s)
        return group;
 }
 
-static int (*ast_moh_start_ptr)(struct ast_channel *, const char *) = NULL;
+static int (*ast_moh_start_ptr)(struct ast_channel *, const char *, const char *) = NULL;
 static void (*ast_moh_stop_ptr)(struct ast_channel *) = NULL;
 static void (*ast_moh_cleanup_ptr)(struct ast_channel *) = NULL;
 
-void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, const char *),
+void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, const char *, const char *),
                                 void (*stop_ptr)(struct ast_channel *),
                                 void (*cleanup_ptr)(struct ast_channel *))
 {
@@ -3902,14 +3902,16 @@ void ast_uninstall_music_functions(void)
 }
 
 /*! \brief Turn on music on hold on a given channel */
-int ast_moh_start(struct ast_channel *chan, const char *mclass)
+int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
 {
        if (ast_moh_start_ptr)
-               return ast_moh_start_ptr(chan, mclass);
+               return ast_moh_start_ptr(chan, mclass, interpclass);
+
+       if (option_verbose > 2) {
+               ast_verbose(VERBOSE_PREFIX_3 "Music class %s requested but no musiconhold loaded.\n", 
+                       mclass ? mclass : (interpclass ? interpclass : "default"));
+       }
 
-       if (option_verbose > 2)
-               ast_verbose(VERBOSE_PREFIX_3 "Music class %s requested but no musiconhold loaded.\n", mclass ? mclass : "default");
-       
        return 0;
 }
 
index 1c440f3..1c3f8d8 100644 (file)
@@ -595,7 +595,7 @@ static int agent_indicate(struct ast_channel *ast, int condition, const void *da
        int res = -1;
        ast_mutex_lock(&p->lock);
        if (p->chan)
-               res = ast_indicate(p->chan, condition);
+               res = ast_indicate_data(p->chan, condition, data, datalen);
        else
                res = 0;
        ast_mutex_unlock(&p->lock);
@@ -773,7 +773,9 @@ static int agent_hangup(struct ast_channel *ast)
                        ast_channel_unlock(p->chan);
                } else if (p->loginstart) {
                        ast_channel_lock(p->chan);
-                       ast_moh_start(p->chan, p->moh);
+                       ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
+                               S_OR(p->moh, NULL),
+                               !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
                        ast_channel_unlock(p->chan);
                }
        }
@@ -965,7 +967,7 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state)
                        ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
                        CRASH;
                }
-               ast_moh_stop(p->chan);
+               ast_indicate(p->chan, AST_CONTROL_UNHOLD);
        }
        return tmp;
 }
@@ -1964,12 +1966,9 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
                                                        res = ast_safe_sleep(chan, 500);
                                                ast_mutex_unlock(&p->lock);
                                        } else if (!res) {
-#ifdef HONOR_MUSIC_CLASS
-                                               /* check if the moh class was changed with setmusiconhold */
-                                               if (*(chan->musicclass))
-                                                       ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
-#endif                                                         
-                                               ast_moh_start(chan, p->moh);
+                                               ast_indicate_data(chan, AST_CONTROL_HOLD, 
+                                                       S_OR(p->moh, NULL), 
+                                                       !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
                                                if (p->loginstart == 0)
                                                        time(&p->loginstart);
                                                manager_event(EVENT_FLAG_AGENT, "Agentlogin",
index 5c921b9..aeadc34 100644 (file)
@@ -61,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/endian.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/abstract_jb.h"
+#include "asterisk/musiconhold.h"
 
 #include "busy.h"
 #include "ringtone.h"
@@ -127,6 +128,7 @@ static const char config[] = "alsa.conf";
 static char context[AST_MAX_CONTEXT] = "default";
 static char language[MAX_LANGUAGE] = "";
 static char exten[AST_MAX_EXTENSION] = "s";
+static char mohinterpret[MAX_MUSICCLASS];
 
 static int hookstate=0;
 
@@ -764,7 +766,9 @@ static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen)
 {
        int res = 0;
+
        ast_mutex_lock(&alsalock);
+       
        switch(cond) {
        case AST_CONTROL_BUSY:
                res = 1;
@@ -773,7 +777,6 @@ static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, s
                res = 2;
                break;
        case AST_CONTROL_RINGING:
-               res = 0;
                break;
        case -1:
                res = -1;
@@ -781,14 +784,24 @@ static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, s
        case AST_CONTROL_VIDUPDATE:
                res = -1;
                break;
+       case AST_CONTROL_HOLD:
+               ast_verbose( " << Console Has Been Placed on Hold >> \n");
+               ast_moh_start(chan, data, mohinterpret);
+               break;
+       case AST_CONTROL_UNHOLD:
+               ast_verbose( " << Console Has Been Retrieved from Hold >> \n");
+               ast_moh_stop(chan);
+               break;
        default:
                ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, chan->name);
                res = -1;
        }
-       if (res > -1) {
+       
+       if (res > -1)
                write(sndcmd[1], &res, sizeof(res));
-       }
+
        ast_mutex_unlock(&alsalock);
+
        return res;     
 }
 
@@ -1068,14 +1081,15 @@ static int load_module(void *mod)
        /* Copy the default jb config over global_jbconf */
        memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
+       strcpy(mohinterpret, "default");
+
        if ((cfg = ast_config_load(config))) {
                v = ast_variable_browse(cfg, "general");
-               while(v) {
+               for (; v; v = v->next) {
                        /* handle jb conf */
-                       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
-                               v = v->next;
+                       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
                                continue;
-                       }
+                       
                        if (!strcasecmp(v->name, "autoanswer"))
                                autoanswer = ast_true(v->value);
                        else if (!strcasecmp(v->name, "silencesuppression"))
@@ -1083,16 +1097,17 @@ static int load_module(void *mod)
                        else if (!strcasecmp(v->name, "silencethreshold"))
                                silencethreshold = atoi(v->value);
                        else if (!strcasecmp(v->name, "context"))
-                               strncpy(context, v->value, sizeof(context)-1);
+                               ast_copy_string(context, v->value, sizeof(context));
                        else if (!strcasecmp(v->name, "language"))
-                               strncpy(language, v->value, sizeof(language)-1);
+                               ast_copy_string(language, v->value, sizeof(language));
                        else if (!strcasecmp(v->name, "extension"))
-                               strncpy(exten, v->value, sizeof(exten)-1);
+                               ast_copy_string(exten, v->value, sizeof(exten));
                        else if (!strcasecmp(v->name, "input_device"))
-                               strncpy(indevname, v->value, sizeof(indevname)-1);
+                               ast_copy_string(indevname, v->value, sizeof(indevname));
                        else if (!strcasecmp(v->name, "output_device"))
-                               strncpy(outdevname, v->value, sizeof(outdevname)-1);
-                       v=v->next;
+                               ast_copy_string(outdevname, v->value, sizeof(outdevname));
+                       else if (!strcasecmp(v->name, "mohinterpret"))
+                               ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
                }
                ast_config_destroy(cfg);
        }
index a638b19..b5e3b18 100644 (file)
@@ -702,6 +702,16 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data
                if (token)
                        free(token);
                return -1;
+       case AST_CONTROL_HOLD:
+               ast_moh_start(c, data, NULL);
+               if (token)
+                       free(token);
+               return 0;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(c);
+               if (token)
+                       free(token);
+               return 0;
        case AST_CONTROL_PROCEEDING:
        case -1:
                if (token)
index f085470..046cd7e 100644 (file)
@@ -217,6 +217,8 @@ static int test_jitpct = 0;
 #endif /* IAXTESTS */
 
 static char accountcode[AST_MAX_ACCOUNT_CODE];
+static char mohinterpret[MAX_MUSICCLASS];
+static char mohsuggest[MAX_MUSICCLASS];
 static int amaflags = 0;
 static int adsi = 0;
 static int delayreject = 0;
@@ -283,6 +285,8 @@ struct iax2_user {
        int authmethods;
        int encmethods;
        char accountcode[AST_MAX_ACCOUNT_CODE];
+       char mohinterpret[MAX_MUSICCLASS];
+       char mohsuggest[MAX_MUSICCLASS];
        char inkeys[80];                                /*!< Key(s) this user can use to authenticate to us */
        char language[MAX_LANGUAGE];
        int amaflags;
@@ -310,6 +314,8 @@ struct iax2_peer {
        char regexten[AST_MAX_EXTENSION];               /*!< Extension to register (if regcontext is used) */
        char peercontext[AST_MAX_EXTENSION];            /*!< Context to pass to peer */
        char mailbox[AST_MAX_EXTENSION];                /*!< Mailbox */
+       char mohinterpret[MAX_MUSICCLASS];
+       char mohsuggest[MAX_MUSICCLASS];
        struct ast_codec_pref prefs;
        struct ast_dnsmgr_entry *dnsmgr;                /*!< DNS refresh manager */
        struct sockaddr_in addr;
@@ -590,6 +596,8 @@ struct chan_iax2_pvt {
        int calling_pres;
        char dproot[AST_MAX_EXTENSION];
        char accountcode[AST_MAX_ACCOUNT_CODE];
+       char mohinterpret[MAX_MUSICCLASS];
+       char mohsuggest[MAX_MUSICCLASS];
        int amaflags;
        struct iax2_dpcache *dpentries;
        struct ast_variable *vars;
@@ -1226,6 +1234,8 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                        iaxs[x]->amaflags = amaflags;
                        ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);    
                        ast_copy_string(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode));
+                       ast_copy_string(iaxs[x]->mohinterpret, mohinterpret, sizeof(iaxs[x]->mohinterpret));
+                       ast_copy_string(iaxs[x]->mohsuggest, mohsuggest, sizeof(iaxs[x]->mohsuggest));
                } else {
                        ast_log(LOG_WARNING, "Out of resources\n");
                        ast_mutex_unlock(&iaxsl[x]);
@@ -2577,6 +2587,8 @@ struct create_addr_info {
        char prefs[32];
        char context[AST_MAX_CONTEXT];
        char peercontext[AST_MAX_CONTEXT];
+       char mohinterpret[MAX_MUSICCLASS];
+       char mohsuggest[MAX_MUSICCLASS];
 };
 
 static int create_addr(const char *peername, struct sockaddr_in *sin, struct create_addr_info *cai)
@@ -2634,6 +2646,8 @@ static int create_addr(const char *peername, struct sockaddr_in *sin, struct cre
        ast_copy_string(cai->username, peer->username, sizeof(cai->username));
        ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone));
        ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey));
+       ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret));
+       ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest));
        if (ast_strlen_zero(peer->dbsecret)) {
                ast_copy_string(cai->secret, peer->secret, sizeof(cai->secret));
        } else {
@@ -2881,6 +2895,9 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
        iaxs[callno]->encmethods = cai.encmethods;
 
        iaxs[callno]->adsi = cai.adsi;
+       
+       ast_copy_string(iaxs[callno]->mohinterpret, cai.mohinterpret, sizeof(iaxs[callno]->mohinterpret));
+       ast_copy_string(iaxs[callno]->mohsuggest, cai.mohsuggest, sizeof(iaxs[callno]->mohsuggest));
 
        if (pds.key)
                ast_copy_string(iaxs[callno]->outkey, pds.key, sizeof(iaxs[callno]->outkey));
@@ -3168,9 +3185,23 @@ static int iax2_answer(struct ast_channel *c)
 static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen)
 {
        unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
+
        if (option_debug && iaxdebug)
                ast_log(LOG_DEBUG, "Indicating condition %d\n", condition);
-       return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
+
+       if (!strcasecmp(iaxs[callno]->mohinterpret, "passthrough"))
+               return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
+
+       switch (condition) {
+       case AST_CONTROL_HOLD:
+               ast_moh_start(c, data, iaxs[callno]->mohinterpret);
+               return 0;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(c);
+               return 0;
+       default:
+               return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
+       }
 }
        
 static int iax2_transfer(struct ast_channel *c, const char *dest)
@@ -4703,6 +4734,10 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                }
                if (!ast_strlen_zero(user->accountcode))
                        ast_copy_string(iaxs[callno]->accountcode, user->accountcode, sizeof(iaxs[callno]->accountcode));
+               if (!ast_strlen_zero(user->mohinterpret))
+                       ast_copy_string(iaxs[callno]->mohinterpret, user->mohinterpret, sizeof(iaxs[callno]->mohinterpret));
+               if (!ast_strlen_zero(user->mohsuggest))
+                       ast_copy_string(iaxs[callno]->mohsuggest, user->mohsuggest, sizeof(iaxs[callno]->mohsuggest));
                if (user->amaflags)
                        iaxs[callno]->amaflags = user->amaflags;
                if (!ast_strlen_zero(user->language))
@@ -6668,9 +6703,12 @@ retryowner:
 
                                        ast_set_flag(iaxs[fr->callno], IAX_QUELCH);
                                        if (ies.musiconhold) {
-                                               if (iaxs[fr->callno]->owner &&
-                                                       ast_bridged_channel(iaxs[fr->callno]->owner))
-                                                               ast_moh_start(ast_bridged_channel(iaxs[fr->callno]->owner), NULL);
+                                               if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
+                                                       const char *mohsuggest = iaxs[fr->callno]->mohsuggest;
+                                                       ast_queue_control_data(iaxs[fr->callno]->owner, AST_CONTROL_HOLD, 
+                                                               S_OR(mohsuggest, NULL),
+                                                               !ast_strlen_zero(mohsuggest) ? strlen(mohsuggest) + 1 : 0);
+                                               }
                                        }
                                }
                                break;
@@ -6686,9 +6724,8 @@ retryowner:
                                        }
 
                                        ast_clear_flag(iaxs[fr->callno], IAX_QUELCH);
-                                       if (iaxs[fr->callno]->owner &&
-                                               ast_bridged_channel(iaxs[fr->callno]->owner))
-                                                       ast_moh_stop(ast_bridged_channel(iaxs[fr->callno]->owner));
+                                       if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner))
+                                               ast_queue_control(iaxs[fr->callno]->owner, AST_CONTROL_UNHOLD);
                                }
                                break;
                        case IAX_COMMAND_TXACC:
@@ -8244,6 +8281,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
                                ast_copy_string(peer->secret, v->value, sizeof(peer->secret));
                        } else if (!strcasecmp(v->name, "mailbox")) {
                                ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
+                       } else if (!strcasecmp(v->name, "mohinterpret")) {
+                               ast_copy_string(peer->mohinterpret, v->value, sizeof(peer->mohinterpret));
+                       } else if (!strcasecmp(v->name, "mohsuggest")) {
+                               ast_copy_string(peer->mohsuggest, v->value, sizeof(peer->mohsuggest));
                        } else if (!strcasecmp(v->name, "dbsecret")) {
                                ast_copy_string(peer->dbsecret, v->value, sizeof(peer->dbsecret));
                        } else if (!strcasecmp(v->name, "trunk")) {
@@ -8502,6 +8543,10 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
                                ast_set_flag(user, IAX_HASCALLERID);    
                        } else if (!strcasecmp(v->name, "accountcode")) {
                                ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
+                       } else if (!strcasecmp(v->name, "mohinterpret")) {
+                               ast_copy_string(user->mohinterpret, v->value, sizeof(user->mohinterpret));
+                       } else if (!strcasecmp(v->name, "mohsuggest")) {
+                               ast_copy_string(user->mohsuggest, v->value, sizeof(user->mohsuggest));
                        } else if (!strcasecmp(v->name, "language")) {
                                ast_copy_string(user->language, v->value, sizeof(user->language));
                        } else if (!strcasecmp(v->name, "amaflags")) {
@@ -8878,6 +8923,10 @@ static int set_config(char *config_file, int reload)
                                ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/ip-tos.txt for more information.'\n", v->lineno);
                } else if (!strcasecmp(v->name, "accountcode")) {
                        ast_copy_string(accountcode, v->value, sizeof(accountcode));
+               } else if (!strcasecmp(v->name, "mohinterpret")) {
+                       ast_copy_string(mohinterpret, v->value, sizeof(user->mohinterpret));
+               } else if (!strcasecmp(v->name, "mohsuggest")) {
+                       ast_copy_string(mohsuggest, v->value, sizeof(user->mohsuggest));
                } else if (!strcasecmp(v->name, "amaflags")) {
                        format = ast_cdr_amaflags2int(v->value);
                        if (format < 0) {
@@ -8956,8 +9005,10 @@ static int reload_config(void)
        struct iax2_registry *reg;
        struct iax2_peer *peer = NULL;
 
-       ast_copy_string(accountcode, "", sizeof(accountcode));
-       ast_copy_string(language, "", sizeof(language));
+       strcpy(accountcode, "");
+       strcpy(language, "");
+       strcpy(mohinterpret, "default");
+       strcpy(mohsuggest, "");
        amaflags = 0;
        delayreject = 0;
        ast_clear_flag((&globalflags), IAX_NOTRANSFER); 
index cefecc7..6ea1462 100644 (file)
@@ -1116,9 +1116,21 @@ static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan
 
 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
 {
-       ast_log(LOG_NOTICE, "XXX Implement jingle indicate XXX\n");
+       int res = 0;
 
-       return -1;
+       switch (condition) {
+       case AST_CONTROL_HOLD:
+               ast_moh_start(ast, data, NULL);
+               break;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(ast);
+               break;
+       default:
+               ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
+               res = -1;
+       }
+
+       return res;
 }
 
 static int jingle_digit(struct ast_channel *ast, char digit)
index 5ad6cb7..0d1a857 100644 (file)
  * \ingroup channel_drivers
  */
 
-/* FO: Changes
- * -- add distinctive ring signalling (part of RFC 3660)
- */
-
-/* JS: Changes
-   -- add support for the wildcard endpoint
-   -- seteable wildcard with wcardep on mgcp.conf
-   -- added package indicator on RQNT, i.e "dl" --> "L/dl"
-   -- removed MDCX just before DLCX, do we need this ?
-*/
-
-/* JS: TODO
-   -- reload for wildcard endpoint probably buggy
-   -- when hf is notified we're sending CRCX after MDCX, without waiting for
-      OK on the MDCX which fails on Cisco IAD 24XX
-   -- honour codec order, by now the lowest codec number in "allow" is the prefered
-*/
-
-/* SC: Changes
-   -- packet retransmit mechanism (simplistic)
-   -- per endpoint/subchannel mgcp command sequencing. 
-   -- better transaction handling
-   -- fixed some mem leaks
-   -- run-time configuration reload 
-   -- distinguish CA and GW default MGCP ports
-   -- prevent clipping of DTMF tones in an established call
-   -- fixed a few crash scenarios in 3-way
-   -- fix for a few cases where asterisk and MGW end-up in conflicting ep states 
-   -- enclose numeric IP in [] for outgoing requests
-*/
-
-/* SC: TODO
-   -- piggyback support
-   -- responseAck support
-   -- enhance retransmit mechanism (RTO calc. etc.)
-   -- embedded command support
-*/
-
-/* FS: Changes
-   -- fixed reload_config() / do_monitor to stay responsive during reloads
-*/
-
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -155,13 +113,13 @@ static const char config[] = "mgcp.conf";
 #define MGCP_DTMF_INBAND       (1 << 1)
 #define MGCP_DTMF_HYBRID       (1 << 2)
 
-#define DEFAULT_MGCP_GW_PORT   2427 /* From RFC 2705 */
-#define DEFAULT_MGCP_CA_PORT   2727 /* From RFC 2705 */
-#define MGCP_MAX_PACKET                1500 /* Also from RFC 2543, should sub headers tho */
-#define DEFAULT_RETRANS                1000 /* How frequently to retransmit */
-#define MAX_RETRANS            5    /* Try only 5 times for retransmissions */
+#define DEFAULT_MGCP_GW_PORT   2427 /*!< From RFC 2705 */
+#define DEFAULT_MGCP_CA_PORT   2727 /*!< From RFC 2705 */
+#define MGCP_MAX_PACKET                1500 /*!< Also from RFC 2543, should sub headers tho */
+#define DEFAULT_RETRANS                1000 /*!< How frequently to retransmit */
+#define MAX_RETRANS            5    /*!< Try only 5 times for retransmissions */
 
-/* MGCP rtp stream modes */
+/*! MGCP rtp stream modes { */
 #define MGCP_CX_SENDONLY       0
 #define MGCP_CX_RECVONLY       1
 #define MGCP_CX_SENDRECV       2
@@ -169,6 +127,7 @@ static const char config[] = "mgcp.conf";
 #define MGCP_CX_CONFERENCE     3
 #define MGCP_CX_MUTE           4
 #define MGCP_CX_INACTIVE       4
+/*! } */
 
 static char *mgcp_cxmodes[] = {
        "sendonly",
@@ -178,16 +137,17 @@ static char *mgcp_cxmodes[] = {
        "inactive"
 };
 
-/* SC: MGCP commands */
-#define MGCP_CMD_EPCF 0
-#define MGCP_CMD_CRCX 1
-#define MGCP_CMD_MDCX 2
-#define MGCP_CMD_DLCX 3
-#define MGCP_CMD_RQNT 4
-#define MGCP_CMD_NTFY 5
-#define MGCP_CMD_AUEP 6
-#define MGCP_CMD_AUCX 7
-#define MGCP_CMD_RSIP 8
+enum {
+       MGCP_CMD_EPCF,
+       MGCP_CMD_CRCX,
+       MGCP_CMD_MDCX,
+       MGCP_CMD_DLCX,
+       MGCP_CMD_RQNT,
+       MGCP_CMD_NTFY,
+       MGCP_CMD_AUEP,
+       MGCP_CMD_AUCX,
+       MGCP_CMD_RSIP
+};
 
 static char context[AST_MAX_EXTENSION] = "default";
 
@@ -199,39 +159,22 @@ static char cid_name[AST_MAX_EXTENSION] = "";
 static int dtmfmode = 0;
 static int nat = 0;
 
-/* Not used. Dosn't hurt for us to always send cid  */
-/* to the mgcp box. */
-/*static int use_callerid = 1;*/
-/*static int cur_signalling = -1;*/
-
-/*static unsigned int cur_group = 0;*/
 static ast_group_t cur_callergroup = 0;
 static ast_group_t cur_pickupgroup = 0;
 
-/* XXX Is this needed? */
-/*     Doesn't look like the dsp stuff for */
-/*     dtmfmode is actually hooked up.   */
-/*static int relaxdtmf = 0;*/
-
 static int tos = 0;
 
 static int immediate = 0;
 
 static int callwaiting = 0;
 
-/* Not used. Dosn't hurt for us to always send cid  */
-/* to the mgcp box. */
-/*static int callwaitingcallerid = 0;*/
-
-/*static int hidecallerid = 0;*/
-
 static int callreturn = 0;
 
 static int slowsequence = 0;
 
 static int threewaycalling = 0;
 
-/* This is for flashhook transfers */
+/*! This is for flashhook transfers */
 static int transfer = 0;
 
 static int cancallforward = 0;
@@ -240,10 +183,6 @@ static int singlepath = 0;
 
 static int canreinvite = CANREINVITE;
 
-/*static int busycount = 3;*/
-
-/*static int callprogress = 0;*/
-
 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
 
 static char mailbox[AST_MAX_EXTENSION];
@@ -252,26 +191,25 @@ static int amaflags = 0;
 
 static int adsi = 0;
 
-/* SC: transaction id should always be positive */
 static unsigned int oseq;
 
-/* Wait up to 16 seconds for first digit (FXO logic) */
+/*! Wait up to 16 seconds for first digit (FXO logic) */
 static int firstdigittimeout = 16000;
 
-/* How long to wait for following digits (FXO logic) */
+/*! How long to wait for following digits (FXO logic) */
 static int gendigittimeout = 8000;
 
-/* How long to wait for an extra digit, if there is an ambiguous match */
+/*! How long to wait for an extra digit, if there is an ambiguous match */
 static int matchdigittimeout = 3000;
 
-/* Protect the monitoring thread, so only one process can kill or start it, and not
-   when it's doing something critical. */
+/*! Protect the monitoring thread, so only one process can kill or start it, and not
+    when it's doing something critical. */
 AST_MUTEX_DEFINE_STATIC(netlock);
 
 AST_MUTEX_DEFINE_STATIC(monlock);
 
-/* This is the thread for the monitor which checks for input on the channels
-   which are not currently in use. */
+/*! This is the thread for the monitor which checks for input on the channels
+    which are not currently in use. */
 static pthread_t monitor_thread = AST_PTHREADT_NULL;
 
 static int restart_monitor(void);
@@ -287,8 +225,8 @@ static int mgcpdebug = 0;
 
 static struct sched_context *sched;
 static struct io_context *io;
-/* The private structures of the  mgcp channels are linked for
-   selecting outgoing channels */
+/*! The private structures of the  mgcp channels are linked for
+  ! selecting outgoing channels */
    
 #define MGCP_MAX_HEADERS       64
 #define MGCP_MAX_LINES         64
@@ -304,21 +242,11 @@ struct mgcp_request {
        int lines;                      /*!< SDP Content */
        char *line[MGCP_MAX_LINES];
        char data[MGCP_MAX_PACKET];
-       int cmd;                        /*!< SC: int version of verb = command */
-       unsigned int trid;              /*!< SC: int version of identifier = transaction id */
-       struct mgcp_request *next;      /*!< SC: next in the queue */
+       int cmd;                        /*!< int version of verb = command */
+       unsigned int trid;              /*!< int version of identifier = transaction id */
+       struct mgcp_request *next;      /*!< next in the queue */
 };
 
-/* SC: obsolete
-static struct mgcp_pkt {
-       int retrans;
-       struct mgcp_endpoint *owner;
-       int packetlen;
-       char data[MGCP_MAX_PACKET];
-       struct mgcp_pkt *next;
-} *packets = NULL;     
-*/
-
 /*! \brief mgcp_message: MGCP message for queuing up */
 struct mgcp_message {
        struct mgcp_endpoint *owner_ep;
@@ -331,7 +259,7 @@ struct mgcp_message {
        char buf[0];
 };
 
-#define RESPONSE_TIMEOUT 30    /* in seconds */
+#define RESPONSE_TIMEOUT 30    /*!< in seconds */
 
 struct mgcp_response {
        time_t whensent;
@@ -347,7 +275,7 @@ struct mgcp_response {
 #define SUB_ALT  1
 
 struct mgcp_subchannel {
-       /* SC: subchannel magic string. 
+       /*! subchannel magic string. 
           Needed to prove that any subchannel pointer passed by asterisk 
           really points to a valid subchannel memory area.
           Ugly.. But serves the purpose for the time being.
@@ -360,18 +288,18 @@ struct mgcp_subchannel {
        struct mgcp_endpoint *parent;
        struct ast_rtp *rtp;
        struct sockaddr_in tmpdest;
-       char txident[80]; /* FIXME SC: txident is replaced by rqnt_ident in endpoint. 
+       char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint. 
                        This should be obsoleted */
        char cxident[80];
        char callid[80];
        int cxmode;
-       struct mgcp_request *cx_queue; /*!< SC: pending CX commands */
-       ast_mutex_t cx_queue_lock;     /*!< SC: CX queue lock */
+       struct mgcp_request *cx_queue; /*!< pending CX commands */
+       ast_mutex_t cx_queue_lock;     /*!< CX queue lock */
        int nat;
-       int iseq; /* Not used? RTP? */
+       int iseq;                      /*!< Not used? RTP? */
        int outgoing;
        int alreadygone;
-       struct mgcp_subchannel *next; /* for out circular linked list */
+       struct mgcp_subchannel *next;  /*!< for out circular linked list */
 };
 
 #define MGCP_ONHOOK  1
@@ -423,13 +351,13 @@ struct mgcp_endpoint {
        int immediate;
        int hookstate;
        int adsi;
-       char rqnt_ident[80];             /*!< SC: request identifier */
-       struct mgcp_request *rqnt_queue; /*!< SC: pending RQNT commands */
+       char rqnt_ident[80];             /*!< request identifier */
+       struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */
        ast_mutex_t rqnt_queue_lock;
-       struct mgcp_request *cmd_queue;  /*!< SC: pending commands other than RQNT */
+       struct mgcp_request *cmd_queue;  /*!< pending commands other than RQNT */
        ast_mutex_t cmd_queue_lock;
-       int delme;                       /*!< SC: needed for reload */
-       int needaudit;                   /*!< SC: needed for reload */
+       int delme;                       /*!< needed for reload */
+       int needaudit;                   /*!< needed for reload */
        struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */
        /* owner is tracked on the subchannels, and the *sub indicates whos in charge */
        /* struct ast_channel *owner; */
@@ -443,7 +371,7 @@ struct mgcp_endpoint {
 static struct mgcp_gateway {
        /* A gateway containing one or more endpoints */
        char name[80];
-       int isnamedottedip; /*!< SC: is the name FQDN or dotted ip */
+       int isnamedottedip; /*!< is the name FQDN or dotted ip */
        struct sockaddr_in addr;
        struct sockaddr_in defaddr;
        struct in_addr ourip;
@@ -451,17 +379,17 @@ static struct mgcp_gateway {
        int expire;             /*!< XXX Should we ever expire dynamic registrations? XXX */
        struct mgcp_endpoint *endpoints;
        struct ast_ha *ha;
-/* SC: obsolete
+/* obsolete
        time_t lastouttime;
        int lastout;
        int messagepending;
 */
-/* JS: Wildcard endpoint name */
+/* Wildcard endpoint name */
        char wcardep[30];
-       struct mgcp_message *msgs; /*!< SC: gw msg queue */
-       ast_mutex_t msgs_lock;     /*!< SC: queue lock */  
-       int retransid;             /*!< SC: retrans timer id */
-       int delme;                 /*!< SC: needed for reload */
+       struct mgcp_message *msgs; /*!< gw msg queue */
+       ast_mutex_t msgs_lock;     /*!< queue lock */  
+       int retransid;             /*!< retrans timer id */
+       int delme;                 /*!< needed for reload */
        struct mgcp_response *responses;
        struct mgcp_gateway *next;
 } *gateways;
@@ -552,7 +480,7 @@ static int unalloc_sub(struct mgcp_subchannel *sub)
        return 0;
 }
 
-/* SC: modified for new transport mechanism */
+/* modified for new transport mechanism */
 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
 {
        int res;
@@ -594,7 +522,7 @@ static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
        return res;
 }
 
-/* SC: modified for new transport framework */
+/* modified for new transport framework */
 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
 {
        struct mgcp_message *cur, *q = NULL, *w, *prev;
@@ -736,7 +664,7 @@ static int retrans_pkt(void *data)
        return res;
 }
 
-/* SC: modified for the new transaction mechanism */
+/* modified for the new transaction mechanism */
 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
                             char *data, int len, unsigned int seqno)
 {
@@ -802,7 +730,7 @@ static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
        return 0;
 }
 
-/* SC: modified for new transport */
+/* modified for new transport */
 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
                         struct mgcp_request *req, unsigned int seqno)
 {
@@ -875,7 +803,7 @@ static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
                }
        }
 
-       /* XXX SC: find tail. We could also keep tail in the data struct for faster access */
+       /* XXX find tail. We could also keep tail in the data struct for faster access */
        for (t = *queue; t && t->next; t = t->next);
 
        r->next = NULL;
@@ -1004,7 +932,7 @@ static int mgcp_hangup(struct ast_channel *ast)
        }
 
        if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
-               /* SC: check whether other channel is active. */
+               /* check whether other channel is active. */
                if (!sub->next->owner) {
                        if (p->dtmfmode & MGCP_DTMF_HYBRID)
                                p->dtmfmode &= ~MGCP_DTMF_INBAND;
@@ -1056,10 +984,10 @@ static int mgcp_hangup(struct ast_channel *ast)
                sub->rtp = NULL;
        }
 
-       /* SC: Decrement use count */
+       /* Decrement use count */
        ast_atomic_fetchadd_int(&__mod_desc->usecnt, -1);
        ast_update_use_count();
-       /* SC: Decrement use count */
+       /* Decrement use count */
 
        if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
                p->hidecallerid = 0;
@@ -1101,7 +1029,7 @@ static int mgcp_show_endpoints(int fd, int argc, char *argv[])
                e = g->endpoints;
                ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), g->addr.sin_addr) : ast_inet_ntoa(iabuf, sizeof(iabuf), g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static");
                while(e) {
-                       /* JS: Don't show wilcard endpoint */
+                       /* Don't show wilcard endpoint */
                        if (strcmp(e->name, g->wcardep) !=0)
                                ast_cli(fd, "   -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle");
                        hasendpoints = 1;
@@ -1197,7 +1125,7 @@ static int mgcp_answer(struct ast_channel *ast)
        } else {
                transmit_modify_request(sub);
        }
-       /* SC: verbose level check */
+       /* verbose level check */
        if (option_verbose > 2) {
                ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_answer(%s) on %s@%s-%d\n", 
                        ast->name, p->name, p->parent->name, sub->id);
@@ -1428,9 +1356,15 @@ static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, siz
        case AST_CONTROL_CONGESTION:
                transmit_notify_request(sub, "G/cg");
                break;
+       case AST_CONTROL_HOLD:
+               ast_moh_start(ast, data, NULL);
+               break;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(ast);
+               break;
        case -1:
                transmit_notify_request(sub, "");
-               break;          
+               break;
        default:
                ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
                res = -1;
@@ -1458,7 +1392,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
                if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
                        i->dsp = ast_dsp_new();
                        ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT);
-                       /* SC: this is to prevent clipping of dtmf tones during dsp processing */
+                       /* this is to prevent clipping of dtmf tones during dsp processing */
                        ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
                } else {
                        i->dsp = NULL;
@@ -1496,7 +1430,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
                                tmp = NULL;
                        }
                }
-               /* SC: verbose level check */
+               /* verbose level check */
                if (option_verbose > 2) {
                        ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_new(%s) created in state: %s\n",
                                tmp->name, ast_state2str(state));
@@ -1637,14 +1571,14 @@ static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, s
                                                ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(iabuf, sizeof(iabuf), g->addr.sin_addr), ntohs(g->addr.sin_port));
                                }
                        }
-                       /* SC: not dynamic, check if the name matches */
+                       /* not dynamic, check if the name matches */
                        else if (name) {
                                if (strcasecmp(g->name, at)) {
                                        g = g->next;
                                        continue;
                                }
                        }
-                       /* SC: not dynamic, no name, check if the addr matches */
+                       /* not dynamic, no name, check if the addr matches */
                        else if (!name && sin) {
                                if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
                                    (g->addr.sin_port != sin->sin_port)) {
@@ -1662,7 +1596,7 @@ static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, s
                                        ast_log(LOG_DEBUG, "Searching on %s@%s for subchannel\n",
                                                p->name, g->name);
                                if (msgid) {
-#if 0 /* SC: new transport mech */
+#if 0 /* new transport mech */
                                        sub = p->sub;
                                        do {
                                                if (option_debug)
@@ -1971,7 +1905,7 @@ static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *ver
                return -1;
        }
        req->header[req->headers] = req->data + req->len;
-       /* SC: check if we need brackets around the gw name */
+       /* check if we need brackets around the gw name */
        if (p->parent->isnamedottedip)
                snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
        else
@@ -2148,12 +2082,12 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
        add_header(&resp, "C", sub->callid);
        add_header(&resp, "L", local);
        add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
-       /* SC: X header should not be sent. kept for compatibility */
+       /* X header should not be sent. kept for compatibility */
        add_header(&resp, "X", sub->txident);
        add_header(&resp, "I", sub->cxident);
        /*add_header(&resp, "S", "");*/
        add_sdp(&resp, sub, rtp);
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_MDCX;
        resp.trid = oseq;
        return send_request(p, sub, &resp, oseq); /* SC */
@@ -2182,11 +2116,11 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp
        add_header(&resp, "C", sub->callid);
        add_header(&resp, "L", local);
        add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
-       /* SC: X header should not be sent. kept for compatibility */
+       /* X header should not be sent. kept for compatibility */
        add_header(&resp, "X", sub->txident);
        /*add_header(&resp, "S", "");*/
        add_sdp(&resp, sub, rtp);
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_CRCX;
        resp.trid = oseq;
        return send_request(p, sub, &resp, oseq);  /* SC */
@@ -2215,7 +2149,7 @@ static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone)
        if (!ast_strlen_zero(tone)) {
                add_header(&resp, "S", tone);
        }
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_RQNT;
        resp.trid = oseq;
        return send_request(p, NULL, &resp, oseq); /* SC */
@@ -2262,7 +2196,7 @@ static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, ch
                ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n", 
                        tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
        }
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_RQNT;
        resp.trid = oseq;
        return send_request(p, NULL, &resp, oseq);  /* SC */
@@ -2285,7 +2219,7 @@ static int transmit_modify_request(struct mgcp_subchannel *sub)
        reqprep(&resp, p, "MDCX");
        add_header(&resp, "C", sub->callid);
        add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
-       /* SC: X header should not be sent. kept for compatibility */
+       /* X header should not be sent. kept for compatibility */
        add_header(&resp, "X", sub->txident);
        add_header(&resp, "I", sub->cxident);
        switch (sub->parent->hookstate) {
@@ -2296,7 +2230,7 @@ static int transmit_modify_request(struct mgcp_subchannel *sub)
                add_header(&resp, "R",  (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N), L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)");
                break;
        }
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_MDCX;
        resp.trid = oseq;
        return send_request(p, sub, &resp, oseq); /* SC */
@@ -2307,10 +2241,10 @@ static int transmit_audit_endpoint(struct mgcp_endpoint *p)
 {
        struct mgcp_request resp;
        reqprep(&resp, p, "AUEP");
-       /* SC: removed unknown param VS */
+       /* removed unknown param VS */
        /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
        add_header(&resp, "F", "A");
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_AUEP;
        resp.trid = oseq;
        return send_request(p, NULL, &resp, oseq);  /* SC */
@@ -2326,15 +2260,15 @@ static int transmit_connection_del(struct mgcp_subchannel *sub)
                        sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
        }
        reqprep(&resp, p, "DLCX");
-       /* SC: check if call id is avail */
+       /* check if call id is avail */
        if (sub->callid[0])
                add_header(&resp, "C", sub->callid);
-       /* SC: X header should not be sent. kept for compatibility */
+       /* X header should not be sent. kept for compatibility */
        add_header(&resp, "X", sub->txident);
-       /* SC: check if cxident is avail */
+       /* check if cxident is avail */
        if (sub->cxident[0])
                add_header(&resp, "I", sub->cxident);
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_DLCX;
        resp.trid = oseq;
        return send_request(p, sub, &resp, oseq);  /* SC */
@@ -2349,13 +2283,13 @@ static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *calli
                        cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
        }
        reqprep(&resp, p, "DLCX");
-       /* SC: check if call id is avail */
+       /* check if call id is avail */
        if (callid && *callid)
                add_header(&resp, "C", callid);
-       /* SC: check if cxident is avail */
+       /* check if cxident is avail */
        if (cxident && *cxident)
                add_header(&resp, "I", cxident);
-       /* SC: fill in new fields */
+       /* fill in new fields */
        resp.cmd = MGCP_CMD_DLCX;
        resp.trid = oseq;
        return send_request(p, p->sub, &resp, oseq);
@@ -2427,7 +2361,7 @@ static struct mgcp_request *find_command(struct mgcp_endpoint *p, struct mgcp_su
        return req;
 }
 
-/* SC: modified for new transport mechanism */
+/* modified for new transport mechanism */
 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,  
                             int result, unsigned int ident, struct mgcp_request *resp)
 {
@@ -2497,7 +2431,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                if (req->cmd == MGCP_CMD_CRCX) {
                        if ((c = get_header(resp, "I"))) {
                                if (!ast_strlen_zero(c) && sub) {
-                                       /* SC: if we are hanging up do not process this conn. */
+                                       /* if we are hanging up do not process this conn. */
                                        if (sub->owner) {
                                                if (!ast_strlen_zero(sub->cxident)) {
                                                        if (strcasecmp(c, sub->cxident)) {
@@ -2509,7 +2443,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                                                        transmit_modify_with_sdp(sub, NULL, 0);
                                                }
                                        } else {
-                                               /* XXX SC: delete this one
+                                               /* XXX delete this one
                                                   callid and conn id may already be lost. 
                                                   so the following del conn may have a side effect of 
                                                   cleaning up the next subchannel */
@@ -2520,7 +2454,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                }
 
                if (req->cmd == MGCP_CMD_AUEP) {
-                       /* SC: check stale connection ids */
+                       /* check stale connection ids */
                        if ((c = get_header(resp, "I"))) {
                                char *v, *n;
                                int len;
@@ -2548,16 +2482,16 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                                if (!ast_strlen_zero(c)) {
                                        if (strstr(c, "hu")) {
                                                if (p->hookstate != MGCP_ONHOOK) {
-                                                       /* SC: XXX cleanup if we think we are offhook XXX */
+                                                       /* XXX cleanup if we think we are offhook XXX */
                                                        if ((p->sub->owner || p->sub->next->owner ) && 
                                                            p->hookstate == MGCP_OFFHOOK)
                                                                mgcp_queue_hangup(sub);
                                                        p->hookstate = MGCP_ONHOOK;
 
-                                                       /* SC: update the requested events according to the new hookstate */
+                                                       /* update the requested events according to the new hookstate */
                                                        transmit_notify_request(p->sub, "");
 
-                                                       /* SC: verbose level check */
+                                                       /* verbose level check */
                                                        if (option_verbose > 2) {
                                                                ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
                                                        }
@@ -2566,10 +2500,10 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                                                if (p->hookstate != MGCP_OFFHOOK) {
                                                        p->hookstate = MGCP_OFFHOOK;
 
-                                                       /* SC: update the requested events according to the new hookstate */
+                                                       /* update the requested events according to the new hookstate */
                                                        transmit_notify_request(p->sub, "");
 
-                                                       /* SC: verbose level check */
+                                                       /* verbose level check */
                                                        if (option_verbose > 2) {
                                                                ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
                                                        }
@@ -2580,7 +2514,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
                }
 
                if (resp && resp->lines) {
-                       /* SC: do not process sdp if we are hanging up. this may be a late response */
+                       /* do not process sdp if we are hanging up. this may be a late response */
                        if (sub && sub->owner) {
                                if (!sub->rtp)
                                        start_rtp(sub);
@@ -2596,7 +2530,7 @@ static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub
 static void start_rtp(struct mgcp_subchannel *sub)
 {
        ast_mutex_lock(&sub->lock);
-       /* SC: check again to be on the safe side */
+       /* check again to be on the safe side */
        if (sub->rtp) {
                ast_rtp_destroy(sub->rtp);
                sub->rtp = NULL;
@@ -2888,7 +2822,7 @@ static int attempt_transfer(struct mgcp_endpoint *p)
                /* The three-way person we're about to transfer to could still be in MOH, so
                   stop if now if appropriate */
                if (ast_bridged_channel(p->sub->next->owner))
-                       ast_moh_stop(ast_bridged_channel(p->sub->next->owner));
+                       ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
                if (p->sub->owner->_state == AST_STATE_RINGING) {
                        ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
                }
@@ -2903,7 +2837,7 @@ static int attempt_transfer(struct mgcp_endpoint *p)
                if (p->sub->owner->_state == AST_STATE_RINGING) {
                        ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
                }
-               ast_moh_stop(ast_bridged_channel(p->sub->next->owner));
+               ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
                if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
                        ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
                                ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
@@ -2942,9 +2876,8 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
        if (sub->outgoing) {
                /* Answered */
                if (sub->owner) {
-                       if (ast_bridged_channel(sub->owner)) {
-                               ast_moh_stop(ast_bridged_channel(sub->owner));
-                       }
+                       if (ast_bridged_channel(sub->owner))
+                               ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
                        sub->cxmode = MGCP_CX_SENDRECV;
                        if (!sub->rtp) {
                                start_rtp(sub);
@@ -3000,9 +2933,8 @@ static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
                                ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
                                ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?");
                        }
-                       if (ast_bridged_channel(sub->owner)) {
-                               ast_moh_stop(ast_bridged_channel(sub->owner));
-                       }
+                       if (ast_bridged_channel(sub->owner))
+                               ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
                        sub->cxmode = MGCP_CX_SENDRECV;
                        if (!sub->rtp) {
                                start_rtp(sub);
@@ -3042,7 +2974,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                        if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) {
                                ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name);
                        }
-                       /* JS: For RSIP on wildcard we reset all endpoints */
+                       /* For RSIP on wildcard we reset all endpoints */
                        if (!strcmp(p->name, p->parent->wcardep)) {
                                /* Reset all endpoints */
                                struct mgcp_endpoint *tmp_ep;
@@ -3072,10 +3004,10 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                mgcp_queue_hangup(sub);
                        }
                        transmit_response(sub, "200", req, "OK");
-                       /* JS: We dont send NTFY or AUEP to wildcard ep */
+                       /* We dont send NTFY or AUEP to wildcard ep */
                        if (strcmp(p->name, p->parent->wcardep) != 0) {
                                transmit_notify_request(sub, "");
-                               /* SC: Audit endpoint. 
+                               /* Audit endpoint. 
                                 Idea is to prevent lost lines due to race conditions 
                                */
                                transmit_audit_endpoint(p);
@@ -3124,9 +3056,8 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
                                        }
                                        transmit_modify_request(sub);
-                                       if (sub->owner && ast_bridged_channel(sub->owner)) {
-                                               ast_moh_start(ast_bridged_channel(sub->owner), NULL);
-                                       }
+                                       if (sub->owner && ast_bridged_channel(sub->owner))
+                                               ast_queue_control(sub->owner, AST_CONTROL_HOLD);
                                        sub->next->cxmode = MGCP_CX_RECVONLY;
                                        handle_hd_hf(sub->next, ev);
                                } else if (sub->owner && sub->next->owner) {
@@ -3139,8 +3070,8 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                }
                                                sub->cxmode = MGCP_CX_CONF;
                                                sub->next->cxmode = MGCP_CX_CONF;
-                                               if (ast_bridged_channel(sub->next->owner)) 
-                                                       ast_moh_stop(ast_bridged_channel(sub->next->owner));
+                                               if (ast_bridged_channel(sub->next->owner))
+                                                       ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
                                                transmit_modify_request(sub);
                                                transmit_modify_request(sub->next);
                                        } else {
@@ -3156,22 +3087,13 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                        ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
                                                }
                                                transmit_modify_request(sub);
-                                               if (ast_bridged_channel(sub->owner)) 
-                                                       ast_moh_start(ast_bridged_channel(sub->owner), NULL);
+                                               if (ast_bridged_channel(sub->owner))
+                                                       ast_queue_control(sub->owner, AST_CONTROL_HOLD);
                         
                                                if (ast_bridged_channel(sub->next->owner)) 
-                                                       ast_moh_stop(ast_bridged_channel(sub->next->owner));
+                                                       ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
                         
                                                handle_hd_hf(sub->next, ev);
-#if 0
-                                               if (sub->next->owner && (sub->next->owner->_state != AST_STATE_UP)) {
-                                                       handle_hd_hf(sub->next, ev);
-                                               } else {
-                                                       ast_verbose(VERBOSE_PREFIX_3 "MGCP Unmuting %d on %s@%s\n", sub->next->id, p->name, p->parent->name);
-                                                       sub->next->cxmode = MGCP_CX_SENDRECV;
-                                                       transmit_modify_request(sub->next);
-                                               }
-#endif
                                        }
                                } else {
                                        /* We've most likely lost one of our calls find an active call and bring it up */
@@ -3184,9 +3106,8 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                                /* XXX - What do we do now? */
                                                return -1;
                                        }
-                                       if (ast_bridged_channel(p->sub->owner)) {
-                                               ast_moh_stop(ast_bridged_channel(p->sub->owner));
-                                       }
+                                       if (ast_bridged_channel(p->sub->owner))
+                                               ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
                                        p->sub->cxmode = MGCP_CX_SENDRECV;
                                        transmit_modify_request(p->sub);
                                }
@@ -3194,12 +3115,11 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n", 
                                        p->name, p->parent->name);
                        }
-                       /*ast_moh_stop(sub->owner->bridge);*/
                } else if (!strcasecmp(ev, "hu")) {
                        p->hookstate = MGCP_ONHOOK;
                        sub->cxmode = MGCP_CX_RECVONLY;
                        ast_log(LOG_DEBUG, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
-                       /* JS: Do we need to send MDCX before a DLCX ?
+                       /* Do we need to send MDCX before a DLCX ?
                        if (sub->rtp) {
                                transmit_modify_request(sub);
                        }
@@ -3227,7 +3147,7 @@ static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req,
                                        sub->alreadygone = 1;
                                        mgcp_queue_hangup(sub);
                                } else {
-                                       /* SC: verbose level check */
+                                       /* verbose level check */
                                        if (option_verbose > 2) {
                                                ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
                                                        p->name, p->parent->name, sub->id);
@@ -3486,7 +3406,7 @@ static void *do_monitor(void *data)
                pthread_testcancel();
                /* Wait for sched or io */
                res = ast_sched_wait(sched);
-               /* SC: copied from chan_sip.c */
+               /* copied from chan_sip.c */
                if ((res < 0) || (res > 1000))
                        res = 1000;
                res = ast_io_wait(io, res);
@@ -3582,7 +3502,7 @@ static struct ast_channel *mgcp_request(const char *type, int format, void *data
        return tmpc;
 }
 
-/* SC: modified for reload support */
+/* modified for reload support */
 /*! \brief  build_gateway: parse mgcp.conf and create gateway/endpoint structures */
 static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
 {
@@ -3595,7 +3515,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
        int ep_reload = 0;
        canreinvite = CANREINVITE;
 
-       /* SC: locate existing gateway */
+       /* locate existing gateway */
        gw = gateways;
        while (gw) {
                if (!strcasecmp(cat, gw->name)) {
@@ -3617,7 +3537,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                        gw->retransid = -1; /* SC */
                        ast_mutex_init(&gw->msgs_lock);
                        ast_copy_string(gw->name, cat, sizeof(gw->name));
-                       /* SC: check if the name is numeric ip */
+                       /* check if the name is numeric ip */
                        if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
                                gw->isnamedottedip = 1;
                }
@@ -3721,7 +3641,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "threewaycalling")) {
                                threewaycalling = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "wcardep")) {
-                               /* SC: locate existing endpoint */
+                               /* locate existing endpoint */
                                e = gw->endpoints;
                                while (e) {
                                        if (!strcasecmp(v->value, e->name)) {
@@ -3822,7 +3742,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "trunk") ||
                                   !strcasecmp(v->name, "line")) {
 
-                               /* SC: locate existing endpoint */
+                               /* locate existing endpoint */
                                e = gw->endpoints;
                                while (e) {
                                        if (!strcasecmp(v->value, e->name)) {
@@ -3860,7 +3780,7 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                                                ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
                                        }
                                        if (!ep_reload) {
-                                               /* XXX SC: potential issue due to reload */
+                                               /* XXX potential issue due to reload */
                                                e->msgstate = -1;
                                                e->parent = gw;
                                        }
@@ -4204,7 +4124,7 @@ static int reload_config(void)
                v = v->next;
        }
 
-       /* SC: mark existing entries for deletion */
+       /* mark existing entries for deletion */
        ast_mutex_lock(&gatelock);
        g = gateways;
        while (g) {
@@ -4241,7 +4161,7 @@ static int reload_config(void)
                cat = ast_category_browse(cfg, cat);
        }
 
-       /* SC: prune deleted entries etc. */
+       /* prune deleted entries etc. */
        prune_gateways();
 
        if (ntohl(bindaddr.sin_addr.s_addr)) {
@@ -4289,7 +4209,7 @@ static int reload_config(void)
        ast_mutex_unlock(&netlock);
        ast_config_destroy(cfg);
 
-       /* SC: send audit only to the new endpoints */
+       /* send audit only to the new endpoints */
        g = gateways;
        while (g) {
                e = g->endpoints;
@@ -4403,15 +4323,10 @@ static int unload_module(void *mod)
        }
 
        if (!ast_mutex_lock(&gatelock)) {
-               g = gateways;
-               while (g) {
+               for (g = gateways; g; g = g->next) {
                        g->delme = 1;
-                       e = g->endpoints;
-                       while (e) {
+                       for (e = g->endpoints; e; e = e->next)
                                e->delme = 1;
-                               e = e->next;
-                       }
-                       g = g->next;
                }
 
                prune_gateways();
index e76e28f..d862a46 100644 (file)
@@ -4291,7 +4291,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        bc->holded_bc=bridged_ch->bc;
                        misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
 
-                       ast_moh_start(bridged, NULL);
+                       /* XXX This should queue an AST_CONTROL_HOLD frame on this channel
+                        * instead of starting moh on the bridged channel directly */
+                       ast_moh_start(bridged, NULL, NULL);
                } else {
                        misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
                        chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
index 36db65f..548e8d6 100644 (file)
@@ -74,6 +74,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/endian.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/abstract_jb.h"
+#include "asterisk/musiconhold.h"
 
 /* ringtones we use */
 #include "busy.h"
@@ -136,6 +137,13 @@ START_CONFIG
     ; context = default                ; default context for outgoing calls
     ; language = ""            ; default language
 
+    ; Default Music on Hold class to use when this channel is placed on hold in
+    ; the case that the music class is not set on the channel with
+    ; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel
+    ; putting this one on hold did not suggest a class to use.
+    ;
+    ; mohinterpret=default
+
     ; If you set overridecontext to 'yes', then the whole dial string
     ; will be interpreted as an extension, which is extremely useful
     ; to dial SIP, IAX and other extensions which use the '@' character.
@@ -365,6 +373,7 @@ struct chan_oss_pvt {
        char language[MAX_LANGUAGE];
        char cid_name[256]; /*XXX */
        char cid_num[256]; /*XXX */
+       char mohinterpret[MAX_MUSICCLASS];
 
        /* buffers used in oss_write */
        char oss_write_buf[FRAME_SIZE*2];
@@ -953,14 +962,24 @@ static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_
        case AST_CONTROL_VIDUPDATE:
                res = -1;
                break;
+       case AST_CONTROL_HOLD:
+               ast_verbose( " << Console Has Been Placed on Hold >> \n");
+               ast_moh_start(c, data, o->mohinterpret);
+               break;
+       case AST_CONTROL_UNHOLD:
+               ast_verbose( " << Console Has Been Retrieved from Hold >> \n");
+               ast_moh_stop(c);
+               break;
        default:
                ast_log(LOG_WARNING,
                    "Don't know how to display condition %d on %s\n",
                    cond, c->name);
                return -1;
        }
+
        if (res > -1)
                ring(o, res);
+       
        return 0;       
 }
 
@@ -1434,6 +1453,8 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg, char *ctg)
                o->name = ast_strdup(ctg);
        }
 
+       strcpy(o->mohinterpret, "default");
+
        o->lastopen = ast_tvnow(); /* don't leave it 0 or tvdiff may wrap */
        /* fill other fields from configuration */
        for (v = ast_variable_browse(cfg, ctg);v; v=v->next) {
@@ -1452,6 +1473,7 @@ static struct chan_oss_pvt * store_config(struct ast_config *cfg, char *ctg)
                M_UINT("queuesize", o->queuesize)
                M_STR("context", o->ctx)
                M_STR("language", o->language)
+               M_STR("mohinterpret", o->mohinterpret)
                M_STR("extension", o->ext)
                M_F("mixer", store_mixer(o, v->value))
                M_F("callerid", store_callerid(o, v->value))
index 99ce67a..12ccba5 100644 (file)
@@ -64,6 +64,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/causes.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/musiconhold.h"
 
 #include "DialTone.h"
 
@@ -219,6 +220,12 @@ static int phone_indicate(struct ast_channel *chan, int condition, const void *d
                        p->lastformat = -1;
                        res = 0;
                        break;
+               case AST_CONTROL_HOLD:
+                       ast_moh_start(chan, data, NULL);
+                       break;
+               case AST_CONTROL_UNHOLD:
+                       ast_moh_stop(chan);
+                       break;
                default:
                        ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, chan->name);
        }
index 2db0dcc..b9442ee 100644 (file)
@@ -452,7 +452,8 @@ static const struct cfsip_options {
  */
 #define DEFAULT_SIP_PORT       5060    /*!< From RFC 3261 (former 2543) */
 #define DEFAULT_CONTEXT                "default"
-#define DEFAULT_MUSICCLASS     "default"
+#define DEFAULT_MOHINTERPRET    "default"
+#define DEFAULT_MOHSUGGEST      ""
 #define DEFAULT_VMEXTEN        "asterisk"
 #define DEFAULT_CALLERID       "asterisk"
 #define DEFAULT_NOTIFYMIME     "application/simple-message-summary"
@@ -486,7 +487,9 @@ static char default_fromdomain[AST_MAX_EXTENSION];
 static char default_notifymime[AST_MAX_EXTENSION];
 static int default_qualify;            /*!< Default Qualify= setting */
 static char default_vmexten[AST_MAX_EXTENSION];
-static char default_musicclass[MAX_MUSICCLASS];                /*!< Global music on hold class */
+static char default_mohinterpret[MAX_MUSICCLASS];  /*!< Global setting for moh class to use when put on hold */
+static char default_mohsuggest[MAX_MUSICCLASS];           /*!< Global setting for moh class to suggest when putting 
+                                                    *   a bridged channel on hold */
 static int default_maxcallbitrate;     /*!< Maximum bitrate for call */
 static struct ast_codec_pref default_prefs;            /*!< Default codec prefs */
 
@@ -868,7 +871,8 @@ static struct sip_pvt {
                AST_STRING_FIELD(fromname);     /*!< Name to show in the user field */
                AST_STRING_FIELD(tohost);       /*!< Host we should put in the "to" field */
                AST_STRING_FIELD(language);     /*!< Default language for this call */
-               AST_STRING_FIELD(musicclass);   /*!< Music on Hold class */
+               AST_STRING_FIELD(mohinterpret); /*!< MOH class to use when put on hold */
+               AST_STRING_FIELD(mohsuggest);   /*!< MOH class to suggest when putting a peer on hold */
                AST_STRING_FIELD(rdnis);        /*!< Referring DNIS */
                AST_STRING_FIELD(theirtag);     /*!< Their tag */
                AST_STRING_FIELD(username);     /*!< [user] name */
@@ -986,7 +990,8 @@ struct sip_user {
        char cid_name[80];              /*!< Caller ID name */
        char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */
        char language[MAX_LANGUAGE];    /*!< Default language for this user */
-       char musicclass[MAX_MUSICCLASS];/*!< Music on Hold class */
+       char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
+       char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
        char useragent[256];            /*!< User agent in SIP request */
        struct ast_codec_pref prefs;    /*!< codec prefs */
        ast_group_t callgroup;          /*!< Call group */
@@ -1032,7 +1037,8 @@ struct sip_peer {
        char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
        char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox setting for MWI checks */
        char language[MAX_LANGUAGE];    /*!<  Default language for prompts */
-       char musicclass[MAX_MUSICCLASS];/*!<  Music on Hold class */
+       char mohinterpret[MAX_MUSICCLASS];/*!<  Music on Hold class */
+       char mohsuggest[MAX_MUSICCLASS];/*!<  Music on Hold class */
        char useragent[256];            /*!<  User agent in SIP request (saved from registration) */
        struct ast_codec_pref prefs;    /*!<  codec prefs */
        int lastmsgssent;
@@ -3541,21 +3547,16 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
                }
                res = -1;
                break;
-       case AST_CONTROL_HOLD:  /* The other part of the bridge are put on hold */
-               if (sipdebug)
-                       ast_log(LOG_DEBUG, "Bridged channel now on hold - %s\n", p->callid);
-               res = -1;
+       case AST_CONTROL_HOLD:
+               ast_moh_start(ast, data, p->mohinterpret);
                break;
-       case AST_CONTROL_UNHOLD:        /* The other part of the bridge are back from hold */
-               if (sipdebug)
-                       ast_log(LOG_DEBUG, "Bridged channel is back from hold, let's talk! : %s\n", p->callid);
-               res = -1;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(ast);
                break;
        case AST_CONTROL_VIDUPDATE:     /* Request a video frame update */
                if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
                        transmit_info_with_vidupdate(p);
                        /* ast_rtcp_send_h261fur(p->vrtp); */
-                       res = 0;
                } else
                        res = -1;
                break;
@@ -3681,8 +3682,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                tmp->amaflags = i->amaflags;
        if (!ast_strlen_zero(i->language))
                ast_string_field_set(tmp, language, i->language);
-       if (!ast_strlen_zero(i->musicclass))
-               ast_string_field_set(tmp, musicclass, i->musicclass);
        i->owner = tmp;
        ast_mutex_lock(&usecnt_lock);
        usecnt++;
@@ -4086,7 +4085,8 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
        else
                ast_string_field_set(p, callid, callid);
        /* Assign default music on hold class */
-       ast_string_field_set(p, musicclass, default_musicclass);
+       ast_string_field_set(p, mohinterpret, default_mohinterpret);
+       ast_string_field_set(p, mohsuggest, default_mohsuggest);
        p->capability = global_capability;
        p->allowtransfer = global_allowtransfer;
        if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
@@ -4935,13 +4935,16 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                /* We have a bridge */
                /* Turn on/off music on hold if we are holding/unholding */
                if (sin.sin_addr.s_addr && !sendonly) {
-                       ast_moh_stop(bridgepeer);
+                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
                
                        /* Activate a re-invite */
                        ast_queue_frame(p->owner, &ast_null_frame);
-               } else if (!sin.sin_addr.s_addr || sendonly ) {
+               } else if (!sin.sin_addr.s_addr || sendonly) {
                        /* No address for RTP, we're on hold */
-                       ast_moh_start(bridgepeer, NULL);
+                       ast_queue_control_data(p->owner, AST_CONTROL_HOLD, 
+                               S_OR(p->mohsuggest, NULL),
+                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+
                        if (sendonly)
                                ast_rtp_stop(p->rtp);
                        /* RTCP needs to go ahead, even if we're on hold!!! */
@@ -8682,7 +8685,8 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                        ast_string_field_set(p, subscribecontext, user->subscribecontext);
                        ast_string_field_set(p, accountcode, user->accountcode);
                        ast_string_field_set(p, language, user->language);
-                       ast_string_field_set(p, musicclass, user->musicclass);
+                       ast_string_field_set(p, mohsuggest, user->mohsuggest);
+                       ast_string_field_set(p, mohinterpret, user->mohinterpret);
                        p->allowtransfer = user->allowtransfer;
                        p->amaflags = user->amaflags;
                        p->callgroup = user->callgroup;
@@ -8769,6 +8773,8 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                        ast_string_field_set(p, peersecret, peer->secret);
                        ast_string_field_set(p, peermd5secret, peer->md5secret);
                        ast_string_field_set(p, subscribecontext, peer->subscribecontext);
+                       ast_string_field_set(p, mohinterpret, peer->mohinterpret);
+                       ast_string_field_set(p, mohsuggest, peer->mohsuggest);
                        if (peer->callingpres)  /* Peer calling pres setting will override RPID */
                                p->callingpres = peer->callingpres;
                        if (peer->maxms && peer->lastms)
@@ -9949,7 +9955,8 @@ static int sip_show_settings(int fd, int argc, char *argv[])
        ast_cli(fd, "  Use ClientCode:         %s\n", ast_test_flag(&global_flags[0], SIP_USECLIENTCODE) ? "Yes" : "No");
        ast_cli(fd, "  Progress inband:        %s\n", (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER) ? "Never" : (ast_test_flag(&global_flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NO) ? "No" : "Yes" );
        ast_cli(fd, "  Language:               %s\n", S_OR(default_language, "(Defaults to English)"));
-       ast_cli(fd, "  Musicclass:             %s\n", default_musicclass);
+       ast_cli(fd, "  MOH Interpret:          %s\n", default_mohinterpret);
+       ast_cli(fd, "  MOH Suggest:            %s\n", default_mohsuggest);
        ast_cli(fd, "  Voice Mail Extension:   %s\n", default_vmexten);
 
        
@@ -13373,8 +13380,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                if (sipdebug && option_debug > 3)
                        ast_log(LOG_DEBUG, "Got SIP transfer, applying to bridged peer '%s'\n", current.chan2->name);
 
-               /* Stop music on hold on this channel */
-               ast_moh_stop(current.chan2);
+               ast_queue_control(current.chan1, AST_CONTROL_UNHOLD);
        }
 
        ast_set_flag(&p->flags[0], SIP_GOTREFER);       
@@ -13603,7 +13609,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
                                bridged_to = ast_bridged_channel(c);
                                if (bridged_to) {
                                        /* Don't actually hangup here... */
-                                       ast_moh_stop(bridged_to);
+                                       ast_queue_control(c, AST_CONTROL_UNHOLD);
                                        ast_async_goto(bridged_to, p->context, p->refer->refer_to,1);
                                } else
                                        ast_queue_hangup(p->owner);
@@ -15021,7 +15027,8 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int
        /* set default context */
        strcpy(user->context, default_context);
        strcpy(user->language, default_language);
-       strcpy(user->musicclass, default_musicclass);
+       strcpy(user->mohinterpret, default_mohinterpret);
+       strcpy(user->mohsuggest, default_mohsuggest);
        for (; v; v = v->next) {
                if (handle_common_options(&userflags[0], &mask[0], v))
                        continue;
@@ -15056,8 +15063,11 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int
                        user->pickupgroup = ast_get_group(v->value);
                } else if (!strcasecmp(v->name, "language")) {
                        ast_copy_string(user->language, v->value, sizeof(user->language));
-               } else if (!strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
-                       ast_copy_string(user->musicclass, v->value, sizeof(user->musicclass));
+               } else if (!strcasecmp(v->name, "mohinterpret") 
+                       || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
+                       ast_copy_string(user->mohinterpret, v->value, sizeof(user->mohinterpret));
+               } else if (!strcasecmp(v->name, "mohsuggest")) {
+                       ast_copy_string(user->mohsuggest, v->value, sizeof(user->mohsuggest));
                } else if (!strcasecmp(v->name, "accountcode")) {
                        ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
                } else if (!strcasecmp(v->name, "call-limit")) {
@@ -15124,7 +15134,8 @@ static void set_peer_defaults(struct sip_peer *peer)
        strcpy(peer->context, default_context);
        strcpy(peer->subscribecontext, default_subscribecontext);
        strcpy(peer->language, default_language);
-       strcpy(peer->musicclass, default_musicclass);
+       strcpy(peer->mohinterpret, default_mohinterpret);
+       strcpy(peer->mohsuggest, default_mohsuggest);
        peer->addr.sin_family = AF_INET;
        peer->defaddr.sin_family = AF_INET;
        peer->capability = global_capability;
@@ -15324,8 +15335,11 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                        }
                } else if (!strcasecmp(v->name, "accountcode")) {
                        ast_copy_string(peer->accountcode, v->value, sizeof(peer->accountcode));
-               } else if (!strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
-                       ast_copy_string(peer->musicclass, v->value, sizeof(peer->musicclass));
+               } else if (!strcasecmp(v->name, "mohinterpret")
+                       || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
+                       ast_copy_string(peer->mohinterpret, v->value, sizeof(peer->mohinterpret));
+               } else if (!strcasecmp(v->name, "mohsuggest")) {
+                       ast_copy_string(peer->mohsuggest, v->value, sizeof(peer->mohsuggest));
                } else if (!strcasecmp(v->name, "mailbox")) {
                        ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
                } else if (!strcasecmp(v->name, "subscribemwi")) {
@@ -15516,7 +15530,8 @@ static int reload_config(enum channelreloadreason reason)
        default_fromdomain[0] = '\0';
        default_qualify = DEFAULT_QUALIFY;
        default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE;
-       ast_copy_string(default_musicclass, DEFAULT_MUSICCLASS, sizeof(default_musicclass));
+       ast_copy_string(default_mohinterpret, DEFAULT_MOHINTERPRET, sizeof(default_mohinterpret));
+       ast_copy_string(default_mohsuggest, DEFAULT_MOHSUGGEST, sizeof(default_mohsuggest));
        ast_copy_string(default_vmexten, DEFAULT_VMEXTEN, sizeof(default_vmexten));
        ast_set_flag(&global_flags[0], SIP_DTMF_RFC2833);                       /*!< Default DTMF setting: RFC2833 */
        ast_set_flag(&global_flags[0], SIP_NAT_RFC3581);                        /*!< NAT support if requested by device with rport */
@@ -15607,8 +15622,11 @@ static int reload_config(enum channelreloadreason reason)
                        global_notifyringing = ast_true(v->value);
                } else if (!strcasecmp(v->name, "alwaysauthreject")) {
                        global_alwaysauthreject = ast_true(v->value);
-               } else if (!strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
-                       ast_copy_string(default_musicclass, v->value, sizeof(default_musicclass));
+               } else if (!strcasecmp(v->name, "mohinterpret") 
+                       || !strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) {
+                       ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret));
+               } else if (!strcasecmp(v->name, "mohsuggest")) {
+                       ast_copy_string(default_mohsuggest, v->value, sizeof(default_mohsuggest));
                } else if (!strcasecmp(v->name, "language")) {
                        ast_copy_string(default_language, v->value, sizeof(default_language));
                } else if (!strcasecmp(v->name, "regcontext")) {
index c74c090..e925b2e 100644 (file)
@@ -733,7 +733,7 @@ static pthread_t tcp_thread;
 static pthread_t accept_t;
 static char context[AST_MAX_CONTEXT] = "default";
 static char language[MAX_LANGUAGE] = "";
-static char musicclass[MAX_MUSICCLASS] = "";
+static char mohinterpret[MAX_MUSICCLASS] = "default";
 static char cid_num[AST_MAX_EXTENSION] = "";
 static char cid_name[AST_MAX_EXTENSION] = "";
 static char linelabel[AST_MAX_EXTENSION] ="";
@@ -911,7 +911,7 @@ struct skinny_line {
        char lastcallerid[AST_MAX_EXTENSION];           /* Last Caller*ID */
        char call_forward[AST_MAX_EXTENSION];
        char mailbox[AST_MAX_EXTENSION];
-       char musicclass[MAX_MUSICCLASS];
+       char mohinterpret[MAX_MUSICCLASS];
        char lastnumberdialed[AST_MAX_EXTENSION];       /* Last number that was dialed - used for redial */
        int curtone;                                    /* Current tone being played */
        ast_group_t callgroup;
@@ -1847,8 +1847,8 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
                                } else {
                                        amaflags = y;
                                }
-                       } else if (!strcasecmp(v->name, "musiconhold")) {
-                               ast_copy_string(musicclass, v->value, sizeof(musicclass));
+                       } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
+                               ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
                        } else if (!strcasecmp(v->name, "callgroup")) {
                                cur_callergroup = ast_get_group(v->value);
                        } else if (!strcasecmp(v->name, "pickupgroup")) {
@@ -1913,7 +1913,7 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
                                        ast_copy_string(l->cid_name, cid_name, sizeof(l->cid_name));
                                        ast_copy_string(l->label, linelabel, sizeof(l->label));
                                        ast_copy_string(l->language, language, sizeof(l->language));
-                                       ast_copy_string(l->musicclass, musicclass, sizeof(l->musicclass));
+                                       ast_copy_string(l->mohinterpret, mohinterpret, sizeof(l->mohinterpret));
                                        ast_copy_string(l->mailbox, mailbox, sizeof(l->mailbox));
                                        ast_copy_string(l->mailbox, mailbox, sizeof(l->mailbox));
                                        if (!ast_strlen_zero(mailbox)) {
@@ -2502,6 +2502,12 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s
        case -1:
                transmit_tone(s, SKINNY_SILENCE);
                break;
+       case AST_CONTROL_HOLD:
+               ast_moh_start(ast, data, l->mohinterpret);
+               break;
+       case AST_CONTROL_UNHOLD:
+               ast_moh_stop(ast);
+               break;
        case AST_CONTROL_PROCEEDING:
                break;
        default:
index d615e60..fa17bf6 100644 (file)
@@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/dsp.h"
 #include "asterisk/features.h"
+#include "asterisk/musiconhold.h"
 }
 
 #include <sys/socket.h>
@@ -1777,7 +1778,12 @@ static int vpb_indicate(struct ast_channel *ast, int condition, const void *data
                                vpb_timer_start(p->busy_timer);
                        }
                        break;
-
+               case AST_CONTROL_HOLD:
+                       ast_moh_start(ast, (const char *) data, NULL);
+                       break;
+               case AST_CONTROL_UNHOLD:
+                       ast_moh_stop(ast);
+                       break;
                default:
                        res = 0;
                        break;
index 7d369a9..1e005b0 100644 (file)
@@ -206,7 +206,8 @@ static char defaultcic[64] = "";
 static char defaultozz[64] = "";
 
 static char language[MAX_LANGUAGE] = "";
-static char musicclass[MAX_MUSICCLASS] = "";
+static char mohinterpret[MAX_MUSICCLASS] = "default";
+static char mohsuggest[MAX_MUSICCLASS] = "";
 static char progzone[10] = "";
 
 static int usedistinctiveringdetection = 0;
@@ -613,7 +614,8 @@ static struct zt_pvt {
        char defcontext[AST_MAX_CONTEXT];
        char exten[AST_MAX_EXTENSION];
        char language[MAX_LANGUAGE];
-       char musicclass[MAX_MUSICCLASS];
+       char mohinterpret[MAX_MUSICCLASS];
+       char mohsuggest[MAX_MUSICCLASS];
 #ifdef PRI_ANI
        char cid_ani[AST_MAX_EXTENSION];
 #endif
@@ -2424,7 +2426,7 @@ static int zt_hangup(struct ast_channel *ast)
                                if (p->owner->_state != AST_STATE_UP)
                                        p->subs[SUB_REAL].needanswer = 1;
                                if (ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                       ast_moh_stop(ast_bridged_channel(p->subs[SUB_REAL].owner));
+                                       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
                        } else if (p->subs[SUB_THREEWAY].zfd > -1) {
                                swap_subs(p, SUB_THREEWAY, SUB_REAL);
                                unalloc_sub(p, SUB_THREEWAY);
@@ -2445,8 +2447,11 @@ static int zt_hangup(struct ast_channel *ast)
                        if (p->subs[SUB_CALLWAIT].inthreeway) {
                                /* This is actually part of a three way, placed on hold.  Place the third part
                                   on music on hold now */
-                               if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
-                                       ast_moh_start(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), NULL);
+                               if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+                                       ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, 
+                                               S_OR(p->mohsuggest, NULL),
+                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               }
                                p->subs[SUB_THREEWAY].inthreeway = 0;
                                /* Make it the call wait now */
                                swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
@@ -2457,8 +2462,11 @@ static int zt_hangup(struct ast_channel *ast)
                        if (p->subs[SUB_CALLWAIT].inthreeway) {
                                /* The other party of the three way call is currently in a call-wait state.
                                   Start music on hold for them, and take the main guy out of the third call */
-                               if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner))
-                                       ast_moh_start(ast_bridged_channel(p->subs[SUB_CALLWAIT].owner), NULL);
+                               if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
+                                       ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, 
+                                               S_OR(p->mohsuggest, NULL),
+                                               !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                               }
                                p->subs[SUB_CALLWAIT].inthreeway = 0;
                        }
                        p->subs[SUB_REAL].inthreeway = 0;
@@ -3404,7 +3412,7 @@ static int attempt_transfer(struct zt_pvt *p)
                /* The three-way person we're about to transfer to could still be in MOH, so
                   stop if now if appropriate */
                if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
-                       ast_moh_stop(ast_bridged_channel(p->subs[SUB_THREEWAY].owner));
+                       ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
                if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
                        ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
                }
@@ -3429,10 +3437,9 @@ static int attempt_transfer(struct zt_pvt *p)
                ast_mutex_unlock(&p->subs[SUB_THREEWAY].owner->lock);
                unalloc_sub(p, SUB_THREEWAY);
        } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
-               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
+               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+               if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)
                        ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
-               }
-               ast_moh_stop(ast_bridged_channel(p->subs[SUB_THREEWAY].owner));
                if (p->subs[SUB_THREEWAY].owner->cdr) {
                        /* Move CDR from second channel to current one */
                        p->subs[SUB_REAL].owner->cdr = 
@@ -3897,7 +3904,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        zt_set_hook(p->subs[index].zfd, ZT_OFFHOOK);
                                        /* Okay -- probably call waiting*/
                                        if (ast_bridged_channel(p->owner))
-                                                       ast_moh_stop(ast_bridged_channel(p->owner));
+                                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
                                        p->subs[index].needunhold = 1;
                                        break;
                                case AST_STATE_RESERVED:
@@ -4054,11 +4061,17 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                        p->callwaitingrepeat = 0;
                                        p->cidcwexpire = 0;
                                        /* Start music on hold if appropriate */
-                                       if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner))
-                                               ast_moh_start(ast_bridged_channel(p->subs[SUB_CALLWAIT].owner), NULL);
+                                       if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
+                                               ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
+                                                       S_OR(p->mohsuggest, NULL),
+                                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       }
                                        p->subs[SUB_CALLWAIT].needhold = 1;
-                                       if (ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                               ast_moh_stop(ast_bridged_channel(p->subs[SUB_REAL].owner));
+                                       if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
+                                               ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
+                                                       S_OR(p->mohsuggest, NULL),
+                                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                       }
                                        p->subs[SUB_REAL].needunhold = 1;
                                } else if (!p->subs[SUB_THREEWAY].owner) {
                                        char cid_num[256];
@@ -4116,8 +4129,11 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                        if (option_verbose > 2) 
                                                                ast_verbose(VERBOSE_PREFIX_3 "Started three way call on channel %d\n", p->channel);
                                                        /* Start music on hold if appropriate */
-                                                       if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
-                                                               ast_moh_start(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), NULL);
+                                                       if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+                                                               ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
+                                                                       S_OR(p->mohsuggest, NULL),
+                                                                       !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+                                                       }
                                                        p->subs[SUB_THREEWAY].needhold = 1;
                                                }               
                                        }
@@ -4155,7 +4171,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                                otherindex = SUB_REAL;
                                                        }
                                                        if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
-                                                               ast_moh_stop(ast_bridged_channel(p->subs[otherindex].owner));
+                                                               ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
                                                        p->subs[otherindex].needunhold = 1;
                                                        p->owner = p->subs[SUB_REAL].owner;
                                                        if (ast->_state == AST_STATE_RINGING) {
@@ -4170,7 +4186,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                        p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
                                                        p->owner = p->subs[SUB_REAL].owner;
                                                        if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                                               ast_moh_stop(ast_bridged_channel(p->subs[SUB_REAL].owner));
+                                                               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
                                                        p->subs[SUB_REAL].needunhold = 1;
                                                        zt_enable_ec(p);
                                                }
@@ -4358,7 +4374,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
                        ast_log(LOG_DEBUG, "Restoring owner of channel %d on event %d\n", p->channel, res);
                        p->owner = p->subs[SUB_REAL].owner;
                        if (p->owner && ast_bridged_channel(p->owner))
-                               ast_moh_stop(ast_bridged_channel(p->owner));
+                               ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
                        p->subs[SUB_REAL].needunhold = 1;
                }
                switch (res) {
@@ -4402,7 +4418,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
                                p->callwaitingrepeat = 0;
                                p->cidcwexpire = 0;
                                if (ast_bridged_channel(p->owner))
-                                       ast_moh_stop(ast_bridged_channel(p->owner));
+                                       ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
                                p->subs[SUB_REAL].needunhold = 1;
                        } else
                                ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
@@ -5005,26 +5021,30 @@ static int zt_indicate(struct ast_channel *chan, int condition, const void *data
 #endif
                                res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
                        break;
-#ifdef HAVE_PRI
                case AST_CONTROL_HOLD:
-                       if (p->pri) {
+#ifdef HAVE_PRI
+                       if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
                                if (!pri_grab(p, p->pri)) {
                                        res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
                                        pri_rel(p->pri);
                                } else
                                                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);                       
-                       }
+                       } else
+#endif
+                               ast_moh_start(chan, data, p->mohinterpret);
                        break;
                case AST_CONTROL_UNHOLD:
-                       if (p->pri) {
+#ifdef HAVE_PRI
+                       if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
                                if (!pri_grab(p, p->pri)) {
                                        res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
                                        pri_rel(p->pri);
                                } else
                                                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);                       
-                       }
-                       break;
+                       } else
 #endif
+                               ast_moh_stop(chan);
+                       break;
                case AST_CONTROL_RADIO_KEY:
                        if (p->radio) 
                            res =  zt_set_hook(p->subs[index].zfd, ZT_OFFHOOK);
@@ -5176,8 +5196,6 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
        }
        if (!ast_strlen_zero(i->language))
                ast_string_field_set(tmp, language, i->language);
-       if (!ast_strlen_zero(i->musicclass))
-               ast_string_field_set(tmp, musicclass, i->musicclass);
        if (!i->owner)
                i->owner = tmp;
        if (!ast_strlen_zero(i->accountcode))
@@ -5882,7 +5900,7 @@ static void *ss_thread(void *data)
                                        unalloc_sub(p, SUB_THREEWAY);
                                        p->owner = p->subs[SUB_REAL].owner;
                                        if (ast_bridged_channel(p->subs[SUB_REAL].owner))
-                                               ast_moh_stop(ast_bridged_channel(p->subs[SUB_REAL].owner));
+                                               ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
                                        ast_hangup(chan);
                                        return NULL;
                                } else {
@@ -7301,7 +7319,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int
                tmp->transfer = transfer;
                ast_copy_string(tmp->defcontext,context,sizeof(tmp->defcontext));
                ast_copy_string(tmp->language, language, sizeof(tmp->language));
-               ast_copy_string(tmp->musicclass, musicclass, sizeof(tmp->musicclass));
+               ast_copy_string(tmp->mohinterpret, mohinterpret, sizeof(tmp->mohinterpret));
+               ast_copy_string(tmp->mohsuggest, mohsuggest, sizeof(tmp->mohsuggest));
                ast_copy_string(tmp->context, context, sizeof(tmp->context));
                ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
                tmp->cid_ton = 0;
@@ -9662,9 +9681,9 @@ static int zap_show_channels(int fd, int argc, char **argv)
 
        ast_mutex_lock(lock);
 #ifdef HAVE_PRI
-       ast_cli(fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MusicOnHold");
+       ast_cli(fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret");
 #else
-       ast_cli(fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MusicOnHold");
+       ast_cli(fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret");
 #endif 
        
        tmp = start;
@@ -9673,7 +9692,7 @@ static int zap_show_channels(int fd, int argc, char **argv)
                        snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
                } else
                        ast_copy_string(tmps, "pseudo", sizeof(tmps));
-               ast_cli(fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->musicclass);
+               ast_cli(fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret);
                tmp = tmp->next;
        }
        ast_mutex_unlock(lock);
@@ -10525,8 +10544,11 @@ static int setup_zap(int reload)
                        ast_copy_string(language, v->value, sizeof(language));
                } else if (!strcasecmp(v->name, "progzone")) {
                        ast_copy_string(progzone, v->value, sizeof(progzone));
-               } else if (!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
-                       ast_copy_string(musicclass, v->value, sizeof(musicclass));
+               } else if (!strcasecmp(v->name, "mohinterpret") 
+                       ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
+                       ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
+               } else if (!strcasecmp(v->name, "mohsuggest")) {
+                       ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
                } else if (!strcasecmp(v->name, "stripmsd")) {
                        stripmsd = atoi(v->value);
                } else if (!strcasecmp(v->name, "jitterbuffers")) {
index e391977..9b036a9 100644 (file)
@@ -20,6 +20,13 @@ extension=s
 ;
 ;language=en
 ;
+; Default Music on Hold class to use when this channel is placed on hold in
+; the case that the music class is not set on the channel with
+; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel
+; putting this one on hold did not suggest a class to use.
+;
+;mohinterpret=default
+;
 ; Silence supression can be enabled when sound is over a certain threshold.
 ; The value for the threshold should probably be between 500 and 2000 or so,
 ; but your mileage may vary.  Use the echo test to evaluate the best setting.
index a0cc636..1bfa458 100644 (file)
@@ -18,6 +18,9 @@ context => parkedcalls                ; Which context parked calls are in
 ;adsipark = yes                        ; if you want ADSI parking announcements
 ;findslot => next              ; Continue to the 'next' free parking space. 
                                ; Defaults to 'first' available
+;parkedmusicclass=default      ; This is the MOH class to use for the parked channel
+                               ; as long as the class is not set on the channel directly
+                               ; using Set(CHANNEL(musicclass)=whatever) in the dialplan
 
 ;transferdigittimeout => 3     ; Number of seconds to wait between digits when transfering a call
                                ; (default is 3 seconds)
index a63c145..f616e4b 100644 (file)
 ;
 ;language=en
 ;
+; This option specifies a preference for which music on hold class this channel
+; should listen to when put on hold if the music class has not been set on the
+; channel with Set(CHANNEL(musicclass)=whatever) in the dialplan, and the peer
+; channel putting this one on hold did not suggest a music class.
+;
+; If this option is set to "passthrough", then the hold message will always be
+; passed through as signalling instead of generating hold music locally.
+;
+; This option may be specified globally, or on a per-user or per-peer basis.
+;
+;mohinterpret=default
+;
+; This option specifies which music on hold class to suggest to the peer channel
+; when this channel places the peer on hold. It may be specified globally or on
+; a per-user or per-peer basis.
+;
+;mohsuggest=default
+;
 ; Specify bandwidth of low, medium, or high to control which codecs are used
 ; in general.
 ;
index 86534f5..4009860 100644 (file)
@@ -51,10 +51,12 @@ monitor-type = MixMonitor
 ;
 ; A sample call queue
 ;
-; Musiconhold sets which music applies for this particular
-; call queue (configure classes in musiconhold.conf)
+; Musicclass sets which music applies for this particular call queue.
+; The only class which can override this one is if the MOH class is set
+; directly on the channel using Set(CHANNEL(musicclass)=whatever) in the
+; dialplan.
 ;
-;musiconhold = default
+;musicclass = default
 ;
 ; An announcement may be specified which is played for the member as
 ; soon as they answer a call, typically to indicate to them which queue
index 2409f6e..3f24034 100644 (file)
@@ -71,8 +71,22 @@ srvlookup=yes                        ; Enable DNS SRV lookups on outbound calls
 ;disallow=all                  ; First disallow all codecs
 ;allow=ulaw                    ; Allow codecs in order of preference
 ;allow=ilbc                    ; 
-;musicclass=default            ; Sets the default music on hold class for all SIP calls
-                               ; This may also be set for individual users/peers
+;
+; This option specifies a preference for which music on hold class this channel
+; should listen to when put on hold if the music class has not been set on the
+; channel with Set(CHANNEL(musicclass)=whatever) in the dialplan, and the peer
+; channel putting this one on hold did not suggest a music class.
+;
+; This option may be specified globally, or on a per-user or per-peer basis.
+;
+;mohinterpret=default
+;
+; This option specifies which music on hold class to suggest to the peer channel
+; when this channel places the peer on hold. It may be specified globally or on
+; a per-user or per-peer basis.
+;
+;mohsuggest=default
+;
 ;language=en                   ; Default language setting for all users/peers
                                ; This may also be set for individual users/peers
 ;relaxdtmf=yes                 ; Relax dtmf handling
index 39313e4..c131c29 100644 (file)
@@ -60,7 +60,10 @@ keepalive=120
 ;threewaycalling=yes
 ;context=default
 ;line => 500           ; Dial(Skinny/500@duba)
-
+;mohinterpret=default   ; This option specifies a default music on hold class to
+                        ; use when put on hold if the channel's moh class was not
+                       ; explicitly set with Set(CHANNEL(musicclass)=whatever) and
+                       ; the peer channel did not suggest a class to use.
 
 ; Typical config for a 7940 with dual 7914s
 ;[support]
index e28153f..c425bca 100644 (file)
@@ -481,10 +481,24 @@ immediate=no
 ;faxdetect=outgoing
 ;faxdetect=no
 ;
-; Select which class of music to use for music on hold.  If not specified
-; then the default will be used.
+; This option specifies a preference for which music on hold class this channel
+; should listen to when put on hold if the music class has not been set on the
+; channel with Set(CHANNEL(musicclass)=whatever) in the dialplan, and the peer
+; channel putting this one on hold did not suggest a music class.
 ;
-;musicclass=default
+; If this option is set to "passthrough", then the hold message will always be
+; passed through as signalling instead of generating hold music locally. This
+; setting is only valid when used on a channel that uses digital signalling.
+;
+; This option may be specified globally, or on a per-user or per-peer basis.
+;
+;mohinterpret=default
+;
+; This option specifies which music on hold class to suggest to the peer channel
+; when this channel places the peer on hold. It may be specified globally or on
+; a per-user or per-peer basis.
+;
+;mohsuggest=default
 ;
 ; PRI channels can have an idle extension and a minunused number.  So long as
 ; at least "minunused" channels are idle, chan_zap will try to call "idledial"
index 55a761c..8a8018d 100644 (file)
 extern "C" {
 #endif
 
-/*! Turn on music on hold on a given channel */
-int ast_moh_start(struct ast_channel *chan, const char *mclass);
+/*!
+ * \brief Turn on music on hold on a given channel 
+ *
+ * \param chan The channel structure that will get music on hold
+ * \param mclass The class to use if the musicclass is not currently set on
+ *               the channel structure.
+ * \param interpclass The class to use if the musicclass is not currently set on
+ *                    the channel structure or in the mclass argument.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass);
 
 /*! Turn off music on hold on a given channel */
 void ast_moh_stop(struct ast_channel *chan);
 
-void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, const char *),
+void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, const char *, const char *),
                                 void (*stop_ptr)(struct ast_channel *),
                                 void (*cleanup_ptr)(struct ast_channel *));
 
diff --git a/pbx.c b/pbx.c
index bf6d14c..c8e6c56 100644 (file)
--- a/pbx.c
+++ b/pbx.c
@@ -5170,7 +5170,7 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
                ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
 
        if (ast_test_flag(&flags, WAITEXTEN_MOH))
-               ast_moh_start(chan, opts[0]);
+               ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
 
        /* Wait for "n" seconds */
        if (args.timeout && (ms = atof(args.timeout)) > 0)
@@ -5195,7 +5195,7 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
        }
 
        if (ast_test_flag(&flags, WAITEXTEN_MOH))
-               ast_moh_stop(chan);
+               ast_indicate(chan, AST_CONTROL_UNHOLD);
 
        return res;
 }
index 7caa4c9..1624e54 100644 (file)
@@ -1330,7 +1330,7 @@ static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[]
 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
        if (!strncasecmp(argv[2], "on", 2))
-               ast_moh_start(chan, argc > 3 ? argv[3] : NULL);
+               ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
        else if (!strncasecmp(argv[2], "off", 3))
                ast_moh_stop(chan);
        fdprintf(agi->fd, "200 result=0\n");
index 588229e..8926afa 100644 (file)
@@ -83,6 +83,7 @@ static char parking_con[AST_MAX_EXTENSION];                /*!< Context for whic
 static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
 static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
+static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
 static int parking_start;                                  /*!< First available extension for parking */
 static int parking_stop;                                   /*!< Last available extension for parking */
 
@@ -358,11 +359,13 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 
        pu->chan = chan;
        
-       /* Start music on hold if we have two different channels */
+       /* Put the parked channel on hold if we have two different channels */
        if (chan != peer) {
-               ast_indicate(pu->chan, AST_CONTROL_HOLD);       /* Indicate to peer that we're on hold */
-               ast_moh_start(pu->chan, NULL);
+               ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
+                       S_OR(parkmohclass, NULL),
+                       !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
        }
+       
        pu->start = ast_tvnow();
        pu->parkingnum = x;
        pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
@@ -423,7 +426,9 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
                ast_say_digits(peer, pu->parkingnum, "", peer->language);
        if (pu->notquiteyet) {
                /* Wake up parking thread if we're really done */
-               ast_moh_start(pu->chan, NULL);
+               ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
+                       S_OR(parkmohclass, NULL),
+                       !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
                pu->notquiteyet = 0;
                pthread_kill(parking_thread, SIGURG);
        }
@@ -612,12 +617,9 @@ static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer
 
 static int finishup(struct ast_channel *chan)
 {
-        int res;
-  
-        ast_moh_stop(chan);
-        res = ast_autoservice_stop(chan);
         ast_indicate(chan, AST_CONTROL_UNHOLD);
-        return res;
+  
+        return ast_autoservice_stop(chan);
 }
 
 /*! \brief Find the context for the transfer */
@@ -644,9 +646,8 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        set_peers(&transferer, &transferee, peer, chan, sense);
        transferer_real_context = real_ctx(transferer, transferee);
        /* Start autoservice on chan while we talk to the originator */
-       ast_indicate(transferee, AST_CONTROL_HOLD);
        ast_autoservice_start(transferee);
-       ast_moh_start(transferee, NULL);
+       ast_indicate(transferee, AST_CONTROL_HOLD);
 
        memset(xferto, 0, sizeof(xferto));
        
@@ -731,7 +732,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
        struct ast_channel *transferer;
        struct ast_channel *transferee;
        const char *transferer_real_context;
-       char xferto[256];
+       char xferto[256] = "";
        int res;
        int outstate=0;
        struct ast_channel *newchan;
@@ -746,10 +747,9 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
        set_peers(&transferer, &transferee, peer, chan, sense);
         transferer_real_context = real_ctx(transferer, transferee);
        /* Start autoservice on chan while we talk to the originator */
-       ast_indicate(transferee, AST_CONTROL_HOLD);
        ast_autoservice_start(transferee);
-       ast_moh_start(transferee, NULL);
-       memset(xferto, 0, sizeof(xferto));
+       ast_indicate(transferee, AST_CONTROL_HOLD);
+       
        /* Transfer */
        res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
        if (res < 0) {
@@ -814,7 +814,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
        if (check_compat(transferee, newchan))
                return -1;
 
-       ast_moh_stop(transferee);
+       ast_indicate(transferee, AST_CONTROL_UNHOLD);
        
        if ((ast_autoservice_stop(transferee) < 0)
           || (ast_waitfordigit(transferee, 100) < 0)
@@ -1521,8 +1521,6 @@ static void *do_parking_thread(void *ignore)
                        }
                        tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
                        if (tms > pu->parkingtime) {
-                               /* Stop music on hold */
-                               ast_moh_stop(chan);
                                ast_indicate(chan, AST_CONTROL_UNHOLD);
                                /* Get chan, exten from derived kludge */
                                if (pu->peername[0]) {
@@ -1620,7 +1618,9 @@ static void *do_parking_thread(void *ignore)
                                                if (pu->moh_trys < 3 && !chan->generatordata) {
                                                        if (option_debug)
                                                                ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
-                                                       ast_moh_start(chan, NULL);
+                                                       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
+                                                               S_OR(parkmohclass, NULL),
+                                                               !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
                                                        pu->moh_trys++;
                                                }
                                                goto std;       /*! \todo XXX Ick: jumping into an else statement??? XXX */
@@ -1748,7 +1748,6 @@ static int park_exec(struct ast_channel *chan, void *data)
                
                if (!ast_strlen_zero(courtesytone)) {
                        int error = 0;
-                       ast_moh_stop(peer);
                        ast_indicate(peer, AST_CONTROL_UNHOLD);
                        if (parkedplay == 0) {
                                error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
@@ -1770,10 +1769,8 @@ static int park_exec(struct ast_channel *chan, void *data)
                                ast_hangup(peer);
                                return -1;
                        }
-               } else {
-                       ast_moh_stop(peer);
+               } else
                        ast_indicate(peer, AST_CONTROL_UNHOLD); 
-               }
 
                res = ast_channel_make_compatible(chan, peer);
                if (res < 0) {
@@ -2063,6 +2060,7 @@ static int load_config(void)
        strcpy(parking_con_dial, "park-dial");
        strcpy(parking_ext, "700");
        strcpy(pickup_ext, "*8");
+       strcpy(parkmohclass, "default");
        courtesytone[0] = '\0';
        strcpy(xfersound, "beep");
        strcpy(xferfailsound, "pbx-invalid");
@@ -2134,6 +2132,8 @@ static int load_config(void)
                                ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
                        } else if (!strcasecmp(var->name, "pickupexten")) {
                                ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
+                       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
+                               ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
                        }
                }
 
index f2d5222..b777ccd 100644 (file)
@@ -549,7 +549,7 @@ static void *monmp3thread(void *data)
 
 static int moh0_exec(struct ast_channel *chan, void *data)
 {
-       if (ast_moh_start(chan, data)) {
+       if (ast_moh_start(chan, data, NULL)) {
                ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
                return -1;
        }
@@ -565,7 +565,7 @@ static int moh1_exec(struct ast_channel *chan, void *data)
                ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
                return -1;
        }
-       if (ast_moh_start(chan, NULL)) {
+       if (ast_moh_start(chan, NULL, NULL)) {
                ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
                return -1;
        }
@@ -589,7 +589,7 @@ static int moh3_exec(struct ast_channel *chan, void *data)
        char *class = NULL;
        if (data && strlen(data))
                class = data;
-       if (ast_moh_start(chan, class)) 
+       if (ast_moh_start(chan, class, NULL)) 
                ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
 
        return 0;
@@ -884,20 +884,37 @@ static void local_ast_moh_cleanup(struct ast_channel *chan)
        }
 }
 
-static int local_ast_moh_start(struct ast_channel *chan, const char *class)
+static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
 {
        struct mohclass *mohclass;
-
-       if (ast_strlen_zero(class))
+       const char *class;
+
+       /* The following is the order of preference for which class to use:
+        * 1) The channels explicitly set musicclass, which should *only* be
+        *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
+        * 2) The mclass argument. If a channel is calling ast_moh_start() as the
+        *    result of receiving a HOLD control frame, this should be the
+        *    payload that came with the frame.
+        * 3) The interpclass argument. This would be from the mohinterpret
+        *    option from channel drivers. This is the same as the old musicclass
+        *    option.
+        * 4) The default class.
+        */
+       if (!ast_strlen_zero(chan->musicclass))
                class = chan->musicclass;
-       if (ast_strlen_zero(class))
+       else if (!ast_strlen_zero(mclass))
+               class = mclass;
+       else if (!ast_strlen_zero(interpclass))
+               class = interpclass;
+       else
                class = "default";
+
        AST_LIST_LOCK(&mohclasses);
        mohclass = get_mohbyname(class);
        AST_LIST_UNLOCK(&mohclasses);
 
        if (!mohclass) {
-               ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
+               ast_log(LOG_WARNING, "No class: %s\n", class);
                return -1;
        }
 
@@ -1104,7 +1121,7 @@ static void moh_on_off(int on)
        while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
                if (ast_test_flag(chan, AST_FLAG_MOH)) {
                        if (on)
-                               local_ast_moh_start(chan, NULL);
+                               local_ast_moh_start(chan, NULL, NULL);
                        else
                                ast_deactivate_generator(chan);
                }