diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index c675b3cc65..cd4c81424a 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -658,6 +658,41 @@ static void send_leave_event(struct ast_channel *chan, const char *conf_name) ); } +/* \brief Playback the given filename and monitor for any dtmf interrupts. + * + * Use this function to playback sound files to the given channel that can be + * interrupted by dtmf. Note, too this function can be used to playback a sound + * file without allowing interruptions. + * + * \retval -1 failure during playback, 0 on file was fully played, 1 on dtmf interrupt. + */ +static int play_file(struct ast_channel *channel, const char *filename, int allow_dtmf_interrupt) +{ + const char *stop_digits = allow_dtmf_interrupt ? AST_DIGIT_ANY : AST_DIGIT_NONE; + int digit; + + digit = ast_stream_and_wait(channel, filename, stop_digits); + if (digit < 0) { + ast_log(LOG_WARNING, "Failed to playback file '%s' to channel\n", filename); + return -1; + } + + if (digit > 0) { + /* file playback was interrupted by a key press, re-queue it */ + struct ast_frame frame; + + memset(&frame, 0, sizeof(frame)); + frame.frametype = AST_FRAME_DTMF_END; + frame.subclass.integer = digit; + + ast_stopstream(channel); + ast_queue_frame_head(channel, &frame); + return 1; + } + + return 0; +} + /*! * \internal * \brief Complain if the given sound file does not exist. @@ -680,11 +715,13 @@ static int sound_file_exists(const char *filename) * * \param conference_bridge Conference bridge to peek at * \param (OPTIONAL) conference_bridge_user Caller + * \param allow_dtmf_interrupt allow dtmf to interrupt playback * * \note if caller is NULL, the announcment will be sent to all participants in the conference. * \return Returns 0 on success, -1 if the user hung up */ -static int 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, + int allow_dtmf_interrupt) { 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); @@ -696,9 +733,7 @@ static int announce_user_count(struct conference_bridge *conference_bridge, stru } else if (conference_bridge->activeusers == 2) { if (conference_bridge_user) { /* Eep, there is one other person */ - if (ast_stream_and_wait(conference_bridge_user->chan, - only_one, - "")) { + if (play_file(conference_bridge_user->chan, only_one, allow_dtmf_interrupt) < 0) { return -1; } } else { @@ -715,9 +750,7 @@ static int announce_user_count(struct conference_bridge *conference_bridge, stru if (ast_say_number(conference_bridge_user->chan, conference_bridge->activeusers - 1, "", ast_channel_language(conference_bridge_user->chan), NULL)) { return -1; } - if (ast_stream_and_wait(conference_bridge_user->chan, - other_in_party, - "")) { + if (play_file(conference_bridge_user->chan, other_in_party, allow_dtmf_interrupt) < 0) { return -1; } } else if (sound_file_exists(there_are) && sound_file_exists(other_in_party)) { @@ -1241,7 +1274,7 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct /* Announce number of users if need be */ if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) { - if (announce_user_count(conference_bridge, conference_bridge_user)) { + if (announce_user_count(conference_bridge, conference_bridge_user, 0)) { leave_conference(conference_bridge_user); return NULL; } @@ -1256,7 +1289,7 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct * joined the conference yet. */ ast_autoservice_start(conference_bridge_user->chan); - user_count_res = announce_user_count(conference_bridge, NULL); + user_count_res = announce_user_count(conference_bridge, NULL, 0); ast_autoservice_stop(conference_bridge_user->chan); if (user_count_res) { leave_conference(conference_bridge_user); @@ -1772,10 +1805,9 @@ static int action_toggle_mute(struct conference_bridge *conference_bridge, conference_bridge_user->b_profile.name, ast_channel_name(chan)); - return ast_stream_and_wait(chan, (mute ? + return play_file(chan, (mute ? conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) : - conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)), - ""); + conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)), 1) < 0; } static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) @@ -1900,18 +1932,16 @@ static int action_playback_and_continue(struct conference_bridge *conference_bri } static int action_kick_last(struct conference_bridge *conference_bridge, - struct ast_bridge_channel *bridge_channel, struct conference_bridge_user *conference_bridge_user) { struct conference_bridge_user *last_participant = NULL; int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN); if (!isadmin) { - ast_stream_and_wait(bridge_channel->chan, - conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), - ""); + play_file(conference_bridge_user->chan, + conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), 1); ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n", - ast_channel_name(bridge_channel->chan), + ast_channel_name(conference_bridge_user->chan), conference_bridge->name); return -1; } @@ -1920,9 +1950,8 @@ static int action_kick_last(struct conference_bridge *conference_bridge, if (((last_participant = AST_LIST_LAST(&conference_bridge->active_list)) == conference_bridge_user) || (ast_test_flag(&last_participant->u_profile, USER_OPT_ADMIN))) { ao2_unlock(conference_bridge); - ast_stream_and_wait(bridge_channel->chan, - conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), - ""); + play_file(conference_bridge_user->chan, + conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds), 1); } else if (last_participant && !last_participant->kicked) { last_participant->kicked = 1; ast_bridge_remove(conference_bridge->bridge, last_participant->chan); @@ -2000,7 +2029,7 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge, action_toggle_mute_participants(conference_bridge, conference_bridge_user); break; case MENU_ACTION_PARTICIPANT_COUNT: - announce_user_count(conference_bridge, conference_bridge_user); + announce_user_count(conference_bridge, conference_bridge_user, 1); break; case MENU_ACTION_PLAYBACK: if (!stop_prompts) { @@ -2048,15 +2077,13 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge, break; } conference_bridge->locked = (!conference_bridge->locked ? 1 : 0); - res |= ast_stream_and_wait(bridge_channel->chan, + res |= play_file(bridge_channel->chan, (conference_bridge->locked ? conf_get_sound(CONF_SOUND_LOCKED_NOW, conference_bridge_user->b_profile.sounds) : - conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)), - ""); - + conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)), 1) < 0; break; case MENU_ACTION_ADMIN_KICK_LAST: - res |= action_kick_last(conference_bridge, bridge_channel, conference_bridge_user); + res |= action_kick_last(conference_bridge, conference_bridge_user); break; case MENU_ACTION_LEAVE: ao2_lock(conference_bridge);