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 <stdlib.h>
@@ -40,27 +41,27 @@
 #include <math.h>
 #include <stdio.h>
 
-
 #include <pthread.h>
 
 /* asterisk includes */
-#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>
+#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 <conference_name> [ 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 <conference_name> [ 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 {<conference_name>}\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 {<conference_name>}\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 <conference> <member id>\n"
+			" kick member <member id> from conference <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 <conference> <member id>\n"
-	"       kick member <member id> from conference <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 <conference_name> <channel>\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 <conference_name> <channel>\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 <channel>\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 <conference_name> <member id>\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 <conference_name> <member id>\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 <channel>\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 <channel>\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 <conference_name> <member id> <stream no>\n"
+			" member <member id> will receive video stream <stream no>\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 <conference_name> <member id> <stream no>\n"
-	"       member <member id> will receive video stream <stream no>\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 <conference_name> <dest channel> <src channel>\n"
+			" channel <dest channel> will receive video stream <src channel>\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 <conference_name> <dest channel> <src channel>\n"
-	"       channel <dest channel> will receive video stream <src channel>\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 <conference_name> <member id>\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 <conference_name> <member id>\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 <channel>\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 <channel>\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 <channel-id> <sound-file> [mute]\n"
-	"       play sound <sound-file> to conference member <channel-id>.\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 <channel-id> <sound-file> [mute]\n"
+			" play sound <sound-file> to conference member <channel-id>.\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 <channel-id>\n"
-	"       stop sounds for conference member <channel-id>.\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 <channel-id>\n"
+			" stop sounds for conference member <channel-id>.\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 <conference name>\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 <conference name>\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 <conference name> <member id>\n"
+		" locks incoming video stream for conference <conference name> to member <member id>\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 <conference name> <member id>\n"
-	"       locks incoming video stream for conference <conference name> to member <member id>\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 <conference name> <channel>\n"
-	"       locks incoming video stream for conference <conference name> to channel <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 <conference name> <channel>\n"
+			" locks incoming video stream for conference <conference name> to channel <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 <conference name>\n"
-	"       unlocks conference <conference name>\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 <conference name>\n"
+			" unlocks conference <conference name>\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 <conference name> <member id>\n"
-	"       sets the default video source for conference <conference name> to member <member id>\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 <conference name> <member id>\n"
+			" sets the default video source for conference <conference name> to member <member id>\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 <conference name> <channel>\n"
-	"       sets the default video source channel for conference <conference name> to channel <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 <conference name> <channel>\n"
+			" sets the default video source channel for conference <conference name> to channel <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 <conference name> <member id>\n"
-	"       mutes video from member <member id> in conference <conference name>\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 <conference name> <member id>\n"
+			" mutes video from member <member id> in conference <conference name>\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 <conference name> <member id>\n"
-	"       unmutes video from member <member id> in conference <conference name>\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 <conference name> <member id>\n"
+			" unmutes video from member <member id> in conference <conference name>\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 <conference name> <channel>\n"
-	"       mutes video from channel <channel> in conference <conference name>\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 <conference name> <channel>\n"
+			" mutes video from channel <channel> in conference <conference name>\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 <conference name> <channel>\n"
-	"       unmutes video from channel <channel> in conference <conference name>\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 <conference name> <channel>\n"
+			" unmutes video from channel <channel> in conference <conference name>\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 <conference name> <member id> <text>\n"
-	"        Sends text message <text> to member <member id> in conference <conference name>\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 <conference name> <member id> <text>\n"
+			" Sends text message <text> to member <member id> in conference <conference name>\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 <conference name> <channel> <text>\n"
-	"        Sends text message <text> to channel <channel> in conference <conference name>\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 <conference name> <channel> <text>\n"
+			" Sends text message <text> to channel <channel> in conference <conference name>\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 <conference name> <text>\n"
-	"        Sends text message <text> to all members in conference <conference name>\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 <conference name> <text>\n"
+			" Sends text message <text> to all members in conference <conference name>\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 <conference name> <source member> [destination member]\n"
-	"        Drives VAD video switching of <destination member> using audio from <source member> in conference <conference name>\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 <conference name> <source member> [destination member]\n"
+			" Drives VAD video switching of <destination member> using audio from <source member> in conference <conference name>\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 <conference name> <source channel> [destination channel]\n"
-	"        Drives VAD video switching of <destination member> using audio from <source channel> in conference <conference channel>\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 <conference name> <source channel> [destination channel]\n"
+			" Drives VAD video switching of <destination member> using audio from <source channel> in conference <conference channel>\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 <stdio.h>
+#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
 //
