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
This commit is contained in:
Automerge script
2012-12-13 22:17:36 +00:00
parent c9037da8dc
commit 5af578c022
7 changed files with 177 additions and 54 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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)) {

View File

@@ -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
*/

View File

@@ -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]);

View File

@@ -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

View File

@@ -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));