diff --git a/CHANGES b/CHANGES index 04de88c6e51d10fadf0c010e721e37430fdc1a50..4d106f6bb8b83829321b12ddcf5479194e9b350f 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,15 @@ --- Functionality changes from Asterisk 10 to Asterisk 11 -------------------- ------------------------------------------------------------------------------ +ConfBridge +------------------- + * Added menu action admin_toggle_mute_participants. This will mute / unmute + all non-admin participants on a conference. The confbridge configuration file + also allows for the default sounds played to all conference users when this + occurs to be overriden using sound_participants_unmuted and sound_participants_muted. + * Added menu action participant_count. This will playback the number of current + participants in a conference. + SIP Changes ----------- * Asterisk will no longer substitute CID number for CID name into display diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 42c0a4ce77bfadb11e062356dec0f211e73c7142..f0b80967d67a2c197701d648f685cdf51f481d28 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -340,6 +340,10 @@ const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds return S_OR(custom_sounds->join, "confbridge-join"); case CONF_SOUND_LEAVE: return S_OR(custom_sounds->leave, "confbridge-leave"); + case CONF_SOUND_PARTICIPANTS_MUTED: + return S_OR(custom_sounds->participantsmuted, "conf-now-muted"); + case CONF_SOUND_PARTICIPANTS_UNMUTED: + return S_OR(custom_sounds->participantsunmuted, "conf-now-unmuted"); } return ""; @@ -1548,6 +1552,37 @@ static int action_toggle_mute(struct conference_bridge *conference_bridge, ""); } +static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) +{ + struct conference_bridge_user *participant = NULL; + const char *sound_to_play; + + ao2_lock(conference_bridge); + + /* If already muted, then unmute */ + conference_bridge->muted = conference_bridge->muted ? 0 : 1; + sound_to_play = conf_get_sound((conference_bridge->muted ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED), + conference_bridge_user->b_profile.sounds); + + AST_LIST_TRAVERSE(&conference_bridge->users_list, participant, list) { + if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) { + participant->features.mute = conference_bridge->muted; + } + } + + ao2_unlock(conference_bridge); + + /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */ + ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, ""); + + /* Announce to the group that all participants are muted */ + ast_autoservice_start(conference_bridge_user->chan); + play_sound_helper(conference_bridge, sound_to_play, 0); + ast_autoservice_stop(conference_bridge_user->chan); + + return 0; +} + static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file) { char *file_copy = ast_strdupa(playback_file); @@ -1727,6 +1762,15 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge, conference_bridge_user, bridge_channel->chan); break; + case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS: + if (!isadmin) { + break; + } + action_toggle_mute_participants(conference_bridge, conference_bridge_user); + break; + case MENU_ACTION_PARTICIPANT_COUNT: + announce_user_count(conference_bridge, conference_bridge_user); + break; case MENU_ACTION_PLAYBACK: if (!stop_prompts) { res |= action_playback(bridge_channel, menu_action->data.playback_file); @@ -1944,14 +1988,15 @@ static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]); return CLI_SUCCESS; } - ast_cli(a->fd, "Channel User Profile Bridge Profile Menu\n"); - ast_cli(a->fd, "============================= ================ ================ ================\n"); + ast_cli(a->fd, "Channel User Profile Bridge Profile Menu CallerID\n"); + ast_cli(a->fd, "============================= ================ ================ ================ ================\n"); ao2_lock(bridge); AST_LIST_TRAVERSE(&bridge->users_list, participant, list) { ast_cli(a->fd, "%-29s ", participant->chan->name); ast_cli(a->fd, "%-17s", participant->u_profile.name); ast_cli(a->fd, "%-17s", participant->b_profile.name); ast_cli(a->fd, "%-17s", participant->menu_name); + ast_cli(a->fd, "%-17s", S_COR(participant->chan->caller.id.number.valid, participant->chan->caller.id.number.str, "<unknown>")); ast_cli(a->fd, "\n"); } ao2_unlock(bridge); diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index d11b8258257e8894c22e7942994c2859187ca3da..a2b52bea7fd6dc7d48bcd68ff8fe101d1f640007 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -253,6 +253,10 @@ static int set_sound(const char *sound_name, const char *sound_file, struct brid ast_string_field_set(sounds, join, sound_file); } else if (!strcasecmp(sound_name, "sound_leave")) { ast_string_field_set(sounds, leave, sound_file); + } else if (!strcasecmp(sound_name, "sound_participants_muted")) { + ast_string_field_set(sounds, participantsmuted, sound_file); + } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) { + ast_string_field_set(sounds, participantsunmuted, sound_file); } else { return -1; } @@ -315,7 +319,7 @@ static int set_bridge_option(const char *name, const char *value, struct bridge_ } /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds * structure of a dynamic profile will need to be altered, a completely new sounds structure must be - * create instead of simply holding a reference to the one built by the config file. */ + * created instead of simply holding a reference to the one built by the config file. */ ast_string_field_set(sounds, onlyperson, tmp->sounds->onlyperson); ast_string_field_set(sounds, hasjoin, tmp->sounds->hasjoin); ast_string_field_set(sounds, hasleft, tmp->sounds->hasleft); @@ -332,6 +336,8 @@ static int set_bridge_option(const char *name, const char *value, struct bridge_ ast_string_field_set(sounds, unlockednow, tmp->sounds->unlockednow); ast_string_field_set(sounds, lockednow, tmp->sounds->lockednow); ast_string_field_set(sounds, errormenu, tmp->sounds->errormenu); + ast_string_field_set(sounds, participantsmuted, tmp->sounds->participantsmuted); + ast_string_field_set(sounds, participantsunmuted, tmp->sounds->participantsunmuted); ao2_ref(tmp->sounds, -1); /* sounds struct copied over to it from the template by reference only. */ ao2_ref(oldsounds,-1); /* original sounds struct we don't need anymore */ @@ -540,6 +546,8 @@ static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum con case MENU_ACTION_RESET_LISTENING: case MENU_ACTION_RESET_TALKING: case MENU_ACTION_ADMIN_TOGGLE_LOCK: + case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS: + case MENU_ACTION_PARTICIPANT_COUNT: case MENU_ACTION_ADMIN_KICK_LAST: case MENU_ACTION_LEAVE: case MENU_ACTION_SET_SINGLE_VIDEO_SRC: @@ -655,6 +663,10 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char * res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DECREASE_TALKING, NULL); } else if (!strcasecmp(action, "admin_toggle_conference_lock")) { res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_LOCK, NULL); + } else if (!strcasecmp(action, "admin_toggle_mute_participants")) { + res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS, NULL); + } else if (!strcasecmp(action, "participant_count")) { + res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PARTICIPANT_COUNT, NULL); } else if (!strcasecmp(action, "admin_kick_last")) { res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_KICK_LAST, NULL); } else if (!strcasecmp(action, "leave_conference")) { @@ -1025,6 +1037,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, ast_cli(a->fd,"sound_unlocked_now: %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds)); ast_cli(a->fd,"sound_lockednow: %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds)); ast_cli(a->fd,"sound_error_menu: %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds)); + ast_cli(a->fd,"sound_participants_muted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds)); + ast_cli(a->fd,"sound_participants_unmuted: %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds)); ast_cli(a->fd,"\n"); conf_bridge_profile_destroy(&b_profile); @@ -1160,6 +1174,12 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s case MENU_ACTION_ADMIN_TOGGLE_LOCK: ast_cli(a->fd, "admin_toggle_conference_lock"); break; + case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS: + ast_cli(a->fd, "admin_toggle_mute_participants"); + break; + case MENU_ACTION_PARTICIPANT_COUNT: + ast_cli(a->fd, "participant_count"); + break; case MENU_ACTION_ADMIN_KICK_LAST: ast_cli(a->fd, "admin_kick_last"); break; @@ -1360,8 +1380,9 @@ const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, conf_bridge_profile_copy(result, &b_data->b_profile); return result; } + } else { + ast_channel_unlock(chan); } - ast_channel_unlock(chan); } if (ast_strlen_zero(bridge_profile_name)) { bridge_profile_name = DEFAULT_BRIDGE_PROFILE; diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index ab4a8c4b0acaf3f7448f2d4c7cffd7031dc6991e..5337e22aa2a8bcafbfbf0aa4634e9a3b08bbd9d7 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -83,6 +83,8 @@ enum conf_menu_action_id { MENU_ACTION_NOOP, MENU_ACTION_SET_SINGLE_VIDEO_SRC, MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC, + MENU_ACTION_PARTICIPANT_COUNT, + MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS, }; /*! The conference menu action contains both @@ -156,6 +158,8 @@ enum conf_sounds { CONF_SOUND_ERROR_MENU, CONF_SOUND_JOIN, CONF_SOUND_LEAVE, + CONF_SOUND_PARTICIPANTS_MUTED, + CONF_SOUND_PARTICIPANTS_UNMUTED, }; struct bridge_profile_sounds { @@ -180,6 +184,8 @@ struct bridge_profile_sounds { AST_STRING_FIELD(errormenu); AST_STRING_FIELD(leave); AST_STRING_FIELD(join); + AST_STRING_FIELD(participantsmuted); + AST_STRING_FIELD(participantsunmuted); ); }; @@ -202,6 +208,7 @@ struct conference_bridge { unsigned int users; /*!< Number of users present */ unsigned int markedusers; /*!< Number of marked users present */ unsigned int locked:1; /*!< Is this conference bridge locked? */ + unsigned int muted:1; /*!< Is this conference bridge muted? */ struct ast_channel *playback_chan; /*!< Channel used for playback into the conference bridge */ struct ast_channel *record_chan; /*!< Channel used for recording the conference */ pthread_t record_thread; /*!< The thread the recording chan lives in */ diff --git a/configs/confbridge.conf.sample b/configs/confbridge.conf.sample index 31060ecab27c37de5f93dad2de8bd0611ab94540..d113825d2eb20882b31ca0633c0c035ee3fb9692 100644 --- a/configs/confbridge.conf.sample +++ b/configs/confbridge.conf.sample @@ -306,6 +306,15 @@ type=bridge ; to whatever operation the video_mode option is set to ; upon release of the video src. +; admin_toggle_mute_participants ; This action allows an administrator to toggle the mute + ; state for all non-admins within a conference. All + ; admin users are unaffected by this option. Note that all + ; users, regardless of their admin status, are notified + ; that the conference is muted. + +; participant_count ; This action plays back the number of participants currently + ; in a conference + [sample_user_menu] type=menu *=playback_and_continue(conf-usermenu) diff --git a/contrib/realtime/mysql/sipfriends.sql b/contrib/realtime/mysql/sipfriends.sql new file mode 100644 index 0000000000000000000000000000000000000000..07cd8788aaa5cf8da6b4f914830cd39c60d06d81 --- /dev/null +++ b/contrib/realtime/mysql/sipfriends.sql @@ -0,0 +1,97 @@ +# +# Table structure for table `sipfriends` +# + +CREATE TABLE IF NOT EXISTS `sipfriends` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(10) NOT NULL, + `ipaddr` varchar(15) DEFAULT NULL, + `port` int(5) DEFAULT NULL, + `regseconds` int(11) DEFAULT NULL, + `defaultuser` varchar(10) DEFAULT NULL, + `fullcontact` varchar(35) DEFAULT NULL, + `regserver` varchar(20) DEFAULT NULL, + `useragent` varchar(20) DEFAULT NULL, + `lastms` int(11) DEFAULT NULL, + `host` varchar(40) DEFAULT NULL, + `type` enum('friend','user','peer') DEFAULT NULL, + `context` varchar(40) DEFAULT NULL, + `permit` varchar(40) DEFAULT NULL, + `deny` varchar(40) DEFAULT NULL, + `secret` varchar(40) DEFAULT NULL, + `md5secret` varchar(40) DEFAULT NULL, + `remotesecret` varchar(40) DEFAULT NULL, + `transport` enum('udp','tcp','udp,tcp','tcp,udp') DEFAULT NULL, + `dtmfmode` enum('rfc2833','info','shortinfo','inband','auto') DEFAULT NULL, + `directmedia` enum('yes','no','nonat','update') DEFAULT NULL, + `nat` enum('yes','no','never','route') DEFAULT NULL, + `callgroup` varchar(40) DEFAULT NULL, + `pickupgroup` varchar(40) DEFAULT NULL, + `language` varchar(40) DEFAULT NULL, + `allow` varchar(200) DEFAULT NULL, + `insecure` varchar(40) DEFAULT NULL, + `trustrpid` enum('yes','no') DEFAULT NULL, + `progressinband` enum('yes','no','never') DEFAULT NULL, + `promiscredir` enum('yes','no') DEFAULT NULL, + `useclientcode` enum('yes','no') DEFAULT NULL, + `accountcode` varchar(40) DEFAULT NULL, + `setvar` varchar(40) DEFAULT NULL, + `callerid` varchar(40) DEFAULT NULL, + `amaflags` varchar(40) DEFAULT NULL, + `callcounter` enum('yes','no') DEFAULT NULL, + `busylevel` int(11) DEFAULT NULL, + `allowoverlap` enum('yes','no') DEFAULT NULL, + `allowsubscribe` enum('yes','no') DEFAULT NULL, + `videosupport` enum('yes','no') DEFAULT NULL, + `maxcallbitrate` int(11) DEFAULT NULL, + `rfc2833compensate` enum('yes','no') DEFAULT NULL, + `mailbox` varchar(40) DEFAULT NULL, + `session-timers` enum('accept','refuse','originate') DEFAULT NULL, + `session-expires` int(11) DEFAULT NULL, + `session-minse` int(11) DEFAULT NULL, + `session-refresher` enum('uac','uas') DEFAULT NULL, + `t38pt_usertpsource` varchar(40) DEFAULT NULL, + `regexten` varchar(40) DEFAULT NULL, + `fromdomain` varchar(40) DEFAULT NULL, + `fromuser` varchar(40) DEFAULT NULL, + `qualify` varchar(40) DEFAULT NULL, + `defaultip` varchar(40) DEFAULT NULL, + `rtptimeout` int(11) DEFAULT NULL, + `rtpholdtimeout` int(11) DEFAULT NULL, + `sendrpid` enum('yes','no') DEFAULT NULL, + `outboundproxy` varchar(40) DEFAULT NULL, + `callbackextension` varchar(40) DEFAULT NULL, + `registertrying` enum('yes','no') DEFAULT NULL, + `timert1` int(11) DEFAULT NULL, + `timerb` int(11) DEFAULT NULL, + `qualifyfreq` int(11) DEFAULT NULL, + `constantssrc` enum('yes','no') DEFAULT NULL, + `contactpermit` varchar(40) DEFAULT NULL, + `contactdeny` varchar(40) DEFAULT NULL, + `usereqphone` enum('yes','no') DEFAULT NULL, + `textsupport` enum('yes','no') DEFAULT NULL, + `faxdetect` enum('yes','no') DEFAULT NULL, + `buggymwi` enum('yes','no') DEFAULT NULL, + `auth` varchar(40) DEFAULT NULL, + `fullname` varchar(40) DEFAULT NULL, + `trunkname` varchar(40) DEFAULT NULL, + `cid_number` varchar(40) DEFAULT NULL, + `callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib') DEFAULT NULL, + `mohinterpret` varchar(40) DEFAULT NULL, + `mohsuggest` varchar(40) DEFAULT NULL, + `parkinglot` varchar(40) DEFAULT NULL, + `hasvoicemail` enum('yes','no') DEFAULT NULL, + `subscribemwi` enum('yes','no') DEFAULT NULL, + `vmexten` varchar(40) DEFAULT NULL, + `autoframing` enum('yes','no') DEFAULT NULL, + `rtpkeepalive` int(11) DEFAULT NULL, + `call-limit` int(11) DEFAULT NULL, + `g726nonstandard` enum('yes','no') DEFAULT NULL, + `ignoresdpversion` enum('yes','no') DEFAULT NULL, + `allowtransfer` enum('yes','no') DEFAULT NULL, + `dynamic` enum('yes','no') DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`), + KEY `ipaddr` (`ipaddr`,`port`), + KEY `host` (`host`,`port`) +) ENGINE=MyISAM;