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);