From 5af578c0227af701a8cd689ee393b641ed876be4 Mon Sep 17 00:00:00 2001 From: Automerge script Date: Thu, 13 Dec 2012 22:17:36 +0000 Subject: Merged revisions 378000-378002 via svnmerge from file:///srv/subversion/repos/asterisk/trunk ................ r378000 | seanbright | 2012-12-13 15:20:32 -0600 (Thu, 13 Dec 2012) | 8 lines Make generate_exchange_uuid() always return the passed ast_str pointer. I changed this code earlier to return NULL if it wasn't able to generate a UUID, whereas the earlier code would always return the ast_str that was passed in. Switch back to returning the ast_str, only set it to the empty string instead if UUID generation fails. We still do a validity check later which will catch this and blow up if necessary. ................ r378001 | wedhorn | 2012-12-13 15:25:31 -0600 (Thu, 13 Dec 2012) | 9 lines Minor fixes for chan_skinny Whitespace, change SUBSTATE_ONHOOK to correct SKINNY_ONHOOK and correct len of 2 strcmp in skinny_setdebug(). (see opticron's review on https://reviewboard.asterisk.org/r/2240/) ........ Merged revisions 377991 from http://svn.asterisk.org/svn/asterisk/branches/11 ................ r378002 | rmudgett | 2012-12-13 15:28:15 -0600 (Thu, 13 Dec 2012) | 35 lines confbridge: Fix MOH on simultaneous user entry to a new conference. When two users entered a new conference simultaneously, one of the callers hears MOH. This happened if two unmarked users entered simultaneously and also if a waitmarked and a marked user entered simultaneously. * Created a confbridge internal MOH API to eliminate the inlined MOH handling code. Note that the conference mixing bridge needs to be locked when actually starting/stopping MOH because there is a small window between the conference join unsuspend MOH and actually joining the mixing bridge. * Created the concept of suspended MOH so it can be interrupted while conference join announcements to the user and DTMF features can operate. * Suspend any MOH until the user is about to actually join the mixing bridge of the conference. This way any pre-join file playback does not need to worry about MOH. * Made post-join actions only play deferred entry announcement files. Changing the user/conference state during that time is not protected or controlled by the state machine. (closes issue ASTERISK-20606) Reported by: Eugenia Belova Tested by: rmudgett Review: https://reviewboard.asterisk.org/r/2232/ ........ Merged revisions 377992 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 377993 from http://svn.asterisk.org/svn/asterisk/branches/11 ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/team/mmichelson/threadpool@378003 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_confbridge.c | 143 ++++++++++++++++++++++-------- apps/confbridge/conf_state.c | 19 ++++ apps/confbridge/conf_state_multi_marked.c | 14 +-- apps/confbridge/include/confbridge.h | 19 ++++ channels/chan_skinny.c | 7 +- include/asterisk/bridging.h | 26 ++++++ res/res_calendar_exchange.c | 3 +- 7 files changed, 177 insertions(+), 54 deletions(-) diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index b4ec076ed..22e97f193 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -909,6 +909,94 @@ static int handle_conf_user_leave(struct conference_bridge_user *cbu) return 0; } +void conf_moh_stop(struct conference_bridge_user *user) +{ + user->playing_moh = 0; + if (!user->suspended_moh) { + int in_bridge; + + /* + * Locking the ast_bridge here is the only way to hold off the + * call to ast_bridge_join() in confbridge_exec() from + * interfering with the bridge and MOH operations here. + */ + ast_bridge_lock(user->conference_bridge->bridge); + + /* + * Temporarily suspend the user from the bridge so we have + * control to stop MOH if needed. + */ + in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan); + ast_moh_stop(user->chan); + if (in_bridge) { + ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan); + } + + ast_bridge_unlock(user->conference_bridge->bridge); + } +} + +void conf_moh_start(struct conference_bridge_user *user) +{ + user->playing_moh = 1; + if (!user->suspended_moh) { + int in_bridge; + + /* + * Locking the ast_bridge here is the only way to hold off the + * call to ast_bridge_join() in confbridge_exec() from + * interfering with the bridge and MOH operations here. + */ + ast_bridge_lock(user->conference_bridge->bridge); + + /* + * Temporarily suspend the user from the bridge so we have + * control to start MOH if needed. + */ + in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan); + ast_moh_start(user->chan, user->u_profile.moh_class, NULL); + if (in_bridge) { + ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan); + } + + ast_bridge_unlock(user->conference_bridge->bridge); + } +} + +/*! + * \internal + * \brief Unsuspend MOH for the conference user. + * + * \param user Conference user to unsuspend MOH on. + * + * \return Nothing + */ +static void conf_moh_unsuspend(struct conference_bridge_user *user) +{ + ao2_lock(user->conference_bridge); + if (--user->suspended_moh == 0 && user->playing_moh) { + ast_moh_start(user->chan, user->u_profile.moh_class, NULL); + } + ao2_unlock(user->conference_bridge); +} + +/*! + * \internal + * \brief Suspend MOH for the conference user. + * + * \param user Conference user to suspend MOH on. + * + * \return Nothing + */ +static void conf_moh_suspend(struct conference_bridge_user *user) +{ + ao2_lock(user->conference_bridge); + if (user->suspended_moh++ == 0 && user->playing_moh) { + ast_moh_stop(user->chan); + } + ao2_unlock(user->conference_bridge); +} + int conf_handle_first_marked_common(struct conference_bridge_user *cbu) { if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu, conf_get_sound(CONF_SOUND_PLACE_IN_CONF, cbu->b_profile.sounds))) { @@ -919,19 +1007,12 @@ int conf_handle_first_marked_common(struct conference_bridge_user *cbu) int conf_handle_inactive_waitmarked(struct conference_bridge_user *cbu) { - /* Be sure we are muted so we can't talk to anybody else waiting */ - cbu->features.mute = 1; /* If we have not been quieted play back that they are waiting for the leader */ if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu, conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, cbu->b_profile.sounds))) { /* user hungup while the sound was playing */ return -1; } - /* Start music on hold if needed */ - if (ast_test_flag(&cbu->u_profile, USER_OPT_MUSICONHOLD)) { - ast_moh_start(cbu->chan, cbu->u_profile.moh_class, NULL); - cbu->playing_moh = 1; - } return 0; } @@ -970,11 +1051,8 @@ void conf_handle_second_active(struct conference_bridge *conference_bridge) /* If we are the second participant we may need to stop music on hold on the first */ struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->active_list); - /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */ - if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) { - first_participant->playing_moh = 0; - ast_moh_stop(first_participant->chan); - ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan); + if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) { + conf_moh_stop(first_participant); } if (!ast_test_flag(&first_participant->u_profile, USER_OPT_STARTMUTED)) { first_participant->features.mute = 0; @@ -1099,6 +1177,13 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct ao2_lock(conference_bridge); + /* + * Suspend any MOH until the user actually joins the bridge of + * the conference. This way any pre-join file playback does not + * need to worry about MOH. + */ + conference_bridge_user->suspended_moh = 1; + if (handle_conf_user_join(conference_bridge_user)) { /* Invalid event, nothing was done, so we don't want to process a leave. */ ao2_unlock(conference_bridge); @@ -1530,21 +1615,18 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) /* Play the Join sound to both the conference and the user entering. */ if (!quiet) { const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds); - if (conference_bridge_user.playing_moh) { - ast_moh_stop(chan); - } + ast_stream_and_wait(chan, join_sound, ""); ast_autoservice_start(chan); play_sound_file(conference_bridge, join_sound); ast_autoservice_stop(chan); - if (conference_bridge_user.playing_moh) { - ast_moh_start(chan, conference_bridge_user.u_profile.moh_class, NULL); - } } /* See if we need to automatically set this user as a video source or not */ handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER)); + conf_moh_unsuspend(&conference_bridge_user); + /* Join our conference bridge for real */ send_join_event(conference_bridge_user.chan, conference_bridge->name); ast_bridge_join(conference_bridge->bridge, @@ -1925,25 +2007,14 @@ int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct conf_menu_entry *menu_entry, struct conf_menu *menu) { - struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge; - /* See if music on hold is playing */ - ao2_lock(conference_bridge); - if (conference_bridge_user->playing_moh) { - /* MOH is going, let's stop it */ - ast_moh_stop(bridge_channel->chan); - } - ao2_unlock(conference_bridge); + conf_moh_suspend(conference_bridge_user); /* execute the list of actions associated with this menu entry */ - execute_menu_entry(conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu); + execute_menu_entry(conference_bridge_user->conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu); /* See if music on hold needs to be started back up again */ - ao2_lock(conference_bridge); - if (conference_bridge_user->playing_moh) { - ast_moh_start(bridge_channel->chan, conference_bridge_user->u_profile.moh_class, NULL); - } - ao2_unlock(conference_bridge); + conf_moh_unsuspend(conference_bridge_user); return 0; } @@ -2835,13 +2906,7 @@ void conf_mute_only_active(struct conference_bridge *conference_bridge) /* Turn on MOH/mute if the single participant is set up for it */ if (ast_test_flag(&only_participant->u_profile, USER_OPT_MUSICONHOLD)) { only_participant->features.mute = 1; - if (!ast_channel_internal_bridge(only_participant->chan) || !ast_bridge_suspend(conference_bridge->bridge, only_participant->chan)) { - ast_moh_start(only_participant->chan, only_participant->u_profile.moh_class, NULL); - only_participant->playing_moh = 1; - if (ast_channel_internal_bridge(only_participant->chan)) { - ast_bridge_unsuspend(conference_bridge->bridge, only_participant->chan); - } - } + conf_moh_start(only_participant); } } diff --git a/apps/confbridge/conf_state.c b/apps/confbridge/conf_state.c index e3684058a..ea5ab10f0 100644 --- a/apps/confbridge/conf_state.c +++ b/apps/confbridge/conf_state.c @@ -47,9 +47,28 @@ void conf_invalid_event_fn(struct conference_bridge_user *cbu) ast_log(LOG_ERROR, "Invalid event for confbridge user '%s'\n", cbu->u_profile.name); } +/*! + * \internal + * \brief Mute the user and play MOH if the user requires it. + * + * \param user Conference user to mute and optionally start MOH on. + * + * \return Nothing + */ +static void conf_mute_moh_inactive_waitmarked(struct conference_bridge_user *user) +{ + /* Be sure we are muted so we can't talk to anybody else waiting */ + user->features.mute = 1; + /* Start music on hold if needed */ + if (ast_test_flag(&user->u_profile, USER_OPT_MUSICONHOLD)) { + conf_moh_start(user); + } +} + void conf_default_join_waitmarked(struct conference_bridge_user *cbu) { conf_add_user_waiting(cbu->conference_bridge, cbu); + conf_mute_moh_inactive_waitmarked(cbu); conf_add_post_join_action(cbu, conf_handle_inactive_waitmarked); } diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c index 69850b18d..252926609 100644 --- a/apps/confbridge/conf_state_multi_marked.c +++ b/apps/confbridge/conf_state_multi_marked.c @@ -107,12 +107,8 @@ static void leave_marked(struct conference_bridge_user *cbu) cbu_iter->conference_bridge->waitingusers++; /* Handle muting/moh of cbu_iter if necessary */ if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_MUSICONHOLD)) { - cbu_iter->features.mute = 1; - if (!ast_bridge_suspend(cbu_iter->conference_bridge->bridge, cbu_iter->chan)) { - ast_moh_start(cbu_iter->chan, cbu_iter->u_profile.moh_class, NULL); - cbu_iter->playing_moh = 1; - ast_bridge_unsuspend(cbu_iter->conference_bridge->bridge, cbu_iter->chan); - } + cbu_iter->features.mute = 1; + conf_moh_start(cbu_iter); } } } @@ -173,10 +169,8 @@ static void transition_to_marked(struct conference_bridge_user *cbu) cbu->conference_bridge->waitingusers--; AST_LIST_INSERT_TAIL(&cbu->conference_bridge->active_list, cbu_iter, list); cbu->conference_bridge->activeusers++; - if (cbu_iter->playing_moh && !ast_bridge_suspend(cbu->conference_bridge->bridge, cbu_iter->chan)) { - cbu_iter->playing_moh = 0; - ast_moh_stop(cbu_iter->chan); - ast_bridge_unsuspend(cbu->conference_bridge->bridge, cbu_iter->chan); + if (cbu_iter->playing_moh) { + conf_moh_stop(cbu_iter); } /* only unmute them if they are not supposed to start muted */ if (!ast_test_flag(&cbu_iter->u_profile, USER_OPT_STARTMUTED)) { diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index 0891f5d4e..059262065 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -236,6 +236,7 @@ struct conference_bridge_user { struct ast_channel *chan; /*!< Asterisk channel participating */ struct ast_bridge_features features; /*!< Bridge features structure */ struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */ + unsigned int suspended_moh; /*!< Count of active suspended MOH actions. */ unsigned int kicked:1; /*!< User has been kicked from the conference */ unsigned int playing_moh:1; /*!< MOH is currently being played to the user */ AST_LIST_HEAD_NOLOCK(, post_join_action) post_join_list; /*!< List of sounds to play after joining */; @@ -358,6 +359,24 @@ int play_sound_file(struct conference_bridge *conference_bridge, const char *fil */ void conf_ended(struct conference_bridge *conference_bridge); +/*! + * \brief Stop MOH for the conference user. + * + * \param user Conference user to stop MOH on. + * + * \return Nothing + */ +void conf_moh_stop(struct conference_bridge_user *user); + +/*! + * \brief Start MOH for the conference user. + * + * \param user Conference user to start MOH on. + * + * \return Nothing + */ +void conf_moh_start(struct conference_bridge_user *user); + /*! \brief Attempt to mute/play MOH to the only user in the conference if they require it * \param conference_bridge A conference bridge containing a single user */ diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 7dce0cd9d..1b2c17002 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -671,7 +671,6 @@ struct close_receive_channel_message { }; #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108 - struct soft_key_template_definition { char softKeyLabel[16]; uint32_t softKeyEvent; @@ -2190,7 +2189,7 @@ static char *callstate2str(int ind) char *tmp; switch (ind) { - case SUBSTATE_OFFHOOK: + case SKINNY_OFFHOOK: return "SKINNY_OFFHOOK"; case SKINNY_ONHOOK: return "SKINNY_ONHOOK"; @@ -3362,13 +3361,13 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as bitmask = DEBUG_PACKET; } else if (!strncasecmp(arg, "audio", 5)) { bitmask = DEBUG_AUDIO; - } else if (!strncasecmp(arg, "lock", 6)) { + } else if (!strncasecmp(arg, "lock", 4)) { bitmask = DEBUG_LOCK; } else if (!strncasecmp(arg, "template", 8)) { bitmask = DEBUG_TEMPLATE; } else if (!strncasecmp(arg, "thread", 6)) { bitmask = DEBUG_THREAD; - } else if (!strncasecmp(arg, "hint", 6)) { + } else if (!strncasecmp(arg, "hint", 4)) { bitmask = DEBUG_HINT; } else { ast_cli(a->fd, "Skinny Debugging - option '%s' unknown\n", a->argv[i]); diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index 0f194f418..2c41f4618 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -271,6 +271,32 @@ struct ast_bridge { */ struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags); +/*! + * \brief Lock the bridge. + * + * \param bridge Bridge to lock + * + * \return Nothing + */ +#define ast_bridge_lock(bridge) _ast_bridge_lock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge) +static inline void _ast_bridge_lock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var) +{ + __ao2_lock(bridge, AO2_LOCK_REQ_MUTEX, file, function, line, var); +} + +/*! + * \brief Unlock the bridge. + * + * \param bridge Bridge to unlock + * + * \return Nothing + */ +#define ast_bridge_unlock(bridge) _ast_bridge_unlock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge) +static inline void _ast_bridge_unlock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var) +{ + __ao2_unlock(bridge, file, function, line, var); +} + /*! \brief See if it is possible to create a bridge * * \param capabilities The capabilities that the bridge will use diff --git a/res/res_calendar_exchange.c b/res/res_calendar_exchange.c index dda4414be..ff711c541 100644 --- a/res/res_calendar_exchange.c +++ b/res/res_calendar_exchange.c @@ -246,7 +246,8 @@ static struct ast_str *generate_exchange_uuid(struct ast_str *uid) struct ast_uuid *uuid = ast_uuid_generate(); if (!uuid) { - return NULL; + ast_str_set(&uid, 0, "%s", ""); + return uid; } ast_str_set(&uid, 0, "%s", ast_uuid_to_str(uuid, buffer, AST_UUID_STR_LEN)); -- cgit v1.2.3