);
}
+/* \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.
*
* \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);
} 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 {
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)) {
/* 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;
}
* 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);
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)
}
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;
}
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);
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) {
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);