Index: apps/app_confbridge.c =================================================================== --- apps/app_confbridge.c (revision 359977) +++ apps/app_confbridge.c (working copy) @@ -161,6 +161,19 @@ ConfbridgeListRoomsComplete. + + + Plays a file back to a bridge or participant. + + + + + + + + + + Mute a Confbridge user. @@ -2092,6 +2105,120 @@ return res; } +struct action_confbridgeplayfile_specifier { + struct conference_bridge_user *participant; + struct conference_bridge *bridge; + char file[256]; +}; + +static void *action_confbridgeplayfile_thread(void *obj) +{ + struct action_confbridgeplayfile_specifier *specifier = (struct action_confbridgeplayfile_specifier *)obj; + + if (specifier->participant) { + if (!ast_bridge_suspend(specifier->bridge->bridge, specifier->participant->chan)) { + if(specifier->participant->playing_moh){ + ast_moh_stop(specifier->participant->chan); + } + ast_stream_and_wait(specifier->participant->chan, (const char *)&specifier->file, ""); + if(specifier->participant->playing_moh){ + ast_moh_start(specifier->participant->chan, specifier->participant->u_profile.moh_class, NULL); + } + ast_bridge_unsuspend(specifier->bridge->bridge, specifier->participant->chan); + } + } else { + play_sound_helper(specifier->bridge, (const char *)&specifier->file, 0); + } + free(specifier); + return NULL; +} + +static const char *action_confbridgeplayfile_helper(const char *conference, const char *channel, const char *file) +{ + struct conference_bridge_user *participant = NULL; + struct conference_bridge_user *tmp_participant = NULL; + struct conference_bridge *bridge = NULL; + struct conference_bridge tmp; + struct action_confbridgeplayfile_specifier *specifier; + pthread_t handler_thread; + + if (ast_strlen_zero(conference)) { + return "No conference name provided."; + } + if (!ao2_container_count(conference_bridges)) { + return "No active conferences."; + } + + ast_copy_string(tmp.name, conference, sizeof(tmp.name)); + bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER); + if (!bridge) { + return "No conference found with that name."; + } + + if (channel == NULL || ast_strlen_zero(channel)) { + /* Do nothing; there is no participant */ + } else { + ao2_lock(bridge); + AST_LIST_TRAVERSE(&bridge->users_list, tmp_participant, list) { + if (!strncmp(channel, ast_channel_name(tmp_participant->chan), strlen(channel))) { + participant = tmp_participant; + break; + } + } + ao2_unlock(bridge); + if (!participant) { + return "No such channel found in conference."; + } + } + + specifier = malloc(sizeof(struct action_confbridgeplayfile_specifier)); /* Freed on failure or end of thread-function */ + strcpy(specifier->file, file); + specifier->bridge = bridge; + specifier->participant = participant; + if (ast_pthread_create_background(&handler_thread, NULL, action_confbridgeplayfile_thread, (void *)specifier)) { + if (ast_strlen_zero(channel)) { + ast_log(LOG_WARNING, "Failed to begin playback in conference %s\n", conference); + } else { + ast_log(LOG_WARNING, "Failed to begin playback to %s in conference %s\n", channel, conference); + } + free(specifier); + return "Unable to process request."; + } + + return NULL; +} + +static char *handle_cli_confbridge_playfile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + const char *result; + + switch (cmd) { + case CLI_INIT: + e->command = "confbridge playfile"; + e->usage = + "Usage: confbridge playfile [channel] \n"; + return NULL; + case CLI_GENERATE: + if (a->pos == 2) { + return complete_confbridge_name(a->line, a->word, a->pos, a->n); + } + return NULL; + } + if (a->argc == 4) { + result = action_confbridgeplayfile_helper(a->argv[2], NULL, a->argv[3]); + } else if (a->argc == 5) { + result = action_confbridgeplayfile_helper(a->argv[2], a->argv[3], a->argv[4]); + } else { + return CLI_SHOWUSAGE; + } + if (result) { + ast_cli(a->fd, "%s\n", result); + } else { + ast_cli(a->fd, "File playback processed for conference %s.\n", a->argv[2]); + } + return CLI_SUCCESS; +} + static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a) { int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]); @@ -2294,6 +2421,7 @@ static struct ast_cli_entry cli_confbridge[] = { AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."), AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."), + AST_CLI_DEFINE(handle_cli_confbridge_playfile, "Play an arbitrary file."), AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."), AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."), AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."), @@ -2430,6 +2558,21 @@ return 0; } +static int action_confbridgeplayfile(struct mansession *s, const struct message *m) +{ + const char *conference = astman_get_header(m, "Conference"); + const char *channel = astman_get_header(m, "Channel"); + const char *file = astman_get_header(m, "File"); + + const char *response = action_confbridgeplayfile_helper(conference, channel, file); + if (response) { + astman_send_error(s, m, "No Conference by that name found."); + } else { + astman_send_ack(s, m, "Playback request processed."); + } + return 0; +} + static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute) { const char *conference = astman_get_header(m, "Conference"); @@ -2754,6 +2897,7 @@ res |= ast_manager_unregister("ConfbridgeList"); res |= ast_manager_unregister("ConfbridgeListRooms"); + res |= ast_manager_unregister("ConfbridgePlayFile"); res |= ast_manager_unregister("ConfbridgeMute"); res |= ast_manager_unregister("ConfbridgeUnmute"); res |= ast_manager_unregister("ConfbridgeKick"); @@ -2795,6 +2939,7 @@ res |= ast_cli_register_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry)); res |= ast_manager_register_xml("ConfbridgeList", EVENT_FLAG_REPORTING, action_confbridgelist); res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms); + res |= ast_manager_register_xml("ConfbridgePlayFile", EVENT_FLAG_CALL, action_confbridgeplayfile); res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute); res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute); res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);