diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-07-19 20:44:39 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-07-19 20:44:39 +0000 |
commit | 6049bb6539153c2f400f1f2dbc763c74d796204b (patch) | |
tree | 3c36781db3a5a7a08967cbe8d83acb5d82e581cb | |
parent | 28df168d0f9fd12f5914263015dc26898e834146 (diff) |
merge Russell's 'hold_handling' branch, finally implementing music-on-hold handling the way it was decided at AstriDevCon Europe 2006 (and the way people really want it to be)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@37988 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | apps/app_dial.c | 10 | ||||
-rw-r--r-- | apps/app_followme.c | 5 | ||||
-rw-r--r-- | apps/app_meetme.c | 6 | ||||
-rw-r--r-- | apps/app_queue.c | 9 | ||||
-rw-r--r-- | channel.c | 16 | ||||
-rw-r--r-- | channels/chan_agent.c | 17 | ||||
-rw-r--r-- | channels/chan_alsa.c | 41 | ||||
-rw-r--r-- | channels/chan_h323.c | 10 | ||||
-rw-r--r-- | channels/chan_iax2.c | 69 | ||||
-rw-r--r-- | channels/chan_jingle.c | 16 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 351 | ||||
-rw-r--r-- | channels/chan_misdn.c | 4 | ||||
-rw-r--r-- | channels/chan_oss.c | 22 | ||||
-rw-r--r-- | channels/chan_phone.c | 7 | ||||
-rw-r--r-- | channels/chan_sip.c | 86 | ||||
-rw-r--r-- | channels/chan_skinny.c | 16 | ||||
-rw-r--r-- | channels/chan_vpb.cc | 8 | ||||
-rw-r--r-- | channels/chan_zap.c | 96 | ||||
-rw-r--r-- | configs/alsa.conf.sample | 7 | ||||
-rw-r--r-- | configs/features.conf.sample | 3 | ||||
-rw-r--r-- | configs/iax.conf.sample | 18 | ||||
-rw-r--r-- | configs/queues.conf.sample | 8 | ||||
-rw-r--r-- | configs/sip.conf.sample | 18 | ||||
-rw-r--r-- | configs/skinny.conf.sample | 5 | ||||
-rw-r--r-- | configs/zapata.conf.sample | 20 | ||||
-rw-r--r-- | include/asterisk/musiconhold.h | 17 | ||||
-rw-r--r-- | pbx.c | 4 | ||||
-rw-r--r-- | res/res_agi.c | 2 | ||||
-rw-r--r-- | res/res_features.c | 46 | ||||
-rw-r--r-- | res/res_musiconhold.c | 35 |
30 files changed, 573 insertions, 399 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c index f2834885d..24fe9b7e0 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -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); } diff --git a/apps/app_followme.c b/apps/app_followme.c index 85dda00aa..42986c96f 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -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; diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 698995d19..6b5355ae7 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -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"); diff --git a/apps/app_queue.c b/apps/app_queue.c index b9b578df1..84583250a 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -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 */ @@ -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; } diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 1c440f3b8..1c3f8d8df 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -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", diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 5c921b918..aeadc340c 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -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); } diff --git a/channels/chan_h323.c b/channels/chan_h323.c index a638b19a7..b5e3b18d0 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -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) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index f08547064..046cd7e6f 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -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); diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c index cefecc783..6ea1462ee 100644 --- a/channels/chan_jingle.c +++ b/channels/chan_jingle.c @@ -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) diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 5ad6cb733..0d1a857a1 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -28,48 +28,6 @@ * \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(); diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index e76e28f43..d862a4633 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -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"); diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 36db65fc3..548e8d6dd 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -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)) diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 99ce67a71..12ccba585 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -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); } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 2db0dcc33..b9442ee1f 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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")) { diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index c74c090a9..e925b2e3c 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -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: diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index d615e606a..fa17bf694 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -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; diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 7d369a916..1e005b00a 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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")) { diff --git a/configs/alsa.conf.sample b/configs/alsa.conf.sample index e39197719..9b036a9d9 100644 --- a/configs/alsa.conf.sample +++ b/configs/alsa.conf.sample @@ -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. diff --git a/configs/features.conf.sample b/configs/features.conf.sample index a0cc63600..1bfa45820 100644 --- a/configs/features.conf.sample +++ b/configs/features.conf.sample @@ -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) diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample index a63c145ee..f616e4b21 100644 --- a/configs/iax.conf.sample +++ b/configs/iax.conf.sample @@ -62,6 +62,24 @@ ; ;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. ; diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index 86534f546..40098606f 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -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 diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 2409f6ef3..3f24034cc 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -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 diff --git a/configs/skinny.conf.sample b/configs/skinny.conf.sample index 39313e4fc..c131c2963 100644 --- a/configs/skinny.conf.sample +++ b/configs/skinny.conf.sample @@ -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] diff --git a/configs/zapata.conf.sample b/configs/zapata.conf.sample index e28153f4c..c425bca4d 100644 --- a/configs/zapata.conf.sample +++ b/configs/zapata.conf.sample @@ -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" diff --git a/include/asterisk/musiconhold.h b/include/asterisk/musiconhold.h index 55a761c2f..8a8018d19 100644 --- a/include/asterisk/musiconhold.h +++ b/include/asterisk/musiconhold.h @@ -27,13 +27,24 @@ 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 *)); @@ -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; } diff --git a/res/res_agi.c b/res/res_agi.c index 7caa4c96d..1624e5455 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -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"); diff --git a/res/res_features.c b/res/res_features.c index 588229e16..8926afa78 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -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)); } } diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index f2d5222ad..b777ccd2d 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -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); } |