This patch is derived from the difference between appconference-2.0.1 from http://appconference.sourceforge.net/ and the version included in http://download.fedora.redhat.com/pub/fedora/linux/development/source/SRPMS/asterisk-1.6.0-0.4.beta5.fc9.src.rpm Index: Flags.txt --- Flags.txt.orig 2008-02-26 17:05:57 +0100 +++ Flags.txt 2008-03-19 09:18:57 +0100 @@ -21,6 +21,10 @@ Moderator/video switch options: 'M' : member is a "moderator". When a moderator quits, all members are kicked and the conference is disabled. 'S' : member accepts VAD controlled video switching. Do not use with 'X'. +'z' : member can "linger". When the member is currently transmitting video and becomes silent and nobody else is speaking, we stay on it. +'o' : enable special behavior when in 1 and 2 member situation (one on one video). The conference observes the 'o' status of the last + member to join it +'F' : force switch mode: if the member is talking, force a switch to it even when there is no video Miscellaneous: 't' : member accepts text based control messages. The messages are described in a separate document Index: Makefile --- Makefile.orig 2008-02-26 17:05:57 +0100 +++ Makefile 2008-03-19 09:18:57 +0100 @@ -18,11 +18,11 @@ # INSTALL_PREFIX := -INSTALL_MODULES_DIR := $(INSTALL_PREFIX)/usr/lib/asterisk/modules +INSTALL_MODULES_DIR := $(INSTALL_PREFIX)/lib/asterisk/modules -ASTERISK_INCLUDE_DIR ?= ../asterisk/include +ASTERISK_INCLUDE_DIR ?= $(INSTALL_PREFIX)/include -REVISION = $(shell svnversion -n .) +REVISION = 2.0.1 # turn app_conference debugging on or off ( 0 == OFF, 1 == ON ) APP_CONFERENCE_DEBUG ?= 0 Index: app_conference.c --- app_conference.c.orig 2008-02-26 17:05:57 +0100 +++ app_conference.c 2008-03-19 09:18:57 +0100 @@ -27,14 +27,7 @@ #include "asterisk.h" -// SVN revision number, provided by make -#ifndef REVISION -#define REVISION "unknown" -#endif - -static char *revision = REVISION; - -ASTERISK_FILE_VERSION(__FILE__, REVISION) +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $") #include "app_conference.h" #include "common.h" @@ -84,7 +77,7 @@ static int load_module( void ) { - ast_log( LOG_NOTICE, "Loading app_conference module, revision=%s\n", revision) ; + ast_log( LOG_NOTICE, "Loading app_conference module\n") ; init_conference() ; Index: app_conference.h --- app_conference.h.orig 2008-02-26 17:05:57 +0100 +++ app_conference.h 2008-03-19 09:18:57 +0100 @@ -31,6 +31,7 @@ #ifndef _ASTERISK_CONF_H #define _ASTERISK_CONF_H +#include "asterisk.h" /* standard includes */ #include @@ -40,27 +41,27 @@ #include #include - #include /* asterisk includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include +#include "asterisk/channel.h" +#include "asterisk/utils.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/logger.h" +#include "asterisk/lock.h" +#include "asterisk/frame.h" +#include "asterisk/manager.h" +#include "asterisk/dsp.h" +#include "asterisk/translate.h" +#include "asterisk/channel.h" +#include "asterisk/file.h" +//#include "asterisk/channel_pvt.h" +#include "asterisk/cli.h" #if (SILDET == 2) -#include "libspeex/speex_preprocess.h" +#include "speex_preprocess.h" #endif // @@ -226,6 +227,10 @@ // Amount of audio required before we decide somebody started talking #define AST_CONF_VIDEO_START_TIMEOUT 2000 +// Amount of time we wait for a video frame until we decide that +// the member has stopped broadcasting video +#define AST_CONF_VIDEO_STOP_BROADCAST_TIMEOUT 200 + // // Text frame control protocol // Index: cli.c --- cli.c.orig 2008-02-26 17:05:57 +0100 +++ cli.c 2008-03-19 09:27:50 +0100 @@ -28,125 +28,121 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "asterisk/autoconfig.h" -#include "cli.h" +#include "asterisk.h" -static char conference_restart_usage[] = - "usage: conference restart\n" - " kick all users in all conferences\n" -; - -static struct ast_cli_entry cli_restart = { - { "conference", "restart", NULL }, - conference_restart, - "restart a conference", - conference_restart_usage -} ; +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $") +#include "asterisk/autoconfig.h" +#include "cli.h" -int conference_restart( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 2 ) - return RESULT_SHOWUSAGE ; + switch ( cmd ) { + case CLI_INIT: + e->command = "conference restart"; + e->usage = "usage: conference restart\n" + " restart a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + if ( a->argc < 2 ) + return CLI_SHOWUSAGE; + kick_all(); - return RESULT_SUCCESS ; + + return CLI_SUCCESS; } +static char *handle_cli_app_conference_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ -// -// debug functions -// - -static char conference_debug_usage[] = - "usage: conference debug [ on | off ]\n" - " enable debugging for a conference\n" -; - -static struct ast_cli_entry cli_debug = { - { "conference", "debug", NULL }, - conference_debug, - "enable debugging for a conference", - conference_debug_usage -} ; - + switch ( cmd ) { + case CLI_INIT: + e->command = "conference debug"; + e->usage = "usage: conference debug [ on | off ]\n" + " enable debugging for a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } -int conference_debug( int fd, int argc, char *argv[] ) -{ - if ( argc < 3 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 3) + return CLI_SHOWUSAGE; // get the conference name - const char* name = argv[2] ; + const char* name = a->argv[2] ; // get the new state int state = 0 ; - if ( argc == 3 ) + if ( a->argc == 3 ) { // no state specified, so toggle it state = -1 ; } else { - if ( strncasecmp( argv[3], "on", 4 ) == 0 ) + if ( strncasecmp( a->argv[3], "on", 4 ) == 0 ) state = 1 ; - else if ( strncasecmp( argv[3], "off", 3 ) == 0 ) + else if ( strncasecmp( a->argv[3], "off", 3 ) == 0 ) state = 0 ; else - return RESULT_SHOWUSAGE ; + return CLI_SHOWUSAGE ; } int new_state = set_conference_debugging( name, state ) ; if ( new_state == 1 ) { - ast_cli( fd, "enabled conference debugging, name => %s, new_state => %d\n", - name, new_state ) ; + ast_cli( a->fd, "enabled conference debugging, name => %s, new_state => %d\n", + name, new_state ) ; } else if ( new_state == 0 ) { - ast_cli( fd, "disabled conference debugging, name => %s, new_state => %d\n", + ast_cli( a->fd, "disabled conference debugging, name => %s, new_state => %d\n", name, new_state ) ; } else { // error setting state - ast_cli( fd, "\nunable to set debugging state, name => %s\n\n", name ) ; + ast_cli( a->fd, "\nunable to set debugging state, name => %s\n\n", name ) ; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -// -// stats functions -// - -static char conference_show_stats_usage[] = - "usage: conference show stats\n" - " display stats for active conferences.\n" -; - -static struct ast_cli_entry cli_show_stats = { - { "conference", "show", "stats", NULL }, - conference_show_stats, - "show conference stats", - conference_show_stats_usage -} ; +static char *conference_show_stats_name( int fd, const char* name ) +{ + // not implemented yet + return CLI_SUCCESS ; +} -int conference_show_stats( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 3 ) - return RESULT_SHOWUSAGE ; + + switch ( cmd ) { + case CLI_INIT: + e->command = "conference show stats"; + e->usage = "usage: conference show stats\n" + " display stats for active conferences.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 3 ) + return CLI_SHOWUSAGE ; // get count of active conferences int count = get_conference_count() ; - ast_cli( fd, "\n\nCONFERENCE STATS, ACTIVE( %d )\n\n", count ) ; + ast_cli( a->fd, "\n\nCONFERENCE STATS, ACTIVE( %d )\n\n", count ) ; // if zero, go no further if ( count <= 0 ) - return RESULT_SUCCESS ; + return CLI_SUCCESS ; // // get the conference stats @@ -161,8 +157,8 @@ // make sure we were able to fetch some if ( count <= 0 ) { - ast_cli( fd, "!!! error fetching conference stats, available => %d !!!\n", count ) ; - return RESULT_SUCCESS ; + ast_cli( a->fd, "!!! error fetching conference stats, available => %d !!!\n", count ) ; + return CLI_SUCCESS ; } // @@ -170,8 +166,8 @@ // // output header - ast_cli( fd, "%-20.20s %-40.40s\n", "Name", "Stats") ; - ast_cli( fd, "%-20.20s %-40.40s\n", "----", "-----") ; + ast_cli( a->fd, "%-20.20s %-40.40s\n", "Name", "Stats") ; + ast_cli( a->fd, "%-20.20s %-40.40s\n", "----", "-----") ; ast_conference_stats* s = NULL ; @@ -182,1008 +178,931 @@ s = &(stats[i]) ; // output this conferences stats - ast_cli( fd, "%-20.20s\n", (char*)( &(s->name) )) ; + ast_cli( a->fd, "%-20.20s\n", (char*)( &(s->name) )) ; } - ast_cli( fd, "\n" ) ; + ast_cli( a->fd, "\n" ) ; // // drill down to specific stats // - if ( argc == 4 ) + if ( a->argc == 4 ) { // show stats for a particular conference - conference_show_stats_name( fd, argv[3] ) ; + conference_show_stats_name( a->fd, a->argv[3] ) ; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -int conference_show_stats_name( int fd, const char* name ) +static char *handle_cli_app_conference_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - // not implemented yet - return RESULT_SUCCESS ; -} - -static char conference_list_usage[] = - "usage: conference list {}\n" - " list members of a conference\n" -; - -static struct ast_cli_entry cli_list = { - { "conference", "list", NULL }, - conference_list, - "list members of a conference", - conference_list_usage -} ; - - + switch ( cmd ) { + case CLI_INIT: + e->command = "conference list"; + e->usage = "usage: conference list {}\n" + " list members of a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } -int conference_list( int fd, int argc, char *argv[] ) -{ int index; - if ( argc < 2 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 2 ) + return CLI_SHOWUSAGE ; - if (argc >= 3) + if (a->argc >= 3) { - for (index = 2; index < argc; index++) + for (index = 2; index < a->argc; index++) { // get the conference name - const char* name = argv[index] ; - show_conference_list( fd, name ); + const char* name = a->argv[index] ; + show_conference_list( a->fd, name ); } } else { - show_conference_stats(fd); + show_conference_stats(a->fd); } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -int conference_kick( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 4 ) - return RESULT_SHOWUSAGE ; + switch ( cmd ) { + case CLI_INIT: + e->command = "conference kick"; + e->usage = "usage: conference kick \n" + " kick member from conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 4 ) + return CLI_SHOWUSAGE ; // get the conference name - const char* name = argv[2] ; + const char* name = a->argv[2] ; int member_id; - sscanf(argv[3], "%d", &member_id); + sscanf(a->argv[3], "%d", &member_id); int res = kick_member( name, member_id ); - if (res) ast_cli( fd, "User #: %d kicked\n", member_id) ; + if (res) ast_cli( a->fd, "User #: %d kicked\n", member_id) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_kick_usage[] = - "usage: conference kick \n" - " kick member from conference \n" -; - -static struct ast_cli_entry cli_kick = { - { "conference", "kick", NULL }, - conference_kick, - "kick member from a conference", - conference_kick_usage -} ; - -int conference_kickchannel( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_kickchannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 4 ) - return RESULT_SHOWUSAGE ; + switch ( cmd ) { + case CLI_INIT: + e->command = "conference kickchannel"; + e->usage = "usage: conference kickchannel \n" + " kick channel from conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 4 ) + return CLI_SHOWUSAGE ; - const char *name = argv[2] ; - const char *channel = argv[3]; + const char *name = a->argv[2] ; + const char *channel = a->argv[3]; int res = kick_channel( name, channel ); if ( !res ) { - ast_cli( fd, "Cannot kick channel %s in conference %s\n", channel, name); - return RESULT_FAILURE; + ast_cli( a->fd, "Cannot kick channel %s in conference %s\n", channel, name); + return CLI_FAILURE; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_kickchannel_usage[] = - "usage: conference kickchannel \n" - " kick channel from conference\n" -; +static char *handle_cli_app_conference_exit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch ( cmd ) { + case CLI_INIT: + e->command = "conference exit"; + e->usage = "usage: conference exit \n" + " exit channel from any conference where it in\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 3 ) + return CLI_SHOWUSAGE ; -static struct ast_cli_entry cli_kickchannel = { - { "conference", "kickchannel", NULL }, - conference_kickchannel, - "kick channel from conference", - conference_kickchannel_usage -} ; + const char *channel = a->argv[2]; + + struct ast_conf_member *member = find_member(channel, 1); + if(!member) + { + ast_cli( a->fd, "Member %s not found\n", channel); + return CLI_FAILURE; + } + const char * name = member->conf_name; + int res = kick_channel( name, channel ); + + if ( !res ) + { + ast_cli( a->fd, "Cannot exit channel %s from conference %s\n", channel, name); + ast_mutex_unlock(&member->lock); + return CLI_FAILURE; + } -int conference_mute( int fd, int argc, char *argv[] ) + ast_mutex_unlock( &member->lock ) ; + return CLI_SUCCESS ; +} + +static char *handle_cli_app_conference_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 4 ) - return RESULT_SHOWUSAGE ; + switch ( cmd ) { + case CLI_INIT: + e->command = "conference mute"; + e->usage = "usage: conference mute \n" + " mute member in a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 4 ) + return CLI_SHOWUSAGE ; // get the conference name - const char* name = argv[2] ; + const char* name = a->argv[2] ; int member_id; - sscanf(argv[3], "%d", &member_id); + sscanf(a->argv[3], "%d", &member_id); int res = mute_member( name, member_id ); - if (res) ast_cli( fd, "User #: %d muted\n", member_id) ; + if (res) ast_cli( a->fd, "User #: %d muted\n", member_id) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_mute_usage[] = - "usage: conference mute \n" - " mute member in a conference\n" -; - -static struct ast_cli_entry cli_mute = { - { "conference", "mute", NULL }, - conference_mute, - "mute member in a conference", - conference_mute_usage -} ; - -int conference_mutechannel( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_mutechannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference mutechannel"; + e->usage = "usage: conference mutechannel \n" + " mute channel in a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + struct ast_conf_member *member; char *channel; - if ( argc < 3 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 3 ) + return CLI_SHOWUSAGE ; - channel = argv[2]; + channel = a->argv[2]; member = find_member(channel, 1); if(!member) { - ast_cli(fd, "Member %s not found\n", channel); - return RESULT_FAILURE; + ast_cli( a->fd, "Member %s not found\n", channel); + return CLI_FAILURE; } member->mute_audio = 1; ast_mutex_unlock( &member->lock ) ; - ast_cli( fd, "Channel #: %s muted\n", argv[2]) ; + ast_cli( a->fd, "Channel #: %s muted\n", a->argv[2]) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_mutechannel_usage[] = - "usage: conference mutechannel \n" - " mute channel in a conference\n" -; - -static struct ast_cli_entry cli_mutechannel = { - { "conference", "mutechannel", NULL }, - conference_mutechannel, - "mute channel in a conference", - conference_mutechannel_usage -} ; - -int conference_viewstream( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_viewstream(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference viewstream"; + e->usage = "usage: conference viewstream \n" + " member will receive video stream \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + int res; - if ( argc < 5 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE ; // get the conference name - const char* switch_name = argv[2] ; + const char* switch_name = a->argv[2] ; int member_id, viewstream_id; - sscanf(argv[3], "%d", &member_id); - sscanf(argv[4], "%d", &viewstream_id); + sscanf(a->argv[3], "%d", &member_id); + sscanf(a->argv[4], "%d", &viewstream_id); res = viewstream_switch( switch_name, member_id, viewstream_id ); - if (res) ast_cli( fd, "User #: %d viewing %d\n", member_id, viewstream_id) ; + if (res) ast_cli( a->fd, "User #: %d viewing %d\n", member_id, viewstream_id) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_viewstream_usage[] = - "usage: conference viewstream \n" - " member will receive video stream \n" -; - -static struct ast_cli_entry cli_viewstream = { - { "conference", "viewstream", NULL }, - conference_viewstream, - "switch view in a conference", - conference_viewstream_usage -} ; - -int conference_viewchannel( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_viewchannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference viewchannel"; + e->usage = "usage: conference viewchannel \n" + " channel will receive video stream \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + int res; - if ( argc < 5 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE ; // get the conference name - const char* switch_name = argv[2] ; + const char* switch_name = a->argv[2] ; - res = viewchannel_switch( switch_name, argv[3], argv[4] ); + res = viewchannel_switch( switch_name, a->argv[3], a->argv[4] ); - if (res) ast_cli( fd, "Channel #: %s viewing %s\n", argv[3], argv[4]) ; + if (res) ast_cli( a->fd, "Channel #: %s viewing %s\n", a->argv[3], a->argv[4]) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_viewchannel_usage[] = - "usage: conference viewchannel \n" - " channel will receive video stream \n" -; - -static struct ast_cli_entry cli_viewchannel = { - { "conference", "viewchannel", NULL }, - conference_viewchannel, - "switch channel in a conference", - conference_viewchannel_usage -} ; - -int conference_unmute( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - if ( argc < 4 ) - return RESULT_SHOWUSAGE ; + switch ( cmd ) { + case CLI_INIT: + e->command = "conference unmute"; + e->usage = "usage: conference unmute \n" + " unmute member in a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if ( a->argc < 4 ) + return CLI_SHOWUSAGE ; // get the conference name - const char* name = argv[2] ; + const char* name = a->argv[2] ; int member_id; - sscanf(argv[3], "%d", &member_id); + sscanf(a->argv[3], "%d", &member_id); int res = unmute_member( name, member_id ); - if (res) ast_cli( fd, "User #: %d unmuted\n", member_id) ; + if (res) ast_cli( a->fd, "User #: %d unmuted\n", member_id) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_unmute_usage[] = - "usage: conference unmute \n" - " unmute member in a conference\n" -; - -static struct ast_cli_entry cli_unmute = { - { "conference", "unmute", NULL }, - conference_unmute, - "unmute member in a conference", - conference_unmute_usage -} ; - -int conference_unmutechannel( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_unmutechannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference unmutechannel"; + e->usage = "usage: conference unmutechannel \n" + " unmute channel in a conference\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + struct ast_conf_member *member; char *channel; - if ( argc < 3 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 3 ) + return CLI_SHOWUSAGE ; - channel = argv[2]; + channel = a->argv[2]; member = find_member(channel, 1); if(!member) { - ast_cli(fd, "Member %s not found\n", channel); - return RESULT_FAILURE; + ast_cli( a->fd, "Member %s not found\n", channel); + return CLI_FAILURE; } member->mute_audio = 0; ast_mutex_unlock( &member->lock ) ; - ast_cli( fd, "Channel #: %s unmuted\n", argv[2]) ; + ast_cli( a->fd, "Channel #: %s unmuted\n", a->argv[2]) ; - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -static char conference_unmutechannel_usage[] = - "usage: conference unmutechannel \n" - " unmute channel in a conference\n" -; - -static struct ast_cli_entry cli_unmutechannel = { - { "conference", "unmutechannel", NULL }, - conference_unmutechannel, - "unmute channel in a conference", - conference_unmutechannel_usage -} ; - -// -// play sound -// -static char conference_play_sound_usage[] = - "usage: conference play sound [mute]\n" - " play sound to conference member .\n" - " If mute is specified, all other audio is muted while the sound is played back.\n" -; - -static struct ast_cli_entry cli_play_sound = { - { "conference", "play", "sound", NULL }, - conference_play_sound, - "play a sound to a conference member", - conference_play_sound_usage -} ; - -int conference_play_sound( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_play_sound(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference play sound"; + e->usage = "usage: conference play sound [mute]\n" + " play sound to conference member .\n" + " If mute is specified, all other audio is muted while the sound is played back.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + char *channel, *file; int mute = 0; - if ( argc < 5 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE ; - channel = argv[3]; - file = argv[4]; + channel = a->argv[3]; + file = a->argv[4]; - if(argc > 5 && !strcmp(argv[5], "mute")) + if(a->argc > 5 && !strcmp(a->argv[5], "mute")) mute = 1; - int res = play_sound_channel(fd, channel, file, mute); + int res = play_sound_channel(a->fd, channel, file, mute); if ( !res ) { - ast_cli(fd, "Sound playback failed failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Sound playback failed failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -// -// stop sounds -// - -static char conference_stop_sounds_usage[] = - "usage: conference stop sounds \n" - " stop sounds for conference member .\n" -; - -static struct ast_cli_entry cli_stop_sounds = { - { "conference", "stop", "sounds", NULL }, - conference_stop_sounds, - "stop sounds for a conference member", - conference_stop_sounds_usage -} ; - -int conference_stop_sounds( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_stop_sounds(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference play sound"; + e->usage = "usage: conference stop sounds \n" + " stop sounds for conference member .\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + char *channel; - if ( argc < 4 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE ; - channel = argv[3]; + channel = a->argv[3]; - int res = stop_sound_channel(fd, channel); + int res = stop_sound_channel( a->fd, channel); if ( !res ) { - ast_cli(fd, "Sound stop failed failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Sound stop failed failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -// -// end conference -// - -static char conference_end_usage[] = - "usage: conference end \n" - " ends a conference.\n" -; - -static struct ast_cli_entry cli_end = { - { "conference", "end", NULL }, - conference_end, - "stops a conference", - conference_end_usage -} ; - -int conference_end( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_end(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference end"; + e->usage = "usage: conference end \n" + " ends a conference.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check the args length - if ( argc < 3 ) - return RESULT_SHOWUSAGE ; + if ( a->argc < 3 ) + return CLI_SHOWUSAGE ; // conference name - const char* name = argv[2] ; + const char* name = a->argv[2] ; // get the conference if ( end_conference( name, 1 ) != 0 ) { - ast_cli( fd, "unable to end the conference, name => %s\n", name ) ; - return RESULT_SHOWUSAGE ; + ast_cli( a->fd, "unable to end the conference, name => %s\n", name ) ; + return CLI_SHOWUSAGE ; } - return RESULT_SUCCESS ; + return CLI_SUCCESS ; } -// -// E.BUU - Manager conference end. Additional option to just kick everybody out -// without hangin up channels -// -int manager_conference_end(struct mansession *s, const struct message *m) +static char *handle_cli_app_conference_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - const char *confname = astman_get_header(m,"Conference"); - int hangup = 1; - - const char * h = astman_get_header(m, "Hangup"); - if (h) - { - hangup = atoi(h); + switch ( cmd ) { + case CLI_INIT: + e->command = "conference lock"; + e->usage = "usage: conference lock \n" + " locks incoming video stream for conference to member \n"; + return NULL; + case CLI_GENERATE: + return NULL; } - ast_log( LOG_NOTICE, "Terminating conference %s on manager's request. Hangup: %s.\n", confname, hangup?"YES":"NO" ); - if ( end_conference( confname, hangup ) != 0 ) - { - ast_log( LOG_ERROR, "manager end conf: unable to terminate conference %s.\n", confname ); - astman_send_error(s, m, "Failed to terminate\r\n"); - return RESULT_FAILURE; - } - - astman_send_ack(s, m, "Conference terminated"); - return RESULT_SUCCESS; -} -// -// lock conference to a video source -// -static char conference_lock_usage[] = - "usage: conference lock \n" - " locks incoming video stream for conference to member \n" -; - -static struct ast_cli_entry cli_lock = { - { "conference", "lock", NULL }, - conference_lock, - "locks incoming video to a member", - conference_lock_usage -} ; - -int conference_lock( int fd, int argc, char *argv[] ) -{ // check args - if ( argc < 4 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; + const char *conference = a->argv[2]; int member; - sscanf(argv[3], "%d", &member); + sscanf(a->argv[3], "%d", &member); int res = lock_conference(conference, member); if ( !res ) { - ast_cli(fd, "Locking failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Locking failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// lock conference to a video source channel -// -static char conference_lockchannel_usage[] = - "usage: conference lockchannel \n" - " locks incoming video stream for conference to channel \n" -; - -static struct ast_cli_entry cli_lockchannel = { - { "conference", "lockchannel", NULL }, - conference_lockchannel, - "locks incoming video to a channel", - conference_lockchannel_usage -} ; - -int conference_lockchannel( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_lockchannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference lockchannel"; + e->usage = "usage: conference lockchannel \n" + " locks incoming video stream for conference to channel \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 4 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; - const char *channel = argv[3]; + const char *conference = a->argv[2]; + const char *channel = a->argv[3]; int res = lock_conference_channel(conference, channel); if ( !res ) { - ast_cli(fd, "Locking failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Locking failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// unlock conference -// -static char conference_unlock_usage[] = - "usage: conference unlock \n" - " unlocks conference \n" -; - -static struct ast_cli_entry cli_unlock = { - { "conference", "unlock", NULL }, - conference_unlock, - "unlocks conference", - conference_unlock_usage -} ; - -int conference_unlock( int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_unlock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference unlock"; + e->usage = "usage: conference unlock \n" + " unlocks conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 3 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 3 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; + const char *conference = a->argv[2]; int res = unlock_conference(conference); if ( !res ) { - ast_cli(fd, "Unlocking failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Unlocking failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Set conference default video source -// -static char conference_set_default_usage[] = - "usage: conference set default \n" - " sets the default video source for conference to member \n" - " Use a negative value for member if you want to clear the default\n" -; - -static struct ast_cli_entry cli_set_default = { - { "conference", "set", "default", NULL }, - conference_set_default, - "sets default video source", - conference_set_default_usage -} ; - -int conference_set_default(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_set_default(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference set default"; + e->usage = "usage: conference set default \n" + " sets the default video source for conference to member \n" + " Use a negative value for member if you want to clear the default\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; + const char *conference = a->argv[3]; int member; - sscanf(argv[4], "%d", &member); + sscanf(a->argv[4], "%d", &member); int res = set_default_id(conference, member); if ( !res ) { - ast_cli(fd, "Setting default video id failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Setting default video id failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Set conference default video source channel -// -static char conference_set_defaultchannel_usage[] = - "usage: conference set defaultchannel \n" - " sets the default video source channel for conference to channel \n" -; - -static struct ast_cli_entry cli_set_defaultchannel = { - { "conference", "set", "defaultchannel", NULL }, - conference_set_defaultchannel, - "sets default video source channel", - conference_set_defaultchannel_usage -} ; - -int conference_set_defaultchannel(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_set_defaultchannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference set defaultchannel"; + e->usage = "usage: conference set defaultchannel \n" + " sets the default video source channel for conference to channel \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; - const char *channel = argv[4]; + const char *conference = a->argv[3]; + const char *channel = a->argv[4]; int res = set_default_channel(conference, channel); if ( !res ) { - ast_cli(fd, "Setting default video id failed\n"); - return RESULT_FAILURE; + ast_cli( a->fd, "Setting default video id failed\n"); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Mute video from a member -// -static char conference_video_mute_usage[] = - "usage: conference video mute \n" - " mutes video from member in conference \n" -; - -static struct ast_cli_entry cli_video_mute = { - { "conference", "video", "mute", NULL }, - conference_video_mute, - "mutes video from a member", - conference_video_mute_usage -} ; - -int conference_video_mute(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_video_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference video mute"; + e->usage = "usage: conference video mute \n" + " mutes video from member in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; + const char *conference = a->argv[3]; int member; - sscanf(argv[4], "%d", &member); + sscanf(a->argv[4], "%d", &member); int res = video_mute_member(conference, member); if ( !res ) { - ast_cli(fd, "Muting video from member %d failed\n", member); - return RESULT_FAILURE; + ast_cli( a->fd, "Muting video from member %d failed\n", member); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Unmute video from a member -// -static char conference_video_unmute_usage[] = - "usage: conference video unmute \n" - " unmutes video from member in conference \n" -; - -static struct ast_cli_entry cli_video_unmute = { - { "conference", "video", "unmute", NULL }, - conference_video_unmute, - "unmutes video from a member", - conference_video_unmute_usage -} ; - -int conference_video_unmute(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_video_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference video unmute"; + e->usage = "usage: conference video unmute \n" + " unmutes video from member in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; + const char *conference = a->argv[3]; int member; - sscanf(argv[4], "%d", &member); + sscanf(a->argv[4], "%d", &member); int res = video_unmute_member(conference, member); if ( !res ) { - ast_cli(fd, "Unmuting video from member %d failed\n", member); - return RESULT_FAILURE; + ast_cli( a->fd, "Unmuting video from member %d failed\n", member); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Mute video from a channel -// -static char conference_video_mutechannel_usage[] = - "usage: conference video mutechannel \n" - " mutes video from channel in conference \n" -; - -static struct ast_cli_entry cli_video_mutechannel = { - { "conference", "video", "mutechannel", NULL }, - conference_video_mutechannel, - "mutes video from a channel", - conference_video_mutechannel_usage -} ; - -int conference_video_mutechannel(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_video_mutechannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference video mutechannel"; + e->usage = "usage: conference video mutechannel \n" + " mutes video from channel in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; - const char *channel = argv[4]; + const char *conference = a->argv[3]; + const char *channel = a->argv[4]; int res = video_mute_channel(conference, channel); if ( !res ) { - ast_cli(fd, "Muting video from channel %s failed\n", channel); - return RESULT_FAILURE; + ast_cli( a->fd, "Muting video from channel %s failed\n", channel); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Unmute video from a channel -// -static char conference_video_unmutechannel_usage[] = - "usage: conference video unmutechannel \n" - " unmutes video from channel in conference \n" -; - -static struct ast_cli_entry cli_video_unmutechannel = { - { "conference", "video", "unmutechannel", NULL }, - conference_video_unmutechannel, - "unmutes video from a channel", - conference_video_unmutechannel_usage -} ; - -int conference_video_unmutechannel(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_video_unmutechannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference video unmutechannel"; + e->usage = "usage: conference video unmutechannel \n" + " unmutes video from channel in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[3]; - const char *channel = argv[4]; + const char *conference = a->argv[3]; + const char *channel = a->argv[4]; int res = video_unmute_channel(conference, channel); if ( !res ) { - ast_cli(fd, "Unmuting video from channel %s failed\n", channel); - return RESULT_FAILURE; + ast_cli( a->fd, "Unmuting video from channel %s failed\n", channel); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } - -// -// Text message functions -// Send a text message to a member -// -static char conference_text_usage[] = - "usage: conference text \n" - " Sends text message to member in conference \n" -; - -static struct ast_cli_entry cli_text = { - { "conference", "text", NULL }, - conference_text, - "sends a text message to a member", - conference_text_usage -} ; - -int conference_text(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_text(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference text"; + e->usage = "usage: conference text \n" + " Sends text message to member in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; + const char *conference = a->argv[2]; int member; - sscanf(argv[3], "%d", &member); - const char *text = argv[4]; + sscanf(a->argv[3], "%d", &member); + const char *text = a->argv[4]; int res = send_text(conference, member, text); if ( !res ) { - ast_cli(fd, "Sending a text message to member %d failed\n", member); - return RESULT_FAILURE; + ast_cli( a->fd, "Sending a text message to member %d failed\n", member); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Send a text message to a channel -// -static char conference_textchannel_usage[] = - "usage: conference textchannel \n" - " Sends text message to channel in conference \n" -; - -static struct ast_cli_entry cli_textchannel = { - { "conference", "textchannel", NULL }, - conference_textchannel, - "sends a text message to a channel", - conference_textchannel_usage -} ; - -int conference_textchannel(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_textchannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference textchannel"; + e->usage = "usage: conference textchannel \n" + " Sends text message to channel in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 5 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 5 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; - const char *channel = argv[3]; - const char *text = argv[4]; + const char *conference = a->argv[2]; + const char *channel = a->argv[3]; + const char *text = a->argv[4]; int res = send_text_channel(conference, channel, text); if ( !res ) { - ast_cli(fd, "Sending a text message to channel %s failed\n", channel); - return RESULT_FAILURE; + ast_cli( a->fd, "Sending a text message to channel %s failed\n", channel); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Send a text message to all members in a conference -// -static char conference_textbroadcast_usage[] = - "usage: conference textbroadcast \n" - " Sends text message to all members in conference \n" -; - -static struct ast_cli_entry cli_textbroadcast = { - { "conference", "textbroadcast", NULL }, - conference_textbroadcast, - "sends a text message to all members in a conference", - conference_textbroadcast_usage -} ; - -int conference_textbroadcast(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_textbroadcast(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference textbroadcast"; + e->usage = "usage: conference textbroadcast \n" + " Sends text message to all members in conference \n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 4 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; - const char *text = argv[3]; + const char *conference = a->argv[2]; + const char *text = a->argv[3]; int res = send_text_broadcast(conference, text); if ( !res ) { - ast_cli(fd, "Sending a text broadcast to conference %s failed\n", conference); - return RESULT_FAILURE; + ast_cli( a->fd, "Sending a text broadcast to conference %s failed\n", conference); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Associate two members -// Audio from the source member will drive VAD based video switching for the destination member -// If the destination member is missing or negative, break any existing association -// -static char conference_drive_usage[] = - "usage: conference drive [destination member]\n" - " Drives VAD video switching of using audio from in conference \n" - " If destination is missing or negative, break existing association\n" -; - -static struct ast_cli_entry cli_drive = { - { "conference", "drive", NULL }, - conference_drive, - "pairs two members to drive VAD-based video switching", - conference_drive_usage -} ; - -int conference_drive(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_drive(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference drive"; + e->usage = "usage: conference drive [destination member]\n" + " Drives VAD video switching of using audio from in conference \n" + " If destination is missing or negative, break existing association\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 4 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; + const char *conference = a->argv[2]; int src_member = -1; int dst_member = -1; - sscanf(argv[3], "%d", &src_member); - if ( argc > 4 ) - sscanf(argv[4], "%d", &dst_member); + sscanf(a->argv[3], "%d", &src_member); + if ( a->argc > 4 ) + sscanf(a->argv[4], "%d", &dst_member); int res = drive(conference, src_member, dst_member); if ( !res ) { - ast_cli(fd, "Pairing members %d and %d failed\n", src_member, dst_member); - return RESULT_FAILURE; + ast_cli( a->fd, "Pairing members %d and %d failed\n", src_member, dst_member); + return CLI_FAILURE; } - return RESULT_SUCCESS; + return CLI_SUCCESS; } -// -// Associate two channels -// Audio from the source channel will drive VAD based video switching for the destination channel -// If the destination channel is missing, break any existing association -// -static char conference_drivechannel_usage[] = - "usage: conference drive [destination channel]\n" - " Drives VAD video switching of using audio from in conference \n" - " If destination is missing, break existing association\n" -; - -static struct ast_cli_entry cli_drivechannel = { - { "conference", "drivechannel", NULL }, - conference_drivechannel, - "pairs two channels to drive VAD-based video switching", - conference_drivechannel_usage -} ; - -int conference_drivechannel(int fd, int argc, char *argv[] ) +static char *handle_cli_app_conference_drivechannel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch ( cmd ) { + case CLI_INIT: + e->command = "conference drivechannel"; + e->usage = "usage: conference drive [destination channel]\n" + " Drives VAD video switching of using audio from in conference \n" + " If destination is missing, break existing association\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + // check args - if ( argc < 4 ) - return RESULT_SHOWUSAGE; + if ( a->argc < 4 ) + return CLI_SHOWUSAGE; - const char *conference = argv[2]; - const char *src_channel = argv[3]; + const char *conference = a->argv[2]; + const char *src_channel = a->argv[3]; const char *dst_channel = NULL; - if ( argc > 4 ) - dst_channel = argv[4]; + if ( a->argc > 4 ) + dst_channel = a->argv[4]; int res = drive_channel(conference, src_channel, dst_channel); if ( !res ) { - ast_cli(fd, "Pairing channels %s and %s failed\n", src_channel, dst_channel); + ast_cli( a->fd, "Pairing channels %s and %s failed\n", src_channel, dst_channel); + return CLI_FAILURE; + } + + return CLI_SUCCESS; +} + +static struct ast_cli_entry app_conference_clis[] = { + AST_CLI_DEFINE(handle_cli_app_conference_restart, "Restart a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_debug, "Enable debugging for a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_show_stats, "Display stats for active conferences"), + AST_CLI_DEFINE(handle_cli_app_conference_list, "List members of a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_kick, "Kick member from a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_kickchannel, "Kick channel from conference"), + AST_CLI_DEFINE(handle_cli_app_conference_exit, "Exit channel from any conference where it in"), + AST_CLI_DEFINE(handle_cli_app_conference_mute, "Mute member in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_mutechannel, "Mute channel in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_viewstream, "Switch view in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_viewchannel, "Switch channel in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_unmute, "Unmute member in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_unmutechannel, "Unmute channel in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_play_sound, "Play a sound to a conference member"), + AST_CLI_DEFINE(handle_cli_app_conference_stop_sounds, "Stop sounds for a conference member"), + AST_CLI_DEFINE(handle_cli_app_conference_end, "Stops a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_lock, "Locks incoming video to a member"), + AST_CLI_DEFINE(handle_cli_app_conference_lockchannel, "Locks incoming video to a channel"), + AST_CLI_DEFINE(handle_cli_app_conference_unlock, "Unlocks conference"), + AST_CLI_DEFINE(handle_cli_app_conference_set_default, "Sets default video sourcee"), + AST_CLI_DEFINE(handle_cli_app_conference_set_defaultchannel, "Sets default video source channel"), + AST_CLI_DEFINE(handle_cli_app_conference_video_mute, "Mutes video from a member"), + AST_CLI_DEFINE(handle_cli_app_conference_video_unmute, "Unmutes video from a member"), + AST_CLI_DEFINE(handle_cli_app_conference_video_mutechannel, "Mutes video from a channel"), + AST_CLI_DEFINE(handle_cli_app_conference_video_unmutechannel, "Unmutes video from a channel"), + AST_CLI_DEFINE(handle_cli_app_conference_text, "Sends a text message to a member"), + AST_CLI_DEFINE(handle_cli_app_conference_textchannel, "Sends a text message to a channel"), + AST_CLI_DEFINE(handle_cli_app_conference_textbroadcast, "Sends a text message to all members in a conference"), + AST_CLI_DEFINE(handle_cli_app_conference_drive, "Pairs two members to drive VAD-based video switching"), + AST_CLI_DEFINE(handle_cli_app_conference_drivechannel, "Pairs two channels to drive VAD-based video switching"), +}; + +// +// E.BUU - Manager conference end. Additional option to just kick everybody out +// without hangin up channels +// +int manager_conference_end(struct mansession *s, const struct message *m) +{ + const char *confname = astman_get_header(m,"Conference"); + int hangup = 1; + + const char * h = astman_get_header(m, "Hangup"); + if (h) + { + hangup = atoi(h); + } + + ast_log( LOG_NOTICE, "Terminating conference %s on manager's request. Hangup: %s.\n", confname, hangup?"YES":"NO" ); + if ( end_conference( confname, hangup ) != 0 ) + { + ast_log( LOG_ERROR, "manager end conf: unable to terminate conference %s.\n", confname ); + astman_send_error(s, m, "Failed to terminate\r\n"); return RESULT_FAILURE; } + astman_send_ack(s, m, "Conference terminated"); return RESULT_SUCCESS; } - // // cli initialization function // void register_conference_cli( void ) { - ast_cli_register( &cli_restart ); - ast_cli_register( &cli_debug ) ; - ast_cli_register( &cli_show_stats ) ; - ast_cli_register( &cli_list ); - ast_cli_register( &cli_kick ); - ast_cli_register( &cli_kickchannel ); - ast_cli_register( &cli_mute ); - ast_cli_register( &cli_mutechannel ); - ast_cli_register( &cli_viewstream ); - ast_cli_register( &cli_viewchannel ); - ast_cli_register( &cli_unmute ); - ast_cli_register( &cli_unmutechannel ); - ast_cli_register( &cli_play_sound ) ; - ast_cli_register( &cli_stop_sounds ) ; - ast_cli_register( &cli_end ); - ast_cli_register( &cli_lock ); - ast_cli_register( &cli_lockchannel ); - ast_cli_register( &cli_unlock ); - ast_cli_register( &cli_set_default ); - ast_cli_register( &cli_set_defaultchannel ); - ast_cli_register( &cli_video_mute ) ; - ast_cli_register( &cli_video_unmute ) ; - ast_cli_register( &cli_video_mutechannel ) ; - ast_cli_register( &cli_video_unmutechannel ) ; - ast_cli_register( &cli_text ); - ast_cli_register( &cli_textchannel ); - ast_cli_register( &cli_textbroadcast ); - ast_cli_register( &cli_drive ); - ast_cli_register( &cli_drivechannel ); + ast_cli_register_multiple(app_conference_clis, sizeof(app_conference_clis) / sizeof(struct ast_cli_entry)); ast_manager_register( "ConferenceList", 0, manager_conference_list, "Conference List" ); ast_manager_register( "ConferenceEnd", EVENT_FLAG_CALL, manager_conference_end, "Terminate a conference" ); @@ -1191,35 +1110,7 @@ void unregister_conference_cli( void ) { - ast_cli_unregister( &cli_restart ); - ast_cli_unregister( &cli_debug ) ; - ast_cli_unregister( &cli_show_stats ) ; - ast_cli_unregister( &cli_list ); - ast_cli_unregister( &cli_kick ); - ast_cli_unregister( &cli_kickchannel ); - ast_cli_unregister( &cli_mute ); - ast_cli_unregister( &cli_mutechannel ); - ast_cli_unregister( &cli_viewstream ); - ast_cli_unregister( &cli_viewchannel ); - ast_cli_unregister( &cli_unmute ); - ast_cli_unregister( &cli_unmutechannel ); - ast_cli_unregister( &cli_play_sound ) ; - ast_cli_unregister( &cli_stop_sounds ) ; - ast_cli_unregister( &cli_end ); - ast_cli_unregister( &cli_lock ); - ast_cli_unregister( &cli_lockchannel ); - ast_cli_unregister( &cli_unlock ); - ast_cli_unregister( &cli_set_default ); - ast_cli_unregister( &cli_set_defaultchannel ); - ast_cli_unregister( &cli_video_mute ) ; - ast_cli_unregister( &cli_video_unmute ) ; - ast_cli_unregister( &cli_video_mutechannel ) ; - ast_cli_unregister( &cli_video_unmutechannel ) ; - ast_cli_unregister( &cli_text ); - ast_cli_unregister( &cli_textchannel ); - ast_cli_unregister( &cli_textbroadcast ); - ast_cli_unregister( &cli_drive ); - ast_cli_unregister( &cli_drivechannel ); + ast_cli_unregister_multiple(app_conference_clis, sizeof(app_conference_clis) / sizeof(struct ast_cli_entry)); ast_manager_unregister( "ConferenceList" ); ast_manager_unregister( "ConferenceEnd" ); } Index: cli.h --- cli.h.orig 2008-02-26 17:05:57 +0100 +++ cli.h 2008-03-19 09:18:57 +0100 @@ -42,52 +42,6 @@ // function declarations // -int conference_show_stats( int fd, int argc, char *argv[] ) ; -int conference_show_stats_name( int fd, const char* name ) ; - -int conference_restart( int fd, int argc, char *argv[] ); - -int conference_debug( int fd, int argc, char *argv[] ) ; -int conference_no_debug( int fd, int argc, char *argv[] ) ; - -int conference_list( int fd, int argc, char *argv[] ) ; -int conference_kick( int fd, int argc, char *argv[] ) ; -int conference_kickchannel( int fd, int argc, char *argv[] ) ; - -int conference_mute( int fd, int argc, char *argv[] ) ; -int conference_unmute( int fd, int argc, char *argv[] ) ; -int conference_mutechannel( int fd, int argc, char *argv[] ) ; -int conference_unmutechannel( int fd, int argc, char *argv[] ) ; -int conference_viewstream( int fd, int argc, char *argv[] ) ; -int conference_viewchannel( int fd, int argc, char *argv[] ) ; - -int conference_play_sound( int fd, int argc, char *argv[] ) ; -int conference_stop_sounds( int fd, int argc, char *argv[] ) ; - -int conference_play_video( int fd, int argc, char *argv[] ) ; -int conference_stop_videos( int fd, int argc, char *argv[] ) ; - -int conference_end( int fd, int argc, char *argv[] ) ; - -int conference_lock( int fd, int argc, char *argv[] ) ; -int conference_lockchannel( int fd, int argc, char *argv[] ) ; -int conference_unlock( int fd, int argc, char *argv[] ) ; - -int conference_set_default(int fd, int argc, char *argv[] ) ; -int conference_set_defaultchannel(int fd, int argc, char *argv[] ) ; - -int conference_video_mute(int fd, int argc, char *argv[] ) ; -int conference_video_mutechannel(int fd, int argc, char *argv[] ) ; -int conference_video_unmute(int fd, int argc, char *argv[] ) ; -int conference_video_unmutechannel(int fd, int argc, char *argv[] ) ; - -int conference_text( int fd, int argc, char *argv[] ) ; -int conference_textchannel( int fd, int argc, char *argv[] ) ; -int conference_textbroadcast( int fd, int argc, char *argv[] ) ; - -int conference_drive( int fd, int argc, char *argv[] ) ; -int conference_drivechannel(int fd, int argc, char *argv[] ); - int manager_conference_end(struct mansession *s, const struct message *m); void register_conference_cli( void ) ; Index: conference.c --- conference.c.orig 2008-02-26 17:05:57 +0100 +++ conference.c 2008-03-19 09:18:57 +0100 @@ -28,6 +28,9 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "asterisk.h" +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $") + #include "asterisk/autoconfig.h" #include "conference.h" #include "asterisk/utils.h" @@ -45,12 +48,21 @@ static int conference_count = 0 ; +// Forward funtcion declarations +static void do_VAD_switching(struct ast_conference *conf); +static void do_video_switching(struct ast_conference *conf, int new_id, int lock); +static struct ast_conference* find_conf(const char* name); +static struct ast_conference* create_conf(char* name, struct ast_conf_member* member); +static void remove_conf(struct ast_conference* conf); +static void add_member(struct ast_conf_member* member, struct ast_conference* conf); +static int get_new_id(struct ast_conference *conf); +static int update_member_broadcasting(struct ast_conference *conf, struct ast_conf_member *member, struct conf_frame *cfr, struct timeval time); // // main conference function // -void conference_exec( struct ast_conference *conf ) +static void conference_exec( struct ast_conference *conf ) { struct ast_conf_member *next_member; @@ -302,54 +314,126 @@ // VIDEO // //-------// - // loop over the incoming frames and send to all outgoing - // TODO: this is an O(n^2) algorithm. Can we speed it up without sacrificing per-member switching? - for (video_source_member = conf->memberlist; - video_source_member != NULL; - video_source_member = video_source_member->next) + curr = ast_tvnow(); + + // Chat mode handling + // If there's only one member, then video gets reflected back to it + // If there are two members, then each sees the other's video + if ( conf->does_chat_mode && + conf->membercount > 0 && + conf->membercount <= 2 + ) + { + struct ast_conf_member *m1, *m2; + + m1 = conf->memberlist; + m2 = conf->memberlist->next; + + if ( !conf->chat_mode_on ) + conf->chat_mode_on = 1; + + start_video(m1); + if ( m2 != NULL ) + start_video(m2); + + if ( conf->membercount == 1 ) + { + cfr = get_incoming_video_frame(m1); + update_member_broadcasting(conf, m1, cfr, curr); + while ( cfr ) + { + queue_outgoing_video_frame(m1, cfr->fr, conf->delivery_time); + delete_conf_frame(cfr); + cfr = get_incoming_video_frame(m1); + } + } else if ( conf->membercount == 2 ) + { + cfr = get_incoming_video_frame(m1); + update_member_broadcasting(conf, m1, cfr, curr); + while ( cfr ) + { + queue_outgoing_video_frame(m2, cfr->fr, conf->delivery_time); + delete_conf_frame(cfr); + cfr = get_incoming_video_frame(m1); + } + + cfr = get_incoming_video_frame(m2); + update_member_broadcasting(conf, m2, cfr, curr); + while ( cfr ) + { + queue_outgoing_video_frame(m1, cfr->fr, conf->delivery_time); + delete_conf_frame(cfr); + cfr = get_incoming_video_frame(m2); + } + } + } else { - while ((cfr = get_incoming_video_frame( video_source_member ))) + // Generic conference handling (chat mode disabled or more than 2 members) + // If we were previously in chat mode, turn it off and stop video from members + if ( conf->chat_mode_on ) { + // Send STOPVIDEO commands to everybody except the current source, if any + conf->chat_mode_on = 0; for (member = conf->memberlist; member != NULL; member = member->next) { - // skip members that are not ready or are not supposed to receive video - if ( !member->ready_for_outgoing || member->norecv_video ) - continue ; - - if ( conf->video_locked ) - { - // Always send video from the locked source - if ( conf->current_video_source_id == video_source_member->id ) - queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time); - } else + if ( member->id != conf->current_video_source_id ) + stop_video(member); + } + } + + // loop over the incoming frames and send to all outgoing + // TODO: this is an O(n^2) algorithm. Can we speed it up without sacrificing per-member switching? + for (video_source_member = conf->memberlist; + video_source_member != NULL; + video_source_member = video_source_member->next + ) + { + cfr = get_incoming_video_frame(video_source_member); + update_member_broadcasting(conf, video_source_member, cfr, curr); + while ( cfr ) + { + for (member = conf->memberlist; member != NULL; member = member->next) { - // If the member has vad switching disabled and dtmf switching enabled, use that - if ( member->dtmf_switch && - !member->vad_switch && - member->req_id == video_source_member->id - ) + // skip members that are not ready or are not supposed to receive video + if ( !member->ready_for_outgoing || member->norecv_video ) + continue ; + + if ( conf->video_locked ) { - queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time); + // Always send video from the locked source + if ( conf->current_video_source_id == video_source_member->id ) + queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time); } else { - // If no dtmf switching, then do VAD switching - // The VAD switching decision code should make sure that our video source - // is legit - if ( (conf->current_video_source_id == video_source_member->id) || - (conf->current_video_source_id < 0 && - conf->default_video_source_id == video_source_member->id - ) + // If the member has vad switching disabled and dtmf switching enabled, use that + if ( member->dtmf_switch && + !member->vad_switch && + member->req_id == video_source_member->id ) { queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time); + } else + { + // If no dtmf switching, then do VAD switching + // The VAD switching decision code should make sure that our video source + // is legit + if ( (conf->current_video_source_id == video_source_member->id) || + (conf->current_video_source_id < 0 && + conf->default_video_source_id == video_source_member->id + ) + ) + { + queue_outgoing_video_frame(member, cfr->fr, conf->delivery_time); + } } - } + } } + // Garbage collection + delete_conf_frame(cfr); + cfr = get_incoming_video_frame(video_source_member); } - // Garbage collection - delete_conf_frame(cfr); } } @@ -448,7 +532,7 @@ ast_mutex_init( &conflist_lock ) ; } -struct ast_conference* start_conference( struct ast_conf_member* member ) +struct ast_conference* join_conference( struct ast_conf_member* member ) { // check input if ( member == NULL ) @@ -499,7 +583,7 @@ } // This function should be called with conflist_lock mutex being held -struct ast_conference* find_conf( const char* name ) +static struct ast_conference* find_conf( const char* name ) { // no conferences exist if ( conflist == NULL ) @@ -527,7 +611,7 @@ } // This function should be called with conflist_lock held -struct ast_conference* create_conf( char* name, struct ast_conf_member* member ) +static struct ast_conference* create_conf( char* name, struct ast_conf_member* member ) { ast_log( AST_CONF_DEBUG, "entered create_conf, name => %s\n", name ) ; @@ -551,7 +635,7 @@ conf->memberlist = NULL ; conf->membercount = 0 ; - conf->conference_thread = -1 ; + conf->conference_thread = 0 ; conf->debug_flag = 0 ; @@ -562,6 +646,9 @@ //conf->current_video_source_timestamp = ast_tvnow(); conf->video_locked = 0; + conf->chat_mode_on = 0; + conf->does_chat_mode = 0; + // zero stats memset( &conf->stats, 0x0, sizeof( ast_conference_stats ) ) ; @@ -614,7 +701,7 @@ { ast_log( LOG_ERROR, "unable to start conference thread for conference %s\n", conf->name ) ; - conf->conference_thread = -1 ; + conf->conference_thread = 0 ; // release conference mutexes ast_mutex_unlock( &conf->lock ) ; @@ -632,7 +719,7 @@ } //This function should be called with conflist_lock and conf->lock held -void remove_conf( struct ast_conference *conf ) +static void remove_conf( struct ast_conference *conf ) { int c; @@ -709,7 +796,7 @@ return ; } -int get_new_id( struct ast_conference *conf ) +static int get_new_id( struct ast_conference *conf ) { // must have the conf lock when calling this int newid; @@ -788,11 +875,10 @@ // // This function should be called with conflist_lock held -void add_member( struct ast_conf_member *member, struct ast_conference *conf ) +static void add_member( struct ast_conf_member *member, struct ast_conference *conf ) { int newid, last_id; struct ast_conf_member *othermember; - int count; if ( conf == NULL ) { @@ -820,11 +906,22 @@ } } - if ( member->mute_video ) + // update conference stats + conf->membercount++; + + // The conference sets chat mode according to the latest member chat flag + conf->does_chat_mode = member->does_chat_mode; + + // check if we're supposed to do chat_mode, and if so, start video on the client + if ( conf->does_chat_mode && conf->membercount <= 2 ) { - send_text_message_to_member(member, AST_CONF_CONTROL_STOP_VIDEO); + start_video(member); + conf->chat_mode_on = 1; } + if ( member->mute_video ) + stop_video(member); + // set a long term id int new_initial_id = 0; othermember = conf->memberlist; @@ -853,9 +950,6 @@ member->next = conf->memberlist ; // next is now list conf->memberlist = member ; // member is now at head of list - // update conference stats - count = count_member( member, conf, 1 ) ; - ast_log( AST_CONF_DEBUG, "member added to conference, name => %s\n", conf->name ) ; // release the conference lock @@ -957,7 +1051,7 @@ member_temp->next = member->next ; // update conference stats - count = count_member( member, conf, 0 ) ; + count = --conf->membercount; // Check if member is the default or current video source if ( conf->current_video_source_id == member->id ) @@ -970,6 +1064,17 @@ conf->default_video_source_id = -1; } + // If the member is broadcasting, we notify that it is no longer the case + if ( member->video_broadcast_active ) + { + manager_event(EVENT_FLAG_CALL, + "ConferenceVideoBroadcastOff", + "ConferenceName: %s\r\nChannel: %s\r\n", + conf->name, + member->channel_name + ); + } + // output to manager... manager_event( EVENT_FLAG_CALL, @@ -997,6 +1102,32 @@ // it already points to the previous (or NULL). // it will still be the previous after member is deleted + // notify others about leave + char * leave_snd = member->leave_snd; + if (conf->membercount && strcmp(leave_snd, "-")>1) + { + struct ast_conf_member *membertest = conf->memberlist; + while (membertest != NULL) + { + if (membertest != member) + { + // lock member for basic_play_sound + ast_mutex_lock(&membertest->lock); + + // basic_play_sound unlock member automatically. do not mute on enter message + if (!basic_play_sound (membertest, leave_snd, 0)) + { + ast_log(LOG_ERROR, "playing conference[%d] leave message <%s> FAILED on <%s>\n", conf->membercount, leave_snd, membertest->channel_name) ; + } + else + { + ast_log(LOG_NOTICE, "playing conference[%d] leave message <%s> on <%s>\n", conf->membercount, leave_snd, membertest->channel_name); + } + membertest = membertest->next; + } + } + } + // delete the member delete_member( member ) ; @@ -1028,33 +1159,6 @@ return count ; } -int count_member( struct ast_conf_member* member, struct ast_conference* conf, short add_member ) -{ - if ( member == NULL || conf == NULL ) - { - ast_log( LOG_WARNING, "unable to count member\n" ) ; - return -1 ; - } - - short delta = ( add_member == 1 ) ? 1 : -1 ; - - // increment member count - conf->membercount += delta ; - - return conf->membercount ; -} - -// -// queue incoming frame functions -// - - - - -// -// get conference stats -// - // // returns: -1 => error, 0 => debugging off, 1 => debugging on // state: on => 1, off => 0, toggle => -1 @@ -1160,6 +1264,8 @@ // acquire conference mutex ast_mutex_lock(&conf->lock); + ast_cli(fd, "Chat mode is %s\n", conf->chat_mode_on ? "ON" : "OFF"); + // do the biz member = conf->memberlist ; while ( member != NULL ) @@ -1182,6 +1288,9 @@ if ( member->no_camera ) ast_cli( fd, "N"); if ( member->does_text ) ast_cli( fd, "t"); if ( member->via_telephone ) ast_cli( fd, "T"); + if ( member->vad_linger ) ast_cli( fd, "z"); + if ( member->does_chat_mode ) ast_cli( fd, "o" ); + if ( member->force_vad_switch ) ast_cli( fd, "F" ); ast_cli( fd, " " ); if ( member->id == conf->default_video_source_id ) @@ -1871,16 +1980,18 @@ // All the VAD-based video switching magic happens here // This function should be called inside conference_exec // The conference mutex should be locked, we don't have to do it here -void do_VAD_switching(struct ast_conference *conf) +static void do_VAD_switching(struct ast_conference *conf) { struct ast_conf_member *member; - struct timeval current_time; - long longest_speaking; - struct ast_conf_member *longest_speaking_member; - int current_silent, current_no_camera, current_video_mute; - int default_no_camera, default_video_mute; - - current_time = ast_tvnow(); + struct timeval current_time = ast_tvnow(); + long longest_speaking = 0; + struct ast_conf_member *longest_speaking_member = NULL; + int current_silent = 0; + int current_linger = 0; + int current_no_video = 0; + int current_force_switch = 0; + int default_no_video = 0; + int default_force_switch = 0; // Scan the member list looking for the longest speaking member // We also check if the currently speaking member has been silent for a while @@ -1889,27 +2000,10 @@ // at least AST_CONF_VIDEO_START_TIMEOUT ms // We say that a member is silent after his speaking state has been off for // at least AST_CONF_VIDEO_STOP_TIMEOUT ms - longest_speaking = 0; - longest_speaking_member = NULL; - current_silent = 0; - current_no_camera = 0; - current_video_mute = 0; - default_no_camera = 0; - default_video_mute = 0; for ( member = conf->memberlist ; member != NULL ; member = member->next ) { - // Has the state changed since last time through this loop? Notify! - if ( member->speaking_state_notify ) - { -/* fprintf(stderr, "Mihai: member %d, channel %s has changed state to %s\n", - member->id, - member->channel_name, - ((member->speaking_state == 1 ) ? "speaking" : "silent") - ); */ - } - // If a member connects via telephone, they don't have video if ( member->via_telephone ) continue; @@ -1920,29 +2014,30 @@ if ( !member->vad_switch ) continue; - if ( member->mute_video ) + // Extract the linger and force switch flags of the current video source + if ( member->id == conf->current_video_source_id ) { - if ( member->id == conf->default_video_source_id ) - default_video_mute = 1; - if ( member->id == conf->current_video_source_id ) - current_video_mute = 1; - else - continue; + current_linger = member->vad_linger; + current_force_switch = member->force_vad_switch; } + + if ( member->id == conf->default_video_source_id ) + default_force_switch = member->force_vad_switch; - if ( member->no_camera ) + if ( member->no_camera || member->mute_video ) { if ( member->id == conf->default_video_source_id ) - default_no_camera = 1; + default_no_video = 1; + if ( member->id == conf->current_video_source_id ) - current_no_camera = 1; - else + current_no_video = 1; + else if ( !member->force_vad_switch ) continue; } // Check if current speaker has been silent for a while if ( member->id == conf->current_video_source_id && - member->speaking_state == 0 && + !member->speaking_state && ast_tvdiff_ms(current_time, member->last_state_change) > AST_CONF_VIDEO_STOP_TIMEOUT ) { current_silent = 1; @@ -1963,27 +2058,33 @@ // We got our results, now let's make a decision // If the currently speaking member has been marked as silent, then we take the longest - // speaking member. If no member is speaking, we go to default + // speaking member. If no member is speaking, but the current member has the vad_linger + // flag set, we stay put, otherwise we go to default. If there's no default, we blank. // As a policy we don't want to switch away from a member that is speaking // however, we might need to refine this to avoid a situation when a member has a // low noise threshold or its VAD is simply stuck - if ( current_silent || current_no_camera || current_video_mute || conf->current_video_source_id < 0 ) - { - if ( longest_speaking_member != NULL ) - { - do_video_switching(conf, longest_speaking_member->id, 0); - } else - { - // If there's nobody speaking and we have a default that can send video, switch to it - // If not, then switch to empty (-1) - if ( conf->default_video_source_id >= 0 && - !default_no_camera && - !default_video_mute - ) - do_video_switching(conf, conf->default_video_source_id, 0); - else - do_video_switching(conf, -1, 0); - } + if ( + (conf->current_video_source_id < 0) || + (current_silent && !current_linger) || + (current_silent && longest_speaking_member != NULL ) || + (current_no_video && !current_force_switch) + ) + { + int new_id; + + if ( longest_speaking_member ) + // Somebody is talking, switch to that member + new_id = longest_speaking_member->id; + else if ( conf->default_video_source_id && + (!default_no_video || default_force_switch) + ) + // No talking, but we have a default that can send video + new_id = conf->default_video_source_id; + else + // No default, switch to empty (-1) + new_id = -1; + + do_video_switching(conf, new_id, 0); } } @@ -2752,80 +2853,62 @@ // a text message notifying members of a video switch // The notification is sent to the current member and to the new member // The function locks the conference mutex as required -void do_video_switching(struct ast_conference *conf, int new_id, int lock) +static void do_video_switching(struct ast_conference *conf, int new_id, int lock) { - struct ast_conf_member *member; - struct ast_conf_member *new_member = NULL; - if ( conf == NULL ) return; if ( lock ) - { - // acquire conference mutex ast_mutex_lock( &conf->lock ); - } - - //fprintf(stderr, "Mihai: video switch from %d to %d\n", conf->current_video_source_id, new_id); // No need to do anything if the current member is the same as the new member if ( new_id != conf->current_video_source_id ) { + // During chat mode, we don't actually switch members + // however, we keep track of who's supposed to be current speaker + // so we can switch to it once we get out of chat mode. + // We also send VideoSwitch events so anybody monitoring the AMI + // can keep track of this + struct ast_conf_member *member; + struct ast_conf_member *new_member = NULL; + for ( member = conf->memberlist ; member != NULL ; member = member->next ) { if ( member->id == conf->current_video_source_id ) { - send_text_message_to_member(member, AST_CONF_CONTROL_STOP_VIDEO); + if ( !conf->chat_mode_on ) + stop_video(member); } if ( member->id == new_id ) { - send_text_message_to_member(member, AST_CONF_CONTROL_START_VIDEO); + if ( !conf->chat_mode_on ) + start_video(member); new_member = member; } } - conf->current_video_source_id = new_id; + manager_event(EVENT_FLAG_CALL, + "ConferenceVideoSwitch", + "ConferenceName: %s\r\nChannel: %s\r\n", + conf->name, + new_member == NULL ? "empty" : new_member->channel_name + ); - if ( new_member != NULL ) - { - manager_event(EVENT_FLAG_CALL, - "ConferenceVideoSwitch", - "ConferenceName: %s\r\nChannel: %s\r\n", - conf->name, - new_member->channel_name); - } else - { - manager_event(EVENT_FLAG_CALL, - "ConferenceVideoSwitch", - "ConferenceName: %s\r\nChannel: empty\r\n", - conf->name); - } + conf->current_video_source_id = new_id; } if ( lock ) - { - // release conference mutex ast_mutex_unlock( &conf->lock ); - } } -int play_sound_channel(int fd, const char *channel, const char *file, int mute) +int basic_play_sound(struct ast_conf_member *member, const char *file, int mute) { - struct ast_conf_member *member; struct ast_conf_soundq *newsound; struct ast_conf_soundq **q; - member = find_member(channel, 1); - if( !member ) - { - ast_cli(fd, "Member %s not found\n", channel); - return 0; - } - newsound = calloc(1, sizeof(struct ast_conf_soundq)); newsound->stream = ast_openstream(member->chan, file, NULL); - if( !newsound->stream ) + if( !newsound->stream ) { - ast_cli(fd, "Sound %s not found\n", file); free(newsound); ast_mutex_unlock(&member->lock); return 0; @@ -2841,6 +2924,26 @@ ast_mutex_unlock(&member->lock); + return 1 ; +} + +int play_sound_channel(int fd, const char *channel, const char *file, int mute) +{ + struct ast_conf_member *member; + + member = find_member(channel, 1); + if( !member ) + { + ast_cli(fd, "Member %s not found\n", channel); + return 0; + } + + if (! basic_play_sound(member, file, mute)) + { + ast_cli(fd, "Sound %s not found\n", file); + return 0; + } + ast_cli(fd, "Playing sound %s to member %s %s\n", file, channel, mute ? "with mute" : ""); @@ -2884,3 +2987,38 @@ ast_cli( fd, "Stopped sounds to member %s\n", channel); return 1; } + +static int update_member_broadcasting(struct ast_conference *conf, struct ast_conf_member *member, struct conf_frame *cfr, struct timeval now) +{ + if ( conf == NULL || member == NULL ) + return 0; + + if ( cfr == NULL && + member->video_broadcast_active && + (ast_tvdiff_ms(now, member->last_video_frame_time)) > AST_CONF_VIDEO_STOP_BROADCAST_TIMEOUT + ) + { + member->video_broadcast_active = 0; + manager_event(EVENT_FLAG_CALL, + "ConferenceVideoBroadcastOff", + "ConferenceName: %s\r\nChannel: %s\r\n", + conf->name, + member->channel_name + ); + } else if ( cfr != NULL ) + { + member->last_video_frame_time = now; + if ( !member->video_broadcast_active ) + { + member->video_broadcast_active = 1; + manager_event(EVENT_FLAG_CALL, + "ConferenceVideoBroadcastOn", + "ConferenceName: %s\r\nChannel: %s\r\n", + conf->name, + member->channel_name + ); + } + } + + return member->video_broadcast_active; +} Index: conference.h --- conference.h.orig 2008-02-26 17:05:57 +0100 +++ conference.h 2008-03-19 09:18:57 +0100 @@ -109,6 +109,12 @@ // keep track of current delivery time struct timeval delivery_time ; + // the conference does chat mode: special treatment for situations with 1 and 2 members + short does_chat_mode; + + // chat mode is on; + short chat_mode_on; + // 1 => on, 0 => off short debug_flag ; } ; @@ -120,13 +126,8 @@ // function declarations // -struct ast_conference* start_conference( struct ast_conf_member* member ) ; - -void conference_exec( struct ast_conference* conf ) ; +struct ast_conference* join_conference( struct ast_conf_member* member ) ; -struct ast_conference* find_conf( const char* name ) ; -struct ast_conference* create_conf( char* name, struct ast_conf_member* member ) ; -void remove_conf( struct ast_conference* conf ) ; int end_conference( const char *name, int hangup ) ; // find a particular member, locking if requested. @@ -136,14 +137,9 @@ int queue_frame_for_speaker( struct ast_conference* conf, struct ast_conf_member* member, conf_frame* frame ) ; int queue_silent_frame( struct ast_conference* conf, struct ast_conf_member* member ) ; -int get_new_id( struct ast_conference *conf ); -void add_member( struct ast_conf_member* member, struct ast_conference* conf ) ; int remove_member( struct ast_conf_member* member, struct ast_conference* conf ) ; -int count_member( struct ast_conf_member* member, struct ast_conference* conf, short add_member ) ; -void do_VAD_switching(struct ast_conference *conf); int send_text_message_to_member(struct ast_conf_member *member, const char *text); -void do_video_switching(struct ast_conference *conf, int new_id, int lock); // called by app_confernce.c:load_module() void init_conference( void ) ; @@ -185,6 +181,7 @@ int drive(const char *conference, int src_member_id, int dst_member_id); int drive_channel(const char *conference, const char *src_channel, const char *dst_channel); +int basic_play_sound(struct ast_conf_member *member, const char *file, int mute); int play_sound_channel(int fd, const char *channel, const char *file, int mute); int stop_sound_channel(int fd, const char *channel); Index: frame.c --- frame.c.orig 2008-02-26 17:05:57 +0100 +++ frame.c 2008-03-19 09:18:57 +0100 @@ -28,6 +28,10 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $") + #include "asterisk/autoconfig.h" #include "frame.h" Index: member.c --- member.c.orig 2008-02-26 17:05:57 +0100 +++ member.c 2008-03-19 09:18:57 +0100 @@ -28,7 +28,13 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1 $") + #include +#include "asterisk/channel.h" +#include "asterisk/app.h" #include "asterisk/autoconfig.h" #include "member.h" @@ -635,7 +641,7 @@ // setup a conference for the new member // - conf = start_conference( member ) ; + conf = join_conference( member ) ; if ( conf == NULL ) { @@ -690,6 +696,42 @@ // tell conference_exec we're ready for frames member->ready_for_outgoing = 1 ; + + // notify others about enter + char * enter_snd = member->enter_snd; + if (strcmp(enter_snd, "-")!=0) + { + // lock conference + ast_mutex_lock( &conf->lock ); + + /*if (conf->membercount < 2) + { + enter_snd = "conf-onlyperson"; + }*/ + + struct ast_conf_member *membertest = conf->memberlist; + while (membertest != NULL) + { + // lock member for basic_play_sound + ast_mutex_lock(&membertest->lock); + + // basic_play_sound unlock member automatically. do not mute on enter message + if (!basic_play_sound ( membertest, enter_snd, 0 )) + { + ast_log(LOG_ERROR, "playing conference[%d] entry message <%s> FAILED on <%s>\n", conf->membercount, enter_snd, membertest->channel_name); + } + else + { + ast_log(LOG_NOTICE, "playing conference[%d] entry message <%s> on <%s>\n", conf->membercount, enter_snd, membertest->channel_name); + } + + membertest = membertest->next; + } + + // unlock conference + ast_mutex_unlock( &conf->lock ); + } + while ( 42 == 42 ) { // make sure we have a channel to process @@ -812,6 +854,17 @@ struct ast_conf_member* create_member( struct ast_channel *chan, const char* data ) { + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(conf_name); + AST_APP_ARG(flags); + AST_APP_ARG(enter_snd); + AST_APP_ARG(leave_snd); + AST_APP_ARG(priority); + AST_APP_ARG(vad_prob_start); + AST_APP_ARG(vad_prob_continue); + ); + // // check input // @@ -828,6 +881,11 @@ return NULL ; } + if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "Conference requires an argument (conf_name[|flags[|enter_snd[|leave_snd[|priority[vad_prob_start[|vad_prob_continue]]]]]]))\n"); + return NULL; + } + // // allocate memory for new conference member // @@ -846,61 +904,54 @@ // // initialize member with passed data values // + + parse = ast_strdupa(data); - char argstr[80] ; - char *stringp, *token ; - - // copy the passed data - strncpy( argstr, data, sizeof(argstr) - 1 ) ; - - // point to the copied data - stringp = argstr ; - - ast_log( AST_CONF_DEBUG, "attempting to parse passed params, stringp => %s\n", stringp ) ; + AST_STANDARD_APP_ARGS(args, parse); // parse the id - if ( ( token = strsep( &stringp, "/" ) ) != NULL ) - { - member->conf_name = malloc( strlen( token ) + 1 ) ; - strcpy( member->conf_name, token ) ; - } - else + if (ast_strlen_zero(args.conf_name)) { ast_log( LOG_ERROR, "unable to parse member id\n" ) ; free( member ) ; return NULL ; } + else + member->conf_name = ast_strdup(args.conf_name); // parse the flags - if ( ( token = strsep( &stringp, "/" ) ) != NULL ) - { - member->flags = malloc( strlen( token ) + 1 ) ; - strcpy( member->flags, token ) ; - } + if (!ast_strlen_zero(args.flags)) + member->flags = ast_strdup(args.flags); else - { - // make member->flags something - member->flags = malloc( sizeof( char ) ) ; - memset( member->flags, 0x0, sizeof( char ) ) ; - } + member->flags = ast_strdup(""); + + // parse enter sound + if (!ast_strlen_zero(args.enter_snd)) + member->enter_snd = ast_strdup(args.enter_snd); + else + member->enter_snd = ast_strdup("enter"); + // parse leave sound + if (!ast_strlen_zero(args.leave_snd)) + member->leave_snd = ast_strdup(args.leave_snd); + else + member->leave_snd = ast_strdup("leave"); + + if (!ast_strlen_zero(args.priority)) // parse the priority - member->priority = ( token = strsep( &stringp, "/" ) ) != NULL - ? atoi( token ) - : 0 - ; - - // parse the vad_prob_start - member->vad_prob_start = ( token = strsep( &stringp, "/" ) ) != NULL - ? atof( token ) - : AST_CONF_PROB_START - ; - - // parse the vad_prob_continue - member->vad_prob_continue = ( token = strsep( &stringp, "/" ) ) != NULL - ? atof( token ) - : AST_CONF_PROB_CONTINUE - ; + member->priority = atoi(args.priority); + else + member->priority = 0; + + if (!ast_strlen_zero(args.vad_prob_start)) + member->vad_prob_start = atof(args.vad_prob_start); + else + member->vad_prob_start = AST_CONF_PROB_START; + + if (!ast_strlen_zero(args.vad_prob_continue)) + member->vad_prob_continue = atof(args.vad_prob_continue); + else + member->vad_prob_continue = AST_CONF_PROB_CONTINUE; // debugging ast_log( @@ -991,9 +1042,15 @@ member->speaking_state_notify = 0 ; member->speaking_state = 0 ; member->local_speaking_state = 0; + member->last_state_change = (struct timeval){0, 0}; member->speaker_count = 0; member->driven_member = NULL; + member->video_broadcast_active = 0; + member->last_video_frame_time = (struct timeval){0, 0}; + + member->video_started = 0; + // linked-list pointer member->next = NULL ; @@ -1067,7 +1124,7 @@ } else { - // allowed flags are C, c, L, l, V, D, A, C, X, R, T, t, M, S + // allowed flags are C, c, L, l, V, D, A, C, X, R, T, t, M, S, z, o, F // mute/no_recv options switch ( flags[i] ) { @@ -1105,6 +1162,9 @@ case 'S': member->vad_switch = 1; break; + case 'F': + member->force_vad_switch = 1; + break; case 'M': member->ismoderator = 1; break; @@ -1114,6 +1174,12 @@ case 't': member->does_text = 1; break; + case 'z': + member->vad_linger = 1; + break; + case 'o': + member->does_chat_mode = 1; + break; //Telephone connection case 'T': @@ -1162,8 +1228,11 @@ speex_preprocess_ctl( member->dsp, SPEEX_PREPROCESS_SET_PROB_START, &member->vad_prob_start ) ; speex_preprocess_ctl( member->dsp, SPEEX_PREPROCESS_SET_PROB_CONTINUE, &member->vad_prob_continue ) ; + speex_preprocess_ctl( member->dsp, SPEEX_PREPROCESS_GET_PROB_START, &member->vad_prob_start ) ; + speex_preprocess_ctl( member->dsp, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &member->vad_prob_continue ) ; + ast_log( AST_CONF_DEBUG, "speech_prob_start => %f, speech_prob_continue => %f\n", - member->dsp->speech_prob_start, member->dsp->speech_prob_continue ) ; + member->vad_prob_start, member->vad_prob_continue ) ; } } #endif @@ -1446,6 +1515,10 @@ free(member->callerid); free(member->callername); + // free enter/leave sounds + free(member->enter_snd); + free(member->leave_snd); + free( member ) ; member = NULL ; @@ -3276,3 +3349,31 @@ return; } + +int is_video_eligible(struct ast_conf_member *member) +{ + if ( member == NULL ) + return 0; + + return !member->no_camera && !member->mute_video && !member->via_telephone; +} + +// Member start and stop video methods +void start_video(struct ast_conf_member *member) +{ + if ( member == NULL || member->video_started || !is_video_eligible(member)) + return; + + send_text_message_to_member(member, AST_CONF_CONTROL_START_VIDEO); + member->video_started = 1; +} + +void stop_video(struct ast_conf_member *member) +{ + if ( member == NULL || !member->video_started ) + return; + + send_text_message_to_member(member, AST_CONF_CONTROL_STOP_VIDEO); + member->video_started = 0; + +} Index: member.h --- member.h.orig 2008-02-26 17:05:57 +0100 +++ member.h 2008-03-19 09:18:57 +0100 @@ -151,6 +151,10 @@ // switch video by VAD? short vad_switch; + // do a VAD switch even if video is not enabled? + short force_vad_switch; + // if member is current speaker, video will stay on it when it becomes silent + short vad_linger; // switch by dtmf? short dtmf_switch; // relay dtmf to manager? @@ -159,6 +163,8 @@ short first_frame_received; // does text messages? short does_text; + // conference does chat mode (1 on 1 video when two members in conference) + short does_chat_mode; // time we last dropped a frame @@ -177,6 +183,15 @@ struct timeval last_state_change; int speaker_count; // Number of drivers (including this member) that are speaking + // Stuff used to determine video broadcast state + // This member's video is sent out to at least one member of the conference + short video_broadcast_active; + // Time when we last sent out a video frame from this member + struct timeval last_video_frame_time; + + // Is the member supposed to be transmitting video? + short video_started; + // pointer to next member in single-linked list struct ast_conf_member* next ; @@ -237,6 +252,10 @@ // For playing sounds struct ast_conf_soundq *soundq; struct ast_conf_soundq *videoq; + + // Enter/leave sounds + char * enter_snd; + char * leave_snd; // Pointer to another member that will be driven from this member's audio struct ast_conf_member *driven_member; @@ -295,6 +314,12 @@ struct ast_conf_member *member, struct conf_frame *send_frames); +int is_video_eligible(struct ast_conf_member *member); + +// Member start and stop video methods +void start_video(struct ast_conf_member *member); +void stop_video(struct ast_conf_member *member); + // // packer functions //