diff options
author | Patrick McHardy <kaber@trash.net> | 2011-07-06 04:52:35 +0200 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-07-06 04:52:35 +0200 |
commit | 916e420bf0c8db7a8cb1f60557cd2807652142cf (patch) | |
tree | ece8aaf3f22e6e1cc545a858cad9e05c34713426 /apps | |
parent | 9364aaccb699c6d19ac2cbe760c208b34ba7838a (diff) | |
parent | 357b97fb29d196a5f336d6a2879278ea135ab08c (diff) |
Merge branch 'master' of 192.168.0.100:/repos/git/asterisk
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_confbridge.c | 234 | ||||
-rw-r--r-- | apps/app_dial.c | 4 | ||||
-rw-r--r-- | apps/app_meetme.c | 2 | ||||
-rw-r--r-- | apps/app_queue.c | 377 | ||||
-rw-r--r-- | apps/app_stack.c | 2 | ||||
-rw-r--r-- | apps/app_voicemail.c | 6 | ||||
-rw-r--r-- | apps/confbridge/conf_config_parser.c | 24 | ||||
-rw-r--r-- | apps/confbridge/include/confbridge.h | 4 |
8 files changed, 516 insertions, 137 deletions
diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 177ee3717..d046c489f 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -77,6 +77,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <description> <para>Enters the user into a specified conference bridge. The user can exit the conference by hangup or DTMF menu option.</para> </description> + <see-also> + <ref type="application">ConfBridge</ref> + <ref type="function">CONFBRIDGE</ref> + <ref type="function">CONFBRIDGE_INFO</ref> + </see-also> </application> <function name="CONFBRIDGE" language="en_US"> <synopsis> @@ -233,6 +238,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <description> </description> </manager> + <manager name="ConfbridgeSetSingleVideoSrc" language="en_US"> + <synopsis> + Set a conference user as the single video source distributed to all other participants. + </synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" /> + <parameter name="Conference" required="true" /> + <parameter name="Channel" required="true" /> + </syntax> + <description> + </description> + </manager> + ***/ /*! @@ -547,9 +565,9 @@ static void send_leave_event(struct ast_channel *chan, const char *conf_name) * \param (OPTIONAL) conference_bridge_user Caller * * \note if caller is NULL, the announcment will be sent to all participants in the conference. - * \return Returns nothing + * \return Returns 0 on success, -1 if the user hung up */ -static void announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) { const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference_bridge->b_profile.sounds); const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference_bridge->b_profile.sounds); @@ -557,14 +575,14 @@ static void announce_user_count(struct conference_bridge *conference_bridge, str if (conference_bridge->users == 1) { /* Awww we are the only person in the conference bridge */ - return; + return 0; } else if (conference_bridge->users == 2) { if (conference_bridge_user) { /* Eep, there is one other person */ if (ast_stream_and_wait(conference_bridge_user->chan, only_one, "")) { - return; + return -1; } } else { play_sound_file(conference_bridge, only_one); @@ -575,15 +593,15 @@ static void announce_user_count(struct conference_bridge *conference_bridge, str if (ast_stream_and_wait(conference_bridge_user->chan, there_are, "")) { - return; + return -1; } if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", conference_bridge_user->chan->language, NULL)) { - return; + return -1; } if (ast_stream_and_wait(conference_bridge_user->chan, other_in_party, "")) { - return; + return -1; } } else { play_sound_file(conference_bridge, there_are); @@ -591,6 +609,7 @@ static void announce_user_count(struct conference_bridge *conference_bridge, str play_sound_file(conference_bridge, other_in_party); } } + return 0; } /*! @@ -600,15 +619,79 @@ static void announce_user_count(struct conference_bridge *conference_bridge, str * \param chan Channel to play audio prompt to * \param file Prompt to play * - * \return Returns nothing + * \return Returns 0 on success, -1 if the user hung up * * \note This function assumes that conference_bridge is locked */ -static void play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file) +static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file) { + int res; ao2_unlock(conference_bridge); - ast_stream_and_wait(chan, file, ""); + res = ast_stream_and_wait(chan, file, ""); ao2_lock(conference_bridge); + return res; +} + +static void handle_video_on_join(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +{ + /* only automatically set video source for marked users */ + if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) { + return; + } + + if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) { + int set = 1; + struct conference_bridge_user *tmp_user = NULL; + ao2_lock(conference_bridge); + /* see if anyone is already the video src */ + AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) { + if (tmp_user == conference_bridge_user) { + continue; + } + if (ast_bridge_is_video_src(conference_bridge->bridge, tmp_user->chan)) { + set = 0; + break; + } + } + ao2_unlock(conference_bridge); + if (set) { + ast_bridge_set_single_src_video_mode(conference_bridge->bridge, conference_bridge_user->chan); + } + } else if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) { + /* we joined and are video capable, we override anyone else that may have already been the video feed */ + ast_bridge_set_single_src_video_mode(conference_bridge->bridge, conference_bridge_user->chan); + } +} + +static void handle_video_on_exit(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +{ + struct conference_bridge_user *tmp_user = NULL; + + /* if this isn't a video source, nothing to update */ + if (!ast_bridge_is_video_src(conference_bridge->bridge, conference_bridge_user->chan)) { + return; + } + + ast_bridge_remove_video_src(conference_bridge->bridge, conference_bridge_user->chan); + + /* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */ + if (!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) && + !ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) { + return; + } + + /* Make the next avaliable marked user the video src. */ + ao2_lock(conference_bridge); + AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) { + if (tmp_user == conference_bridge_user) { + continue; + } + if (ast_test_flag(&tmp_user->u_profile, USER_OPT_MARKEDUSER)) { + ast_bridge_set_single_src_video_mode(conference_bridge->bridge, tmp_user->chan); + break; + } + } + ao2_unlock(conference_bridge); } /*! @@ -617,16 +700,17 @@ static void play_prompt_to_channel(struct conference_bridge *conference_bridge, * \param conference_bridge Conference bridge being joined * \param conference_bridge_user Conference bridge user joining * - * \return Returns nothing + * \return Returns 0 on success, -1 if the user hung up */ -static void post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) { if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) { struct conference_bridge_user *other_conference_bridge_user = NULL; - /* If we are not the first marked user to join just bail out now */ + /* If we are not the first user to join, then the users are already + * in the conference so we do not need to update them. */ if (conference_bridge->markedusers >= 2) { - return; + return 0; } /* Iterate through every participant stopping MOH on them if need be */ @@ -661,19 +745,21 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct other_conference_bridge_user->features.mute = 0; } } - } else { /* If a marked user already exists in the conference bridge we can just bail out now */ if (conference_bridge->markedusers) { - return; + return 0; } /* Be sure we are muted so we can't talk to anybody else waiting */ conference_bridge_user->features.mute = 1; /* If we have not been quieted play back that they are waiting for the leader */ if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) { - play_prompt_to_channel(conference_bridge, + if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, - conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, conference_bridge_user->b_profile.sounds)); + conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, conference_bridge_user->b_profile.sounds))) { + /* user hungup while the sound was playing */ + return -1; + } } /* Start music on hold if needed */ /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially @@ -684,6 +770,7 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user->playing_moh = 1; } } + return 0; } /*! @@ -692,17 +779,20 @@ static void post_join_marked(struct conference_bridge *conference_bridge, struct * \param conference_bridge Conference bridge being joined * \param conference_bridge_user Conference bridge user joining * - * \return Returns nothing + * \return Returns 0 on success, -1 if the user hung up */ -static void post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) { /* Play back audio prompt and start MOH if need be if we are the first participant */ if (conference_bridge->users == 1) { /* If audio prompts have not been quieted or this prompt quieted play it on out */ if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) { - play_prompt_to_channel(conference_bridge, + if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, - conf_get_sound(CONF_SOUND_ONLY_PERSON, conference_bridge_user->b_profile.sounds)); + conf_get_sound(CONF_SOUND_ONLY_PERSON, conference_bridge_user->b_profile.sounds))) { + /* user hungup while the sound was playing */ + return -1; + } } /* If we need to start music on hold on the channel do so now */ /* We need to re-check the number of users in the conference bridge here because another conference bridge @@ -712,13 +802,16 @@ static void post_join_unmarked(struct conference_bridge *conference_bridge, stru ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL); conference_bridge_user->playing_moh = 1; } - return; + return 0; } /* Announce number of users if need be */ if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) { ao2_unlock(conference_bridge); - announce_user_count(conference_bridge, conference_bridge_user); + if (announce_user_count(conference_bridge, conference_bridge_user)) { + ao2_lock(conference_bridge); + return -1; + } ao2_lock(conference_bridge); } @@ -737,9 +830,13 @@ static void post_join_unmarked(struct conference_bridge *conference_bridge, stru if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) && (conference_bridge->users > conference_bridge_user->u_profile.announce_user_count_all_after)) { ao2_unlock(conference_bridge); - announce_user_count(conference_bridge, NULL); + if (announce_user_count(conference_bridge, NULL)) { + ao2_lock(conference_bridge); + return -1; + } ao2_lock(conference_bridge); } + return 0; } /*! @@ -772,6 +869,8 @@ static void destroy_conference_bridge(void *obj) conf_bridge_profile_destroy(&conference_bridge->b_profile); } +static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user); + /*! * \brief Join a conference bridge * @@ -840,6 +939,10 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct /* Set the internal mixing interval on the bridge from the bridge profile */ ast_bridge_set_mixing_interval(conference_bridge->bridge, conference_bridge->b_profile.mix_interval); + if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) { + ast_bridge_set_talker_src_video_mode(conference_bridge->bridge); + } + /* Setup lock for playback channel */ ast_mutex_init(&conference_bridge->playback_lock); @@ -876,9 +979,17 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */ if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER | USER_OPT_WAITMARKED)) { - post_join_marked(conference_bridge, conference_bridge_user); + if (post_join_marked(conference_bridge, conference_bridge_user)) { + ao2_unlock(conference_bridge); + leave_conference_bridge(conference_bridge, conference_bridge_user); + return NULL; + } } else { - post_join_unmarked(conference_bridge, conference_bridge_user); + if (post_join_unmarked(conference_bridge, conference_bridge_user)) { + ao2_unlock(conference_bridge); + leave_conference_bridge(conference_bridge, conference_bridge_user); + return NULL; + } } /* check to see if recording needs to be started or not */ @@ -1335,14 +1446,16 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) ast_moh_stop(chan); } ast_stream_and_wait(chan, join_sound, ""); - if (conference_bridge_user.playing_moh) { - ast_moh_start(chan, conference_bridge_user.u_profile.moh_class, NULL); - } 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); + } } + handle_video_on_join(conference_bridge, &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, @@ -1352,6 +1465,9 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) &conference_bridge_user.tech_args); send_leave_event(conference_bridge_user.chan, conference_bridge->name); + + handle_video_on_exit(conference_bridge, &conference_bridge_user); + /* if this user has a intro, play it when leaving */ if (!quiet && !ast_strlen_zero(conference_bridge_user.name_rec_location)) { ast_autoservice_start(chan); @@ -1373,9 +1489,6 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) leave_conference_bridge(conference_bridge, &conference_bridge_user); conference_bridge = NULL; - /* Can't forget to clean up the features structure, or else we risk a memory leak */ - ast_bridge_features_cleanup(&conference_bridge_user.features); - /* If the user was kicked from the conference play back the audio prompt for it */ if (!quiet && conference_bridge_user.kicked) { res = ast_stream_and_wait(chan, @@ -1657,6 +1770,11 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge, break; case MENU_ACTION_NOOP: break; + case MENU_ACTION_SET_SINGLE_VIDEO_SRC: + ao2_lock(conference_bridge); + ast_bridge_set_single_src_video_mode(conference_bridge->bridge, bridge_channel->chan); + ao2_unlock(conference_bridge); + break; } } return res; @@ -2412,6 +2530,55 @@ static int action_confbridgestoprecord(struct mansession *s, const struct messag return 0; } +static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m) +{ + const char *conference = astman_get_header(m, "Conference"); + const char *channel = astman_get_header(m, "Channel"); + struct conference_bridge_user *participant = NULL; + struct conference_bridge *bridge = NULL; + struct conference_bridge tmp; + + if (ast_strlen_zero(conference)) { + astman_send_error(s, m, "No Conference name provided."); + return 0; + } + if (ast_strlen_zero(channel)) { + astman_send_error(s, m, "No channel name provided."); + return 0; + } + if (!ao2_container_count(conference_bridges)) { + astman_send_error(s, m, "No active conferences."); + return 0; + } + + ast_copy_string(tmp.name, conference, sizeof(tmp.name)); + bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER); + if (!bridge) { + astman_send_error(s, m, "No Conference by that name found."); + return 0; + } + + /* find channel and set as video src. */ + ao2_lock(bridge); + AST_LIST_TRAVERSE(&bridge->users_list, participant, list) { + if (!strncmp(channel, participant->chan->name, strlen(channel))) { + ast_bridge_set_single_src_video_mode(bridge->bridge, participant->chan); + break; + } + } + ao2_unlock(bridge); + ao2_ref(bridge, -1); + + /* do not access participant after bridge unlock. We are just + * using this check to see if it was found or not */ + if (!participant) { + astman_send_error(s, m, "No channel by that name found in conference."); + return 0; + } + astman_send_ack(s, m, "Conference single video source set."); + return 0; +} + static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { char *parse = NULL; @@ -2543,6 +2710,7 @@ static int load_module(void) res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock); res |= ast_manager_register_xml("ConfbridgeStartRecord", EVENT_FLAG_CALL, action_confbridgestartrecord); res |= ast_manager_register_xml("ConfbridgeStopRecord", EVENT_FLAG_CALL, action_confbridgestoprecord); + res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc); conf_load_config(0); return res; diff --git a/apps/app_dial.c b/apps/app_dial.c index 25172c743..d3b8009de 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/aoc.h" #include "asterisk/ccss.h" #include "asterisk/indications.h" +#include "asterisk/framehook.h" /*** DOCUMENTATION <application name="Dial" language="en_US"> @@ -631,7 +632,8 @@ END_OPTIONS ); OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | \ OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB) && \ - !chan->audiohooks && !peer->audiohooks) + !chan->audiohooks && !peer->audiohooks && \ + ast_framehook_list_is_empty(chan->framehooks) && ast_framehook_list_is_empty(peer->framehooks)) /* * The list of active channels diff --git a/apps/app_meetme.c b/apps/app_meetme.c index dad293b6e..40f5b0ee4 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -371,7 +371,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </syntax> <description> <para>Run admin <replaceable>command</replaceable> for a specific - <replaceable>channel</replaceable> in any coference.</para> + <replaceable>channel</replaceable> in any conference.</para> </description> </application> <application name="SLAStation" language="en_US"> diff --git a/apps/app_queue.c b/apps/app_queue.c index be929c1dc..9442ce649 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -57,7 +57,7 @@ */ /*** MODULEINFO - <use>res_monitor</use> + <use type="module">res_monitor</use> ***/ #include "asterisk.h" @@ -521,11 +521,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <enum name="count"> <para>Returns the total number of members for the specified queue.</para> </enum> + <enum name="penalty"> + <para>Gets or sets queue member penalty.</para> + </enum> + <enum name="paused"> + <para>Gets or sets queue member paused status.</para> + </enum> + <enum name="ignorebusy"> + <para>Gets or sets queue member ignorebusy.</para> + </enum> </enumlist> </parameter> + <parameter name="interface" required="false" /> </syntax> <description> - <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para> + <para>Allows access to queue counts [R] and member information [R/W].</para> + <para> + <replaceable>queuename</replaceable> is required for all operations + <replaceable>interface</replaceable> is required for all member operations. + </para> </description> <see-also> <ref type="application">Queue</ref> @@ -658,6 +672,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </syntax> <description> <para>Gets or sets queue members penalty.</para> + <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning> </description> <see-also> <ref type="application">Queue</ref> @@ -680,7 +695,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") Queues. </synopsis> <syntax> - <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" /> </syntax> <description> </description> @@ -934,6 +948,9 @@ static struct ast_event_sub *device_state_sub; /*! \brief queues.conf [general] option */ static int update_cdr = 0; +/*! \brief queues.conf [general] option */ +static int negative_penalty_invalid = 0; + enum queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, @@ -1043,6 +1060,7 @@ struct member { unsigned int dead:1; /*!< Used to detect members deleted in realtime */ unsigned int delme:1; /*!< Flag to delete entry on reload */ char rt_uniqueid[80]; /*!< Unique id of realtime member entry */ + unsigned int ignorebusy:1; /*!< Flag to ignore member if the status is not available */ }; enum empty_conditions { @@ -1160,6 +1178,7 @@ struct call_queue { int timeout; /*!< How long to wait for an answer */ int weight; /*!< Respective weight */ int autopause; /*!< Auto pause queue members if they fail to answer */ + int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */ int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */ /* Queue strategy things */ @@ -1190,9 +1209,10 @@ static AST_LIST_HEAD_STATIC(rule_lists, rule_list); static struct ao2_container *queues; static void update_realtime_members(struct call_queue *q); +static struct member *interface_exists(struct call_queue *q, const char *interface); static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused); -static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); +static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); /*! \brief sets the QUEUESTATUS channel variable */ static void set_queue_result(struct ast_channel *chan, enum queue_result res) { @@ -1698,6 +1718,7 @@ static void init_queue(struct call_queue *q) q->numperiodicannounce = 0; q->autopause = QUEUE_AUTOPAUSE_OFF; q->timeoutpriority = TIMEOUT_PRIORITY_APP; + q->autopausedelay = 0; if (!q->members) { if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) /* linear strategy depends on order, so we have to place all members in a single bucket */ @@ -1760,7 +1781,7 @@ static void clear_queue(struct call_queue *q) * \retval 0 on success * \note Call this with the rule_lists locked */ -static int insert_penaltychange (const char *list_name, const char *content, const int linenum) +static int insert_penaltychange(const char *list_name, const char *content, const int linenum) { char *timestr, *maxstr, *minstr, *contentdup; struct penalty_rule *rule = NULL, *rule_iter; @@ -2003,6 +2024,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char q->montype = 1; } else if (!strcasecmp(param, "autopause")) { q->autopause = autopause2int(val); + } else if (!strcasecmp(param, "autopausedelay")) { + q->autopausedelay = atoi(val); } else if (!strcasecmp(param, "maxlen")) { q->maxlen = atoi(val); if (q->maxlen < 0) @@ -2081,7 +2104,9 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc int penalty = 0; int paused = 0; int found = 0; + int ignorebusy = 0; + const char *config_val; const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid"); const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface); const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface); @@ -2095,8 +2120,11 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc if (penalty_str) { penalty = atoi(penalty_str); - if (penalty < 0) + if ((penalty < 0) && negative_penalty_invalid) { + return; + } else if (penalty < 0) { penalty = 0; + } } if (paused_str) { @@ -2105,31 +2133,39 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, struc paused = 0; } - /* Find member by realtime uniqueid and update */ - mem_iter = ao2_iterator_init(q->members, 0); - while ((m = ao2_iterator_next(&mem_iter))) { - if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { - m->dead = 0; /* Do not delete this one. */ - ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); - if (paused_str) - m->paused = paused; - if (strcasecmp(state_interface, m->state_interface)) { - ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); - } - m->penalty = penalty; - found = 1; - ao2_ref(m, -1); - break; - } - ao2_ref(m, -1); - } + if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy"))) { + ignorebusy = ast_true(config_val); + } else { + ignorebusy = 1; + } + + /* Find member by realtime uniqueid and update */ + mem_iter = ao2_iterator_init(q->members, 0); + while ((m = ao2_iterator_next(&mem_iter))) { + if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { + m->dead = 0; /* Do not delete this one. */ + ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); + if (paused_str) + m->paused = paused; + if (strcasecmp(state_interface, m->state_interface)) { + ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); + } + m->penalty = penalty; + m->ignorebusy = ignorebusy; + found = 1; + ao2_ref(m, -1); + break; + } + ao2_ref(m, -1); + } ao2_iterator_destroy(&mem_iter); - /* Create a new member */ - if (!found) { + /* Create a new member */ + if (!found) { if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { m->dead = 0; m->realtime = 1; + m->ignorebusy = ignorebusy; ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", ""); ao2_link(q->members, m); @@ -2873,16 +2909,24 @@ static int num_available_members(struct call_queue *q) mem_iter = ao2_iterator_init(q->members, 0); while ((mem = ao2_iterator_next(&mem_iter))) { switch (mem->status) { - case AST_DEVICE_INUSE: - if (!q->ringinuse) + case AST_DEVICE_INVALID: + case AST_DEVICE_UNAVAILABLE: + break; + case AST_DEVICE_INUSE: + case AST_DEVICE_BUSY: + case AST_DEVICE_RINGING: + case AST_DEVICE_RINGINUSE: + case AST_DEVICE_ONHOLD: + if ((!q->ringinuse) || (!mem->ignorebusy)) { + break; + } + /* else fall through */ + case AST_DEVICE_NOT_INUSE: + case AST_DEVICE_UNKNOWN: + if (!mem->paused) { + avl++; + } break; - /* else fall through */ - case AST_DEVICE_NOT_INUSE: - case AST_DEVICE_UNKNOWN: - if (!mem->paused) { - avl++; - } - break; } ao2_ref(mem, -1); @@ -3010,38 +3054,54 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies char tech[256]; char *location; const char *macrocontext, *macroexten; + enum ast_device_state newstate; /* on entry here, we know that tmp->chan == NULL */ - if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || - (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { - ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", - (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); - if (qe->chan->cdr) + if (tmp->member->paused) { + ast_debug(1, "%s paused, can't receive call\n", tmp->interface); + if (qe->chan->cdr) { ast_cdr_busy(qe->chan->cdr); + } tmp->stillgoing = 0; - (*busies)++; return 0; } - if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { - ast_debug(1, "%s in use, can't receive call\n", tmp->interface); - if (qe->chan->cdr) + if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || + (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { + ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", + (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); + if (qe->chan->cdr) { ast_cdr_busy(qe->chan->cdr); + } tmp->stillgoing = 0; + (*busies)++; return 0; } - if (tmp->member->paused) { - ast_debug(1, "%s paused, can't receive call\n", tmp->interface); - if (qe->chan->cdr) - ast_cdr_busy(qe->chan->cdr); - tmp->stillgoing = 0; - return 0; + if (!qe->parent->ringinuse || !tmp->member->ignorebusy) { + if ((tmp->member->status == AST_DEVICE_UNKNOWN) || (tmp->member->status == AST_DEVICE_NOT_INUSE)) { + newstate = ast_parse_device_state(tmp->member->interface); + if (newstate != tmp->member->status) { + ast_log(LOG_ERROR, "Found a channel matching iterface %s while status was %i changed to %i\n", + tmp->member->interface, tmp->member->status, newstate); + update_status(qe->parent, tmp->member, newstate); + } + } + if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { + ast_debug(1, "%s in use, can't receive call\n", tmp->interface); + if (qe->chan->cdr) { + ast_cdr_busy(qe->chan->cdr); + } + tmp->stillgoing = 0; + return 0; + } } + if (use_weight && compare_weight(qe->parent,tmp->member)) { ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_cdr_busy(qe->chan->cdr); + } tmp->stillgoing = 0; (*busies)++; return 0; @@ -3056,8 +3116,9 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies /* Request the peer */ tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); if (!tmp->chan) { /* If we can't, just go on to the next call */ - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_cdr_busy(qe->chan->cdr); + } tmp->stillgoing = 0; ao2_lock(qe->parent); @@ -3396,6 +3457,18 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member } ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { + if (qe->parent->autopausedelay > 0) { + struct member *mem; + ao2_lock(qe->parent); + if ((mem = interface_exists(qe->parent, interface))) { + time_t idletime = time(&idletime)-mem->lastcall; + if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) { + ao2_unlock(qe->parent); + return; + } + } + ao2_unlock(qe->parent); + } if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", @@ -4707,8 +4780,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce else ast_moh_stop(qe->chan); /* If appropriate, log that we have a destination channel */ - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_cdr_setdestchan(qe->chan->cdr, peer->name); + } /* Make sure channels are compatible */ res = ast_channel_make_compatible(qe->chan, peer); if (res < 0) { @@ -4788,10 +4862,11 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (mixmonapp) { ast_debug(1, "Starting MixMonitor as requested.\n"); if (!monitorfilename) { - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); - else + } else { snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); + } } else { const char *m = monitorfilename; for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { @@ -4858,12 +4933,13 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); /* We purposely lock the CDR so that pbx_exec does not update the application data */ - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); + } pbx_exec(qe->chan, mixmonapp, mixmonargs); - if (qe->chan->cdr) + if (qe->chan->cdr) { ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); - + } } else { ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); } @@ -5180,7 +5256,10 @@ static int remove_from_queue(const char *queuename, const char *interface) ao2_lock(q); if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { /* XXX future changes should beware of this assumption!! */ - if (!mem->dynamic) { + /*Change Penalty on realtime users*/ + if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) { + update_realtime_member_field(mem, q->name, "penalty", "-1"); + } else if (!mem->dynamic) { ao2_ref(mem, -1); ao2_unlock(q); queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); @@ -5355,35 +5434,34 @@ static int set_member_penalty(const char *queuename, const char *interface, int int foundinterface = 0, foundqueue = 0; struct call_queue *q; struct member *mem; - struct ao2_iterator queue_iter; + char rtpenalty[80]; - if (penalty < 0) { + if (penalty < 0 && !negative_penalty_invalid) { ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); return RESULT_FAILURE; } - queue_iter = ao2_iterator_init(queues, 0); - while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { + if ((q = load_realtime_queue(queuename))) { + foundqueue++; ao2_lock(q); - if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { - foundqueue++; - if ((mem = interface_exists(q, interface))) { - foundinterface++; + if ((mem = interface_exists(q, interface))) { + foundinterface++; + if (!mem->realtime) { mem->penalty = penalty; - - ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); - manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", - "Queue: %s\r\n" - "Location: %s\r\n" - "Penalty: %d\r\n", - q->name, mem->interface, penalty); - ao2_ref(mem, -1); + } else { + sprintf(rtpenalty,"%i", penalty); + update_realtime_member_field(mem, q->name, "penalty", rtpenalty); } + ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); + manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", + "Queue: %s\r\n" + "Location: %s\r\n" + "Penalty: %d\r\n", + q->name, mem->interface, penalty); + ao2_ref(mem, -1); } ao2_unlock(q); - queue_t_unref(q, "Done with iterator"); } - ao2_iterator_destroy(&queue_iter); if (foundinterface) { return RESULT_SUCCESS; @@ -5769,7 +5847,6 @@ static void copy_rules(struct queue_ent *qe, const char *rulename) struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); if (!new_pr) { ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); - AST_LIST_UNLOCK(&rule_lists); break; } new_pr->time = pr_iter->time; @@ -6157,31 +6234,37 @@ static int queue_function_exists(struct ast_channel *chan, const char *cmd, char return 0; } -/*! +/*! * \brief Get number either busy / free / ready or total members of a specific queue - * \retval number of members (busy / free / ready / total) + * \brief Get or set member properties penalty / paused / ignorebusy + * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy) * \retval -1 on error */ -static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { int count = 0; struct member *m; struct ao2_iterator mem_iter; struct call_queue *q; - char *option; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(queuename); + AST_APP_ARG(option); + AST_APP_ARG(interface); + ); + /* Make sure the returned value on error is zero length string. */ + buf[0] = '\0'; if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); return -1; } - if ((option = strchr(data, ','))) - *option++ = '\0'; - else - option = "logged"; - if ((q = load_realtime_queue(data))) { + AST_STANDARD_APP_ARGS(args, data); + + if ((q = load_realtime_queue(args.queuename))) { ao2_lock(q); - if (!strcasecmp(option, "logged")) { + if (!strcasecmp(args.option, "logged")) { mem_iter = ao2_iterator_init(q->members, 0); while ((m = ao2_iterator_next(&mem_iter))) { /* Count the agents who are logged in and presently answering calls */ @@ -6191,7 +6274,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - } else if (!strcasecmp(option, "free")) { + } else if (!strcasecmp(args.option, "free")) { mem_iter = ao2_iterator_init(q->members, 0); while ((m = ao2_iterator_next(&mem_iter))) { /* Count the agents who are logged in and presently answering calls */ @@ -6201,7 +6284,7 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - } else if (!strcasecmp(option, "ready")) { + } else if (!strcasecmp(args.option, "ready")) { time_t now; time(&now); mem_iter = ao2_iterator_init(q->members, 0); @@ -6214,22 +6297,104 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d ao2_ref(m, -1); } ao2_iterator_destroy(&mem_iter); - } else /* must be "count" */ + } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) { count = q->membercount; + } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) && + ((m = interface_exists(q, args.interface)))) { + count = m->penalty; + } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) && + ((m = interface_exists(q, args.interface)))) { + count = m->paused; + } else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface) && + ((m = interface_exists(q, args.interface)))) { + count = m->ignorebusy; + } ao2_unlock(q); queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); - } else - ast_log(LOG_WARNING, "queue %s was not found\n", data); + } else { + ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename); + } snprintf(buf, len, "%d", count); return 0; } -/*! +/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. */ +static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + int memvalue; + struct call_queue *q; + struct member *m; + char rtvalue[80]; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(queuename); + AST_APP_ARG(option); + AST_APP_ARG(interface); + ); + + if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n"); + return -1; + } + + AST_STANDARD_APP_ARGS(args, data); + + if (args.argc < 3) { + ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); + return -1; + } + + if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) { + ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n"); + return -1; + } + + memvalue = atoi(value); + + if (!strcasecmp(args.option, "penalty")) { + /* if queuename = NULL then penalty will be set for interface in all the queues.*/ + if (set_member_penalty(args.queuename, args.interface, memvalue)) { + ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); + return -1; + } + } else if ((q = load_realtime_queue(args.queuename))) { + ao2_lock(q); + if ((m = interface_exists(q, args.interface))) { + sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1"); + if (!strcasecmp(args.option, "paused")) { + if (m->realtime) { + update_realtime_member_field(m, q->name, args.option, rtvalue); + } else { + m->paused = (memvalue <= 0) ? 0 : 1; + } + } else if (!strcasecmp(args.option, "ignorebusy")) { + if (m->realtime) { + update_realtime_member_field(m, q->name, args.option, rtvalue); + } else { + m->ignorebusy = (memvalue <= 0) ? 0 : 1; + } + } else { + ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n"); + return -1; + } + } else { + ast_log(LOG_ERROR, "Invalid interface or queue\n"); + return -1; + } + ao2_unlock(q); + } else { + ast_log(LOG_ERROR, "Invalid queue\n"); + return -1; + } + return 0; +} + +/*! * \brief Get the total number of members in a specific queue (Deprecated) - * \retval number of members - * \retval -1 on error + * \retval number of members + * \retval -1 on error */ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { @@ -6435,7 +6600,8 @@ static struct ast_custom_function queuevar_function = { static struct ast_custom_function queuemembercount_function = { .name = "QUEUE_MEMBER", - .read = queue_function_qac, + .read = queue_function_mem_read, + .write = queue_function_mem_write, }; static struct ast_custom_function queuemembercount_dep = { @@ -6494,6 +6660,7 @@ static int reload_queue_rules(int reload) while ((rulecat = ast_category_browse(cfg, rulecat))) { if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { AST_LIST_UNLOCK(&rule_lists); + ast_config_destroy(cfg); return AST_MODULE_LOAD_FAILURE; } else { ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); @@ -6517,8 +6684,9 @@ static void queue_set_global_params(struct ast_config *cfg) { const char *general_val = NULL; queue_persistent_members = 0; - if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) + if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) { queue_persistent_members = ast_true(general_val); + } autofill_default = 0; if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) autofill_default = ast_true(general_val); @@ -6533,6 +6701,9 @@ static void queue_set_global_params(struct ast_config *cfg) shared_lastcall = 0; if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) shared_lastcall = ast_true(general_val); + negative_penalty_invalid = 0; + if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) + negative_penalty_invalid = ast_true(general_val); } /*! \brief reload information pertaining to a single member @@ -7087,9 +7258,15 @@ static int manager_queues_show(struct mansession *s, const struct message *m) static int manager_queue_rule_show(struct mansession *s, const struct message *m) { const char *rule = astman_get_header(m, "Rule"); + const char *id = astman_get_header(m, "ActionID"); struct rule_list *rl_iter; struct penalty_rule *pr_iter; + astman_append(s, "Response: Success\r\n"); + if (!ast_strlen_zero(id)) { + astman_append(s, "ActionID: %s\r\n", id); + } + AST_LIST_LOCK(&rule_lists); AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { @@ -7103,6 +7280,10 @@ static int manager_queue_rule_show(struct mansession *s, const struct message *m } AST_LIST_UNLOCK(&rule_lists); + /* + * Two blank lines instead of one because the Response and + * ActionID headers used to not be present. + */ astman_append(s, "\r\n\r\n"); return RESULT_SUCCESS; diff --git a/apps/app_stack.c b/apps/app_stack.c index 29c37a20b..10a1af48d 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -26,7 +26,7 @@ */ /*** MODULEINFO - <use>res_agi</use> + <use type="module">res_agi</use> ***/ #include "asterisk.h" diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 5e342bda0..971e1879d 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -38,8 +38,8 @@ */ /*** MODULEINFO - <use>res_adsi</use> - <use>res_smdi</use> + <use type="module">res_adsi</use> + <use type="module">res_smdi</use> ***/ /*** MAKEOPTS @@ -60,7 +60,7 @@ <depend>imap_tk</depend> <conflict>ODBC_STORAGE</conflict> <conflict>FILE_STORAGE</conflict> - <use>openssl</use> + <use type="external">openssl</use> <defaultenabled>no</defaultenabled> </member> </category> diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 3d1f31326..8864f52bc 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -284,6 +284,14 @@ static int set_bridge_option(const char *name, const char *value, struct bridge_ } } else if (!strcasecmp(name, "record_conference")) { ast_set2_flag(b_profile, ast_true(value), BRIDGE_OPT_RECORD_CONFERENCE); + } else if (!strcasecmp(name, "video_mode")) { + if (!strcasecmp(value, "first_marked")) { + ast_set_flag(b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED); + } else if (!strcasecmp(value, "last_marked")) { + ast_set_flag(b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED); + } else if (!strcasecmp(value, "follow_talker")) { + ast_set_flag(b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER); + } } else if (!strcasecmp(name, "max_members")) { if (sscanf(value, "%30u", &b_profile->max_members) != 1) { return -1; @@ -534,6 +542,7 @@ static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum con case MENU_ACTION_ADMIN_TOGGLE_LOCK: case MENU_ACTION_ADMIN_KICK_LAST: case MENU_ACTION_LEAVE: + case MENU_ACTION_SET_SINGLE_VIDEO_SRC: break; case MENU_ACTION_PLAYBACK: case MENU_ACTION_PLAYBACK_AND_CONTINUE: @@ -649,6 +658,8 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char * res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_KICK_LAST, NULL); } else if (!strcasecmp(action, "leave_conference")) { res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL); + } else if (!strcasecmp(action, "set_as_single_video_src")) { + res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_SET_SINGLE_VIDEO_SRC, NULL); } else if (!strncasecmp(action, "dialplan_exec(", 14)) { ast_copy_string(buf, action, sizeof(buf)); action_args = buf; @@ -983,6 +994,16 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, ast_cli(a->fd,"Max Members: No Limit\n"); } + if (b_profile.flags & BRIDGE_OPT_VIDEO_SRC_LAST_MARKED) { + ast_cli(a->fd, "Video Mode: last_marked\n"); + } else if (b_profile.flags & BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) { + ast_cli(a->fd, "Video Mode: first_marked\n"); + } else if (b_profile.flags & BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER) { + ast_cli(a->fd, "Video Mode: follow_talker\n"); + } else { + ast_cli(a->fd, "Video Mode: no video\n"); + } + ast_cli(a->fd,"sound_join: %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds)); ast_cli(a->fd,"sound_leave: %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds)); ast_cli(a->fd,"sound_only_person: %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds)); @@ -1142,6 +1163,9 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s case MENU_ACTION_LEAVE: ast_cli(a->fd, "leave_conference"); break; + case MENU_ACTION_SET_SINGLE_VIDEO_SRC: + ast_cli(a->fd, "set_as_single_video_src"); + break; } action_num++; } diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index de467b5f7..7a2f6bb07 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -61,6 +61,9 @@ enum user_profile_flags { enum bridge_profile_flags { BRIDGE_OPT_RECORD_CONFERENCE = (1 << 0), /*!< Set if the conference should be recorded */ + BRIDGE_OPT_VIDEO_SRC_LAST_MARKED = (1 << 1), /*!< Set if conference should feed video of last marked user to all participants. */ + BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED = (1 << 2), /*!< Set if conference should feed video of first marked user to all participants. */ + BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER = (1 << 3), /*!< Set if conference set the video feed to follow the loudest talker. */ }; enum conf_menu_action_id { @@ -78,6 +81,7 @@ enum conf_menu_action_id { MENU_ACTION_ADMIN_KICK_LAST, MENU_ACTION_LEAVE, MENU_ACTION_NOOP, + MENU_ACTION_SET_SINGLE_VIDEO_SRC, }; /*! The conference menu action contains both |