/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

File: oct6100_conf_bridge.c

    Copyright (c) 2001-2008 Octasic Inc.
    
Description: 

	This file contains all functions related to a conference bridge.  Procedures
	needed to open/close a bridge, add/remove a participant to a conference 
	bridge, mute/unmute a participant, etc..  are all present in this source 
	file.

This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API  is 
free software; you can redistribute it and/or modify it under the terms of 
the GNU General Public License as published by the Free Software Foundation; 
either version 2 of the License, or (at your option) any later version.

The OCT6100 GPL API is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
for more details. 

You should have received a copy of the GNU General Public License 
along with the OCT6100 GPL API; if not, write to the Free Software 
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

$Octasic_Release: OCT612xAPI-01.01.01 $

$Octasic_Revision: 146 $

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/


/*****************************  INCLUDE FILES  *******************************/

#include "octdef.h"

#include "oct6100api/oct6100_defines.h"
#include "oct6100api/oct6100_errors.h"
#include "oct6100api/oct6100_apiud.h"

#include "apilib/octapi_llman.h"

#include "oct6100api/oct6100_tlv_inst.h"
#include "oct6100api/oct6100_chip_open_inst.h"
#include "oct6100api/oct6100_chip_stats_inst.h"
#include "oct6100api/oct6100_interrupts_inst.h"
#include "oct6100api/oct6100_remote_debug_inst.h"
#include "oct6100api/oct6100_debug_inst.h"
#include "oct6100api/oct6100_api_inst.h"
#include "oct6100api/oct6100_channel_inst.h"
#include "oct6100api/oct6100_mixer_inst.h"
#include "oct6100api/oct6100_conf_bridge_inst.h"

#include "oct6100api/oct6100_interrupts_pub.h"
#include "oct6100api/oct6100_chip_open_pub.h"
#include "oct6100api/oct6100_channel_pub.h"
#include "oct6100api/oct6100_mixer_pub.h"
#include "oct6100api/oct6100_conf_bridge_pub.h"

#include "oct6100_chip_open_priv.h"
#include "oct6100_miscellaneous_priv.h"
#include "oct6100_memory_priv.h"
#include "oct6100_tsst_priv.h"
#include "oct6100_channel_priv.h"
#include "oct6100_mixer_priv.h"
#include "oct6100_conf_bridge_priv.h"


/****************************  PUBLIC FUNCTIONS  *****************************/


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeOpen

Description:    This function opens a conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeOpen		Pointer to conference bridge open structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeOpenDef(
				tPOCT6100_CONF_BRIDGE_OPEN			f_pConfBridgeOpen )
{
	f_pConfBridgeOpen->pulConfBridgeHndl = NULL;
	f_pConfBridgeOpen->fFlexibleConferencing = FALSE;

	return cOCT6100_ERR_OK;
}


UINT32 Oct6100ConfBridgeOpen(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_OPEN			f_pConfBridgeOpen )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure.*/
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeOpenSer( f_pApiInstance, f_pConfBridgeOpen );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeClose

Description:    This function closes a conference bridge.  A conference
				bridge can only be closed if no participants are present on 
				the bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeClose		Pointer to conference bridge close structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeCloseDef(
				tPOCT6100_CONF_BRIDGE_CLOSE			f_pConfBridgeClose )
{
	f_pConfBridgeClose->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK;
}


UINT32 Oct6100ConfBridgeClose(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_CLOSE			f_pConfBridgeClose )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeCloseSer( f_pApiInstance, f_pConfBridgeClose );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanAdd

Description:    This function adds an echo channel (participant) to a 
				conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeAdd		Pointer to conference bridge channel addition structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanAddDef(
				tPOCT6100_CONF_BRIDGE_CHAN_ADD		f_pConfBridgeAdd )
{
	f_pConfBridgeAdd->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeAdd->ulChannelHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeAdd->ulInputPort = cOCT6100_CHANNEL_PORT_SOUT;
	f_pConfBridgeAdd->ulListenerMaskIndex = cOCT6100_INVALID_VALUE;
	f_pConfBridgeAdd->ulListenerMask = 0;
	f_pConfBridgeAdd->fMute = FALSE;
	f_pConfBridgeAdd->ulTappedChannelHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK;
}


UINT32 Oct6100ConfBridgeChanAdd(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_CHAN_ADD		f_pConfBridgeAdd )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeChanAddSer( f_pApiInstance, f_pConfBridgeAdd );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanRemove

Description:    This function removes an echo channel (participant) from a 
				conference bridge.  All participants can be removed from
				the bridge if a special flag (fRemoveAll) is set to TRUE.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeRemove		Pointer to conference bridge channel removal structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanRemoveDef(
				tPOCT6100_CONF_BRIDGE_CHAN_REMOVE	f_pConfBridgeRemove )
{
	f_pConfBridgeRemove->ulChannelHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeRemove->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeRemove->fRemoveAll = FALSE;

	return cOCT6100_ERR_OK;
}


UINT32 Oct6100ConfBridgeChanRemove(
			tPOCT6100_INSTANCE_API				f_pApiInstance,
			tPOCT6100_CONF_BRIDGE_CHAN_REMOVE	f_pConfBridgeRemove )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure.*/
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, f_pConfBridgeRemove );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanMute

Description:    This function mutes a participant present on a conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeMute		Pointer to conference bridge channel mute structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanMuteDef(
				tPOCT6100_CONF_BRIDGE_CHAN_MUTE		f_pConfBridgeMute )
{
	f_pConfBridgeMute->ulChannelHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK; 
}


UINT32 Oct6100ConfBridgeChanMute(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_CHAN_MUTE		f_pConfBridgeMute )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeChanMuteSer( f_pApiInstance, f_pConfBridgeMute );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanUnMute

Description:    This function unmutes a channel on a bridge. The other member 
				of the conference will start to hear this participant again.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeUnMute		Pointer to conference bridge channel unmute structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanUnMuteDef(
				tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE	f_pConfBridgeUnMute )
{
	f_pConfBridgeUnMute->ulChannelHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK;
}

UINT32 Oct6100ConfBridgeChanUnMute(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE	f_pConfBridgeUnMute )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure.*/
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeChanUnMuteSer( f_pApiInstance, f_pConfBridgeUnMute );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeDominantSpeakerSet

Description:    This function sets a participant present on a conference 
				bridge as the dominant speaker.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to 
						keep the present state of the chip and all its 
						resources.

f_pConfBridgeDominant	Pointer to conference bridge dominant speaker 
						structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeDominantSpeakerSetDef(
				tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET	f_pConfBridgeDominantSpeaker )
{
	f_pConfBridgeDominantSpeaker->ulChannelHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeDominantSpeaker->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK; 
}


UINT32 Oct6100ConfBridgeDominantSpeakerSet(
				tPOCT6100_INSTANCE_API						f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET	f_pConfBridgeDominantSpeaker )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure.*/
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeDominantSpeakerSetSer( f_pApiInstance, f_pConfBridgeDominantSpeaker );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeMaskChange

Description:    This function changes the mask of a flexible bridge participant.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to 
							keep the present state of the chip and all its 
							resources.

f_pConfBridgeMaskChange		Pointer to conference bridge change of mask 
							structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeMaskChangeDef(
				tPOCT6100_CONF_BRIDGE_MASK_CHANGE			f_pConfBridgeMaskChange )
{
	f_pConfBridgeMaskChange->ulChannelHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeMaskChange->ulNewListenerMask = 0x0;

	return cOCT6100_ERR_OK; 
}


UINT32 Oct6100ConfBridgeMaskChange(
				tPOCT6100_INSTANCE_API						f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_MASK_CHANGE			f_pConfBridgeMaskChange )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeMaskChangeSer( f_pApiInstance, f_pConfBridgeMaskChange );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeGetStats

Description:    This function returns the stats for a conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeStats		Pointer to conference bridge channel stats structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeGetStatsDef(
				tPOCT6100_CONF_BRIDGE_STATS			f_pConfBridgeStats )
{
	f_pConfBridgeStats->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;
	f_pConfBridgeStats->ulNumChannels = cOCT6100_INVALID_STAT;
	f_pConfBridgeStats->ulNumTappedChannels = cOCT6100_INVALID_STAT;
	f_pConfBridgeStats->fFlexibleConferencing = cOCT6100_INVALID_STAT;

	return cOCT6100_ERR_OK;
}


UINT32 Oct6100ConfBridgeGetStats(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_CONF_BRIDGE_STATS			f_pConfBridgeStats )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100ConfBridgeGetStatsSer( f_pApiInstance, f_pConfBridgeStats );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}

/****************************  PRIVATE FUNCTIONS  ****************************/


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiGetConfBridgeSwSizes

Description:    Gets the sizes of all portions of the API instance pertinent
				to the management of conference bridges.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pOpenChip				Pointer to chip configuration struct.
f_pInstSizes			Pointer to struct containing instance sizes.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiGetConfBridgeSwSizes(
				IN		tPOCT6100_CHIP_OPEN				f_pOpenChip,
				OUT		tPOCT6100_API_INSTANCE_SIZES	f_pInstSizes )
{
	UINT32	ulTempVar;
	UINT32	ulResult;

	/* Calculate memory needed for conference bridge list. */
	if ( f_pOpenChip->ulMaxConfBridges == 0 && f_pOpenChip->fEnableChannelRecording == TRUE )
		f_pOpenChip->ulMaxConfBridges = 1;
	f_pInstSizes->ulConfBridgeList = f_pOpenChip->ulMaxConfBridges * sizeof( tOCT6100_API_CONF_BRIDGE );
	
	/* Calculate memory needed for conference bridge allocation software. */
	if ( f_pOpenChip->ulMaxConfBridges > 0 )
	{
		/* Get size of bridge allocation memory */
		ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxConfBridges, &f_pInstSizes->ulConfBridgeAlloc );
		if ( ulResult != cOCT6100_ERR_OK )
			return cOCT6100_ERR_FATAL_1C;

		/* Check if the user wants to build flexible conference bridges. */
		if ( f_pOpenChip->ulMaxFlexibleConfParticipants > 0 )
		{
			/* Allocate the lowest quantity according to what the user requested. */
			if ( f_pOpenChip->ulMaxFlexibleConfParticipants < ( f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ) )
				f_pInstSizes->ulFlexConfParticipantsList = f_pOpenChip->ulMaxFlexibleConfParticipants * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT );
			else
			{
				f_pOpenChip->ulMaxFlexibleConfParticipants = f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE;
				f_pInstSizes->ulFlexConfParticipantsList = f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT );
			}

			/* Get size of flexible conferencing participants allocation memory */
			ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxFlexibleConfParticipants, &f_pInstSizes->ulFlexConfParticipantsAlloc );
			if ( ulResult != cOCT6100_ERR_OK )
				return cOCT6100_ERR_FATAL_1C;
		}
		else
		{
			f_pInstSizes->ulFlexConfParticipantsList  = 0;
			f_pInstSizes->ulFlexConfParticipantsAlloc  = 0;
		}
	}
	else
	{
		f_pInstSizes->ulMixerEventList = 0;		
		f_pInstSizes->ulMixerEventAlloc  = 0;
		f_pInstSizes->ulConfBridgeAlloc  = 0;

		/* Make sure flexible conferencing is not used. */
		f_pInstSizes->ulFlexConfParticipantsList  = 0;
		f_pInstSizes->ulFlexConfParticipantsAlloc  = 0;
	}

	/* Calculate memory needed for list and allocation software serialization. */
	mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulConfBridgeList, ulTempVar )
	mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulConfBridgeAlloc, ulTempVar )

	mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulFlexConfParticipantsList, ulTempVar )
	mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulFlexConfParticipantsAlloc, ulTempVar )

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiConfBridgeSwInit

Description:    Initializes all elements of the instance structure associated
				to conference bridges.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep
						the present state of the chip and all its resources.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiConfBridgeSwInit(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance )
{
	tPOCT6100_SHARED_INFO				pSharedInfo;
	tPOCT6100_API_CONF_BRIDGE			pConfBridgeList;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT	pFlexConfParticipantList;
	PVOID	pFlexConfPartipantsAlloc;
	UINT32	ulMaxFlexConfParicipants;
	PVOID	pConfBridgeAlloc;
	UINT32	ulMaxConfBridges;
	UINT32	ulResult;

	/* Get local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	/* Get the maximum number of conference bridges. */
	ulMaxConfBridges = pSharedInfo->ChipConfig.usMaxConfBridges;
	
	/*===================================================================*/
	/* Set all entries in the conference bridge list to unused. */

	mOCT6100_GET_CONF_BRIDGE_LIST_PNT( pSharedInfo, pConfBridgeList );

	/* Initialize the conference bridge allocation software to "all free". */
	if ( ulMaxConfBridges > 0 )
	{
		/* Clear the bridge memory */	
		Oct6100UserMemSet( pConfBridgeList, 0x00, ulMaxConfBridges * sizeof( tOCT6100_API_CONF_BRIDGE ));

		mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( pSharedInfo, pConfBridgeAlloc )
		
		ulResult = OctapiLlmAllocInit( &pConfBridgeAlloc, ulMaxConfBridges );
		if ( ulResult != cOCT6100_ERR_OK )
			return cOCT6100_ERR_FATAL_1E;
	}
	/*===================================================================*/


	/*===================================================================*/
	/* Set all entries in the flexible conferencing participant list to unused. */

	/* Get the maximum number of flexible conferencing participants. */
	ulMaxFlexConfParicipants = pSharedInfo->ChipConfig.usMaxFlexibleConfParticipants;

	mOCT6100_GET_FLEX_CONF_PARTICIPANT_LIST_PNT( pSharedInfo, pFlexConfParticipantList );

	/* Initialize the flexible conferencing allocation software. */
	if ( ulMaxFlexConfParicipants > 0 )
	{
		UINT32 i, ulEventIndex;
		
		/* Clear the participants memory */	
		Oct6100UserMemSet( pFlexConfParticipantList, 0x00, ulMaxFlexConfParicipants * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT ));

		mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( pSharedInfo, pFlexConfPartipantsAlloc )
		
		ulResult = OctapiLlmAllocInit( &pFlexConfPartipantsAlloc, ulMaxFlexConfParicipants );
		if ( ulResult != cOCT6100_ERR_OK )
			return cOCT6100_ERR_FATAL_1E;

		/* Initialize the conferencing indexes. */
		for ( i = 0; i < ulMaxFlexConfParicipants; i ++ )
		{
			for ( ulEventIndex = 0; ulEventIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulEventIndex ++ )
				pFlexConfParticipantList[ i ].ausLoadOrAccumulateEventIndex[ ulEventIndex ] = cOCT6100_INVALID_INDEX;
		}
	}
	
	/*===================================================================*/
	
	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeOpenSer

Description:    Open a conference bridge. Note that no chip resources are 
				allocated until a channel is added to the bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeOpen		Pointer to conference bridge configuration structure.  
						The handle identifying the conference bridge in all 
						future function calls is returned in this structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeOpenSer(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN OUT	tPOCT6100_CONF_BRIDGE_OPEN		f_pConfBridgeOpen )
{
	UINT16	usBridgeIndex;
	UINT32	ulResult;

	/* Check the user's configuration of the conference bridge for errors. */
	ulResult = Oct6100ApiCheckBridgeParams( f_pApiInstance, f_pConfBridgeOpen );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Reserve all resources needed by the conference bridge. */
	ulResult = Oct6100ApiReserveBridgeResources( f_pApiInstance, &usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Update the new conference bridge's entry in the conference bridge list. */
	ulResult = Oct6100ApiUpdateBridgeEntry( f_pApiInstance, f_pConfBridgeOpen, usBridgeIndex);
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeParams

Description:    Checks the user's conference bridge open configuration for errors.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeOpen		Pointer to conference bridge configuration structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeParams(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_OPEN		f_pConfBridgeOpen )
{
	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;
	
	if ( f_pConfBridgeOpen->pulConfBridgeHndl == NULL )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;
	
	if ( f_pApiInstance->pSharedInfo->ImageInfo.fConferencing == FALSE )
		return cOCT6100_ERR_NOT_SUPPORTED_CONF_BRIDGE;

	if ( f_pConfBridgeOpen->fFlexibleConferencing != FALSE
		&& f_pConfBridgeOpen->fFlexibleConferencing != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReserveBridgeResources

Description:    Reserves all resources needed for the new conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.
	
f_pusBridgeIndex		Allocated entry in the API conference bridge list.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReserveBridgeResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				OUT		PUINT16							f_pusBridgeIndex )
{
	tPOCT6100_SHARED_INFO	pSharedInfo;
	UINT32	ulResult;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	/* Reserve an entry in the conference bridge list. */
	ulResult = Oct6100ApiReserveBridgeEntry( f_pApiInstance, f_pusBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiUpdateBridgeEntry

Description:    Updates the new conference bridge's entry in the conference 
				bridge list.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep
						the present state of the chip and all its resources.

f_pConfBridgeOpen		Pointer to conference bridge configuration structure.
f_usBridgeIndex			Allocated entry in API conference bridge list.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiUpdateBridgeEntry(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN OUT	tPOCT6100_CONF_BRIDGE_OPEN		f_pConfBridgeOpen,
				IN		UINT16							f_usBridgeIndex )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_CONF_BRIDGE	pTempBridgeEntry;

	/*================================================================================*/
	/* Obtain a pointer to the new conference bridge's list entry. */

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex )

	/* No clients are currently connected to the bridge. */
	pBridgeEntry->usNumClients = 0;
	/* Nobody is tapped for now. */
	pBridgeEntry->usNumTappedClients = 0;
	pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX;
	pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX;
	pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX;

	pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX;

	pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX;

	/* Now update the bridge pointer. */
	if ( f_pApiInstance->pSharedInfo->MiscVars.usNumBridgesOpened == 0 )
	{
		pBridgeEntry->usNextBridgePtr = cOCT6100_INVALID_INDEX;
		pBridgeEntry->usPrevBridgePtr = cOCT6100_INVALID_INDEX;

		/* Set the global first bridge to this bridge. */
		f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge = f_usBridgeIndex;
	}
	else	/* Insert this bridge at the head of the bridge list.*/
	{
		if ( f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_FATAL_22;

		mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge )
	
		if ( pTempBridgeEntry->fReserved != TRUE )
			return cOCT6100_ERR_FATAL_23;

		/* Modify the old first entry. */
		pTempBridgeEntry->usPrevBridgePtr = f_usBridgeIndex;

		/* Modify current pointer. */
		pBridgeEntry->usPrevBridgePtr = cOCT6100_INVALID_INDEX;
		pBridgeEntry->usNextBridgePtr = f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge;

		/* Set the new first bridge of the list. */
		f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge = f_usBridgeIndex;
	}

	/* Form handle returned to user. */
	*f_pConfBridgeOpen->pulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pBridgeEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usBridgeIndex;

	/* Remember whether or not we are a flexible conference bridge. */
	pBridgeEntry->fFlexibleConferencing = (UINT8)( f_pConfBridgeOpen->fFlexibleConferencing & 0xFF );

	/* Finally, mark the conference bridge as opened. */
	pBridgeEntry->fReserved = TRUE;
	
	/* Increment the number of conference bridge opened. */
	f_pApiInstance->pSharedInfo->ChipStats.usNumberConfBridges++;
	f_pApiInstance->pSharedInfo->MiscVars.usNumBridgesOpened++;

	/*================================================================================*/

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeCloseSer

Description:    Closes a conference bridge. Note that no client must be present
				on the bridge for the bridge to be closed.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeClose		Pointer to conference bridge close structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeCloseSer(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CLOSE			f_pConfBridgeClose )
{
	UINT16	usBridgeIndex;
	UINT32	ulResult;

	/* Verify that all the parameters given match the state of the API. */
	ulResult = Oct6100ApiAssertBridgeParams( f_pApiInstance, f_pConfBridgeClose, &usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK  )
		return ulResult;

	/* Release all resources associated to the conference bridge. */
	ulResult = Oct6100ApiReleaseBridgeResources( f_pApiInstance, usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK  )
		return ulResult;

	/* Invalidate the handle. */
	f_pConfBridgeClose->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiAssertBridgeParams

Description:    Checks the user's conference bridge close configuration for errors.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeClose		Pointer to conference bridge close structure.
f_pusBridgeIndex		Pointer to API instance conference bridge index.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiAssertBridgeParams(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CLOSE			f_pConfBridgeClose,
				OUT		PUINT16								f_pusBridgeIndex )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	UINT32						ulEntryOpenCnt;

	/* Check the provided handle. */
	if ( (f_pConfBridgeClose->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	*f_pusBridgeIndex = (UINT16)( f_pConfBridgeClose->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeClose->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( pBridgeEntry->usNumClients != 0 )
		return cOCT6100_ERR_CONF_BRIDGE_ACTIVE_DEPENDENCIES;
	if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReleaseBridgeResources

Description:    Release all resources reserved for the conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_usBridgeIndex			Allocated external memory block for the conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReleaseBridgeResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex )
{
	tPOCT6100_SHARED_INFO		pSharedInfo;
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_CONF_BRIDGE	pTempBridgeEntry;
	UINT32	ulResult;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	/* Release the entry from the conference bridge list. */
	ulResult = Oct6100ApiReleaseBridgeEntry( f_pApiInstance, f_usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return cOCT6100_ERR_FATAL_24;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex );

	/* Remove the bridge entry from the bridge list. */
	if ( pSharedInfo->MiscVars.usNumBridgesOpened == 1 )
	{
		/* This bridge was the only one opened. */
		pSharedInfo->MiscVars.usFirstBridge = cOCT6100_INVALID_INDEX;
	}
	else if ( pSharedInfo->MiscVars.usNumBridgesOpened > 1 )
	{
		/* There are more then one bridge open, must update the list. */
		if ( pBridgeEntry->usPrevBridgePtr != cOCT6100_INVALID_INDEX )
		{
			/* There is a valid entry before this bridge, let's update this entry. */
			mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, pBridgeEntry->usPrevBridgePtr );
			
			pTempBridgeEntry->usNextBridgePtr = pBridgeEntry->usNextBridgePtr;
		}

		if ( pBridgeEntry->usNextBridgePtr != cOCT6100_INVALID_INDEX )
		{
			/* There is a valid entry after this bridge, let's update this entry. */
			mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, pBridgeEntry->usNextBridgePtr );

			pTempBridgeEntry->usPrevBridgePtr = pBridgeEntry->usPrevBridgePtr;
		}

		if ( pSharedInfo->MiscVars.usFirstBridge == f_usBridgeIndex )
		{
			/* This entry was the first of the list, make the next one be the first now. */
			pSharedInfo->MiscVars.usFirstBridge = pBridgeEntry->usNextBridgePtr;
		}
	}
	else
	{
		/* Variable has become out of sync. */
		return cOCT6100_ERR_FATAL_25;
	}

	/*=============================================================*/
	/* Update the conference bridge's list entry. */

	/* Mark the bridge as closed. */
	pBridgeEntry->fFlexibleConferencing = FALSE;
	pBridgeEntry->fReserved = FALSE;
	pBridgeEntry->byEntryOpenCnt++;

	/* Decrement the number of conference bridges opened. */
	pSharedInfo->MiscVars.usNumBridgesOpened--;
	pSharedInfo->ChipStats.usNumberConfBridges--;

	/*=============================================================*/

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanAddSer

Description:    Adds an echo channel (participant) to a conference bridge. 

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeAdd		Pointer to conference bridge channel add structure.  

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanAddSer(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_ADD	f_pConfBridgeAdd )
{
	UINT16	usBridgeIndex;
	UINT16	usChanIndex;
	UINT16	usLoadEventIndex;
	UINT16	usSubStoreEventIndex;
	UINT16	usCopyEventIndex;
	UINT32	ulInputPort;
	UINT8	fFlexibleConfBridge;
	UINT32	ulListenerMaskIndex;
	UINT32	ulListenerMask;
	UINT16	usTapChanIndex;
	UINT16	usTapBridgeIndex;
	UINT8	fMute;
	UINT8	fTap;
	UINT32	ulResult;

	/* Check the validity of the channel and conference bridge given. */
	ulResult = Oct6100ApiCheckBridgeAddParams( 
									f_pApiInstance, 
									f_pConfBridgeAdd, 
									&usBridgeIndex, 
									&usChanIndex, 
									&fMute, 
									&ulInputPort, 
									&fFlexibleConfBridge, 
									&ulListenerMaskIndex, 
									&ulListenerMask,
									&fTap,
									&usTapChanIndex );
	if ( ulResult != cOCT6100_ERR_OK  )
		return ulResult;

	/* Reserve all resources needed by the conference bridge. */
	ulResult = Oct6100ApiReserveBridgeAddResources( 
									f_pApiInstance, 
									usBridgeIndex, 
									usChanIndex, 
									ulInputPort, 
									fFlexibleConfBridge, 
									ulListenerMaskIndex, 
									ulListenerMask,
									fTap,
									&usLoadEventIndex, 
									&usSubStoreEventIndex, 
									&usCopyEventIndex,
									&usTapBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Reserve all resources needed by the conference bridge. */
	ulResult = Oct6100ApiBridgeEventAdd( 
									f_pApiInstance, 
									usBridgeIndex, 
									usChanIndex, 
									fFlexibleConfBridge, 
									usLoadEventIndex, 
									usSubStoreEventIndex, 
									usCopyEventIndex, 
									ulInputPort, 
									fMute, 
									ulListenerMaskIndex, 
									ulListenerMask,
									fTap,
									usTapBridgeIndex,
									usTapChanIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeAddParams

Description:	Check the validity of the channel and conference bridge given.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.
f_pConfBridgeAdd		Pointer to conference bridge channenl add structure.  
f_pusBridgeIndex		Extracted bridge index where this channel should be 
						added.
f_pusChannelIndex		Extracted channel index related to the channel handle
						to be added to the bridge.
f_pfMute				Whether to mute this channel in the bridge or not.
f_pulInputPort			Input port where the channel signal should be
						copied from.
f_pfFlexibleConfBridge	If this is a flexible conference bridge.
f_pulListenerMaskIndex	Index of the listener in this flexible conference bridge.
f_pulListenerMask		Mask of listeners in this flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeAddParams(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_ADD		f_pConfBridgeAdd,
				OUT		PUINT16								f_pusBridgeIndex, 
				OUT		PUINT16								f_pusChannelIndex,
				OUT		PUINT8								f_pfMute,
				OUT		PUINT32								f_pulInputPort, 
				OUT		PUINT8								f_pfFlexibleConfBridge,
				OUT		PUINT32								f_pulListenerMaskIndex,
				OUT		PUINT32								f_pulListenerMask,
				OUT		PUINT8								f_pfTap,
				OUT		PUINT16								f_pusTapChannelIndex )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_CHANNEL		pEchoChanEntry;
	UINT32	ulEntryOpenCnt;
	UINT8	byTapChannelLaw;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;

	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 1 &&
		 f_pApiInstance->pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;

	if ( f_pConfBridgeAdd->ulConfBridgeHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	if ( f_pConfBridgeAdd->ulChannelHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE;
	
	if( f_pConfBridgeAdd->ulInputPort != cOCT6100_CHANNEL_PORT_SOUT
		&& f_pConfBridgeAdd->ulInputPort != cOCT6100_CHANNEL_PORT_RIN )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_INPUT_PORT;

	if ( f_pConfBridgeAdd->fMute != TRUE && f_pConfBridgeAdd->fMute != FALSE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_MUTE;

	/*=====================================================================*/
	/* Check the conference bridge handle. */

	if ( (f_pConfBridgeAdd->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	*f_pusBridgeIndex = (UINT16)( f_pConfBridgeAdd->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeAdd->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/* When we a flexible conference bridge, more things need to be checked. */
	if ( pBridgeEntry->fFlexibleConferencing == TRUE )
	{
		/* Check if flexible conferencing has been activated. */
		if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxFlexibleConfParticipants == 0 )
			return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_DISABLED;

		/* Check the number of clients on the bridge. */
		if ( pBridgeEntry->usNumClients >= cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE )
			return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_PARTICIPANT_CNT;

		/* Check if the listener index in a flexible bridge is valid. */
		if ( f_pConfBridgeAdd->ulListenerMaskIndex == cOCT6100_INVALID_VALUE
			|| f_pConfBridgeAdd->ulListenerMaskIndex >= cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE )
			return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_MASK_INDEX;
	}

	if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE )
	{
		if ( pBridgeEntry->fFlexibleConferencing == TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_TAP_NOT_SUPPORTED;
	}

	/*=====================================================================*/
	

	/*=====================================================================*/
	/* Check the channel handle. */

	if ( (f_pConfBridgeAdd->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE;

	*f_pusChannelIndex = (UINT16)( f_pConfBridgeAdd->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeAdd->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pEchoChanEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;
	if ( pEchoChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ALREADY_ON_BRIDGE;
	if ( pEchoChanEntry->fBiDirChannel == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_BIDIR;
	/* Law conversion is not allowed on a conference bridge. */
	if ( ( pEchoChanEntry->TdmConfig.usRinTimeslot != cOCT6100_UNASSIGNED )
		&& ( pEchoChanEntry->TdmConfig.usRoutTimeslot != cOCT6100_UNASSIGNED ) )
	{
		if ( pEchoChanEntry->TdmConfig.byRinPcmLaw != pEchoChanEntry->TdmConfig.byRoutPcmLaw )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_LAW_CONVERSION;
	}
	if ( ( pEchoChanEntry->TdmConfig.usSinTimeslot != cOCT6100_UNASSIGNED )
		&& ( pEchoChanEntry->TdmConfig.usSoutTimeslot != cOCT6100_UNASSIGNED ) )
	{
		if ( pEchoChanEntry->TdmConfig.bySinPcmLaw != pEchoChanEntry->TdmConfig.bySoutPcmLaw )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_LAW_CONVERSION;
	}
	if ( pEchoChanEntry->fRinRoutCodecActive == TRUE || pEchoChanEntry->fSinSoutCodecActive == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_CODEC_ACTIVE;
	if ( pEchoChanEntry->fEnableExtToneDetection == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_EXT_TONE_ENABLED;
	if ( pEchoChanEntry->usCopyEventCnt != 0x0 )
		return cOCT6100_ERR_CONF_BRIDGE_COPY_EVENTS;

	/* If the bridge is flexible, few more things need to be checked. */
	if ( pBridgeEntry->fFlexibleConferencing == TRUE )
	{
		tPOCT6100_SHARED_INFO	pSharedInfo;
		UINT16					usChannelIndex;
		UINT32					ulResult = cOCT6100_ERR_OK;

		/* Obtain local pointer to shared portion of instance. */
		pSharedInfo = f_pApiInstance->pSharedInfo;

		/* Check if the listener index has been used by another channel in the specified bridge. */
		for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usChannelIndex );
			
			/* Channel reserved? */
			if ( ( usChannelIndex != ( *f_pusChannelIndex ) ) && ( pEchoChanEntry->fReserved == TRUE ) )
			{
				/* On current bridge? */
				if ( pEchoChanEntry->usBridgeIndex == ( *f_pusBridgeIndex ) )
				{
					tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant;

					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

					/* Check if this participant has the same listener index. */
					if ( f_pConfBridgeAdd->ulListenerMaskIndex == pCurrentParticipant->ulListenerMaskIndex )
						return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_INDEX_USED;
				}
			}
		}
	}

	if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE )
	{
		/* For internal logic, make sure the mute flag is set to false. */
		f_pConfBridgeAdd->fMute = FALSE;

		/* Force input port to Sout for logic below. */
		f_pConfBridgeAdd->ulInputPort = cOCT6100_CHANNEL_PORT_SOUT;

		/* Keep law to check for conversion. */
		/* Check if the same law. */
		byTapChannelLaw = pEchoChanEntry->TdmConfig.bySoutPcmLaw;

		/* Check the tap handle. */
		if ( (f_pConfBridgeAdd->ulTappedChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE;

		*f_pusTapChannelIndex = (UINT16)( f_pConfBridgeAdd->ulTappedChannelHndl & cOCT6100_HNDL_INDEX_MASK );
		if ( *f_pusTapChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE;

		mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusTapChannelIndex )

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = (f_pConfBridgeAdd->ulTappedChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

		/* Check for errors. */
		if ( pEchoChanEntry->fReserved != TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
		if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE;
		if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_BRIDGE;
		if ( pEchoChanEntry->usBridgeIndex != *f_pusBridgeIndex )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_SAME_BRIDGE;

		/* We can only tap a channel added on the Sout port. */
		if ( pEchoChanEntry->usSinCopyEventIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_TAP_SOUT_ONLY;

		/* Check if already tapped. */
		if ( pEchoChanEntry->fBeingTapped == TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_ALREADY_TAPPED;
	}

	/*=====================================================================*/

	/* Return the tap flag. */
	if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE )
	{
		*f_pfTap = TRUE;
	}
	else
	{
		*f_pfTap = FALSE;
	}

	/* Return the mute config specified. */
	*f_pfMute = (UINT8)( f_pConfBridgeAdd->fMute & 0xFF );

	/* Return the input port specified. */
	*f_pulInputPort = f_pConfBridgeAdd->ulInputPort;

	/* Return whether we are in the flexible conference bridge case. */
	*f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing;

	/* Return the listener mask index as specified. */
	*f_pulListenerMaskIndex = f_pConfBridgeAdd->ulListenerMaskIndex;

	/* Return the listener mask as specified. */
	*f_pulListenerMask = f_pConfBridgeAdd->ulListenerMask;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReserveBridgeAddResources

Description:    Reserves all resources needed for the addition of a channel to 
				the conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_usBridgeIndex				Bridge index of the bridge where this channel is added.
f_usChanIndex				Channel index of the channel to be added to the bridge.
f_ulInputPort				Input port where to copy samples from.
f_fFlexibleConfBridge		If this is a flexible conference bridge.
f_ulListenerMaskIndex		Index of the listener in this flexible conference bridge.
f_ulListenerMask			Mask of listeners in this flexible conference bridge.
f_pusLoadEventIndex			Load event index within the API's list of mixer event.
f_pusSubStoreEventIndex		Sub-Store event index within the API's list of mixer event.
f_pusCopyEventIndex			Copy event index within the API's list of mixer event.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReserveBridgeAddResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex,
				IN		UINT16							f_usChanIndex,
				IN		UINT32							f_ulInputPort,
				IN		UINT8							f_fFlexibleConfBridge,
				IN		UINT32							f_ulListenerMaskIndex,
				IN		UINT32							f_ulListenerMask,
				IN		UINT8							f_fTap,
				OUT		PUINT16							f_pusLoadEventIndex,
				OUT		PUINT16							f_pusSubStoreEventIndex,
				OUT		PUINT16							f_pusCopyEventIndex,
				OUT		PUINT16							f_pusTapBridgeIndex )
{
	tPOCT6100_API_CHANNEL			pChanEntry;
	tPOCT6100_SHARED_INFO			pSharedInfo;
	tPOCT6100_API_CHANNEL			pTempEchoChanEntry;
	UINT32	ulResult;
	UINT32	ulTempVar;
	UINT16	usChannelIndex;
	BOOL	fLoadEventReserved = FALSE;
	BOOL	fStoreEventReserved = FALSE;
	BOOL	fCopyEventReserved = FALSE;
	BOOL	fExtraSinTsiReserved = FALSE;
	BOOL	fExtraRinTsiReserved = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	/* Get a pointer to the channel's list entry. */
	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex )

	/* Resources must be reserved according to the type of bridge we are adding to. */
	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pNewParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant;

		/*========================================================================*/
		/* If we are in the flexible conferencing case, things are a little       */
		/* different.  We create a mixer for every participant instead of the     */
		/* usual same mixer for everyone.  For example, if we have 3 participants */
		/* of type client - agent - coach, we build the mixers as follows:        */
		/*                                                                        */
		/*   Client:            - Load Agent                                      */
		/*                      - Store                                           */
		/*                                                                        */
		/*   Agent:             - Load Client                                     */
		/*                      - Accumulate Coach                                */
		/*                      - Store                                           */
		/*                                                                        */
		/*   Coach:             - Load Client                                     */
		/*                      - Accumulate Agent                                */
		/*                      - Store                                           */
		/*                                                                        */
		/*========================================================================*/

		/* First reserve a flexible conferencing participant entry. */
		ulResult = Oct6100ApiReserveFlexConfParticipantEntry( f_pApiInstance, &pChanEntry->usFlexConfParticipantIndex );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pNewParticipant, pChanEntry->usFlexConfParticipantIndex );

		/* Reserve an entry for the store event in the mixer memory. */
		ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusSubStoreEventIndex );
		if ( ulResult == cOCT6100_ERR_OK )
		{
			/* If using the SOUT port, we must copy this entry */
			if( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
			{
				/* Reserve an entry for the copy event in the Mixer memory. */
				ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusCopyEventIndex );
				if ( ulResult == cOCT6100_ERR_OK )
				{
					fCopyEventReserved = TRUE;

					/* Reserve a SIN copy entry if none were reserved before.*/
					if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX )
					{
						/* Reserve an entry for the extra tsi chariot memory. */
						ulResult = Oct6100ApiReserveTsiMemEntry(	f_pApiInstance, 
																	&pChanEntry->usExtraSinTsiMemIndex );
						if ( ulResult == cOCT6100_ERR_OK )
							fExtraSinTsiReserved = TRUE;
					}
				}
			}
			else /* if( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
			{
				/* Reserve a RIN copy entry if none were reserved before.*/
				if ( pChanEntry->usExtraRinTsiMemIndex == cOCT6100_INVALID_INDEX )
				{
					/* Reserve an entry for the extra tsi chariot memory. */
					ulResult = Oct6100ApiReserveTsiMemEntry(	f_pApiInstance, 
																&pChanEntry->usExtraRinTsiMemIndex );
					if ( ulResult == cOCT6100_ERR_OK )
						fExtraRinTsiReserved = TRUE;
				}				
			}

			/* Must travel all clients of this conference and reserve a load or accumulate event for */
			/* all participants which can hear us. */

			/* Search through the list of API channel entry for the ones on to this bridge.*/
			for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
				
				/* Channel reserved? */
				if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
				{
					/* On current bridge? */
					if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
					{
						mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

						/* Check if we can hear this participant. */
						if ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 )
						{
							/* Must reserve a load or accumulate entry mixer event here! */
							ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								/* Most probably, the hardware is out of mixer events. */
								break;
							}
						}

						/* Check if this participant can hear us. */
						if ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 )
						{
							/* Must reserve a load or accumulate entry mixer event here! */
							ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								/* Most probably, the hardware is out of mixer events. */
								break;
							}
						}
					}
				}
			}

			/* If an error is returned, make sure everything is cleaned up properly. */
			if ( ulResult != cOCT6100_ERR_OK )
			{
				/* Release the flexible conferencing participant entry. */
				ulTempVar = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pChanEntry->usFlexConfParticipantIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;
				
				pChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX;

				/* Release the substore event in the mixer memory. */
				ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusSubStoreEventIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;

				if ( fCopyEventReserved == TRUE )
				{
					/* Release the copy event in the mixer memory. */
					ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusCopyEventIndex );
					if ( ulTempVar != cOCT6100_ERR_OK )
						return ulTempVar;
				}

				if ( fExtraSinTsiReserved == TRUE )
				{
					/* Release the extra Sin TSI in TSI memory. */
					ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraSinTsiMemIndex );
					if ( ulTempVar != cOCT6100_ERR_OK )
						return ulTempVar;

					pChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
				}

				if ( fExtraRinTsiReserved == TRUE )
				{
					/* Release the extra Rin TSI in TSI memory. */
					ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraRinTsiMemIndex );
					if ( ulTempVar != cOCT6100_ERR_OK )
						return ulTempVar;

					pChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX;
				}
				
				/* Search through the list of API channel entry for the ones on to this bridge. */
				for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
				{
					mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
					
					/* Channel reserved? */
					if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
					{
						/* On current bridge? */
						if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
						{
							mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

							/* Check if we can hear this participant. */
							if ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 )
							{
								/* If the load or event entry in the mixer memory was reserved. */
								if ( pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX )
								{
									/* Must release the load or accumulate entry mixer event. */
									ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] );
									if ( ulTempVar != cOCT6100_ERR_OK )
										return ulTempVar;

									pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
								}
							}

							/* Check this participant can hear us. */
							if ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 )
							{
								/* If the load or event entry in the mixer memory was reserved. */
								if ( pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX )
								{
									/* Must release the load or accumulate entry mixer event. */
									ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] );
									if ( ulTempVar != cOCT6100_ERR_OK )
										return ulTempVar;

									pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
								}
							}
						}
					}
				}

				return ulResult;
			}
		}
		else /* if ( ulResult != cOCT6100_ERR_OK ) */
		{
			ulTempVar = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pChanEntry->usFlexConfParticipantIndex );
			if ( ulTempVar != cOCT6100_ERR_OK )
				return ulTempVar;

			pChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX;
			
			/* Return the error code to the user.  The mixer event allocation failed. */
			return ulResult;
		}

		/*=======================================================================*/
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		/*=======================================================================*/
		/* Normal conferencing. */		

		/* Reserve an entry for the load event in the mixer memory. */
		ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusLoadEventIndex );
		if ( ulResult == cOCT6100_ERR_OK )
		{
			fLoadEventReserved = TRUE;
			/* Reserve an entry for the substract and store event in the mixer memory. */
			ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusSubStoreEventIndex );
			if ( ulResult == cOCT6100_ERR_OK )
			{
				fStoreEventReserved = TRUE;

				/* If using the SOUT port, we must copy this entry */
				if( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
				{
					/* Reserve an entry for the copy event in the mixer memory. */
					ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusCopyEventIndex );
					if ( ulResult == cOCT6100_ERR_OK )
					{
						fCopyEventReserved = TRUE;

						/* Reserve a SIN copy entry if none were reserved before. */
						if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX )
						{
							/* Reserve an entry for the extra tsi chariot memory. */
							ulResult = Oct6100ApiReserveTsiMemEntry(	f_pApiInstance, 
																		&pChanEntry->usExtraSinTsiMemIndex );

							if ( ulResult == cOCT6100_ERR_OK )
								fExtraSinTsiReserved = TRUE;
						}
					}
				}
			}
		}

		if ( ( ulResult == cOCT6100_ERR_OK ) && ( f_fTap == TRUE ) )
		{
			/* Reserve a "tap" bridge. */
			tOCT6100_CONF_BRIDGE_OPEN	ConfBridgeOpen;
			UINT32						ulTapBridgeHndl;

			Oct6100ConfBridgeOpenDef( &ConfBridgeOpen );

			ConfBridgeOpen.pulConfBridgeHndl = &ulTapBridgeHndl;

			ulResult = Oct6100ConfBridgeOpenSer( f_pApiInstance, &ConfBridgeOpen );

			*f_pusTapBridgeIndex = (UINT16)( ulTapBridgeHndl & cOCT6100_HNDL_INDEX_MASK );
		}

		if ( ulResult != cOCT6100_ERR_OK )
		{
			if ( fLoadEventReserved == TRUE )
			{
				ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusLoadEventIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;
			}
		
			if ( fStoreEventReserved == TRUE )
			{
				ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusSubStoreEventIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;
			}
			
			if ( fCopyEventReserved == TRUE )
			{
				ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusCopyEventIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;
			}

			if ( fExtraSinTsiReserved == TRUE )
			{
				ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraSinTsiMemIndex );
				if ( ulTempVar != cOCT6100_ERR_OK )
					return ulTempVar;

				pChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
			}

			return ulResult;
		}

		/*=======================================================================*/
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeEventAdd

Description:    Add the event into the global event list of the chip and update
				the bridge and channel structures.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to 
							keep the present state of the chip and all its 
							resources.
f_usBridgeIndex				Index of the current bridge in the API list.
f_usChanIndex				Index of the current channel in the API list.
f_fFlexibleConfBridge		If this is a flexible conference bridge.
f_usLoadEventIndex			Allocated entry for the Load event of the 
							channel.
f_usSubStoreEventIndex		Allocated entry for the substract and store 
							event of the channel.
f_usCopyEventIndex			Allocated entry for the copy event of the 
							channel.
f_ulInputPort				Input port where to copy samples from.
f_fMute						Mute flag indicating if the channel is added in 
							a mute state.
f_ulListenerMaskIndex		Index of the listener in this flexible conference bridge.
f_ulListenerMask			Mask of listeners in this flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiBridgeEventAdd(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex, 
				IN		UINT16							f_usChanIndex,
				IN		UINT8							f_fFlexibleConfBridge,
				IN		UINT16							f_usLoadEventIndex,
				IN		UINT16							f_usSubStoreEventIndex,
				IN		UINT16							f_usCopyEventIndex,
				IN		UINT32							f_ulInputPort,
				IN		UINT8							f_fMute, 
				IN		UINT32							f_ulListenerMaskIndex,
				IN		UINT32							f_ulListenerMask,
				IN		UINT8							f_fTap,
				IN		UINT16							f_usTapBridgeIndex,
				IN		UINT16							f_usTapChanIndex )
{
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT		pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT		pSubStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT		pTempEntry;

	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	tPOCT6100_API_CHANNEL			pTapEchoChanEntry = NULL;
	tPOCT6100_API_CHANNEL			pTempEchoChanEntry;

	tPOCT6100_SHARED_INFO			pSharedInfo;
	tOCT6100_WRITE_PARAMS			WriteParams;

	UINT32	ulResult;
	UINT16	usChannelIndex;
	UINT16	usLastSubStoreEventIndex;
	UINT16	usLastLoadEventIndex;

	BOOL	fAddSinCopy = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	/* Get the bridge and channel entries of interest. */
	if ( f_fTap == FALSE )
	{
		mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usBridgeIndex );
	}
	else
	{
		mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usTapBridgeIndex );
		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTapEchoChanEntry, f_usTapChanIndex );
	}
	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );

	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pNewParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant;

		mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pNewParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

		/* Search through the list of API channel entry for the ones onto this bridge. */
		for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
			
			/* Channel reserved? */
			if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
			{
				/* On current bridge? */
				if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
				{
					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

					/* Check if we can hear this participant. */
					if ( ( pTempEchoChanEntry->fMute == FALSE ) && ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 ) )
					{
						/* First create/update the current channel's mixer. */
						ulResult = Oct6100ApiBridgeAddParticipantToChannel(
													f_pApiInstance,
													f_usBridgeIndex,
													usChannelIndex,
													f_usChanIndex,
													pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ],
													f_usSubStoreEventIndex,
													f_usCopyEventIndex,
													pCurrentParticipant->ulInputPort,
													f_ulInputPort );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}

					/* Check if this participant can hear us. */
					if ( ( f_fMute == FALSE ) && ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 ) )
					{
						/* Then create/update this channel's mixer. */
						ulResult = Oct6100ApiBridgeAddParticipantToChannel(
													f_pApiInstance,
													f_usBridgeIndex,
													f_usChanIndex,
													usChannelIndex,
													pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ],
													pTempEchoChanEntry->usSubStoreEventIndex,
													pTempEchoChanEntry->usSinCopyEventIndex,
													f_ulInputPort,
													pCurrentParticipant->ulInputPort );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						/* Check if the Rin silence event can be cleared now that the */
						/* channel has been added to a conference. */
						if ( ( pCurrentParticipant->fFlexibleMixerCreated == TRUE )
							&& ( pTempEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) )
						{
							/* Remove the event from the list. */
							ulResult = Oct6100ApiMixerEventRemove(	f_pApiInstance,
																	pTempEchoChanEntry->usRinSilenceEventIndex,
																	cOCT6100_EVENT_TYPE_SOUT_COPY );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex );
							if ( ulResult != cOCT6100_ERR_OK  )
								return cOCT6100_ERR_FATAL_DF;

							pTempEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX;
						}
					}
				}
			}
		}

		/* Check if the mixer for the destination channel has been created. */
		if ( pNewParticipant->fFlexibleMixerCreated == FALSE )
		{
			/* Save store event index that might be used for next channel added. */
			pEchoChanEntry->usSubStoreEventIndex = f_usSubStoreEventIndex;
		}
		else
		{
			/* Check if the Rin silence event can be cleared now that the */
			/* channel has been added to a conference. */
			if ( pEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX )
			{
				/* Remove the event from the list.*/
				ulResult = Oct6100ApiMixerEventRemove(	f_pApiInstance,
														pEchoChanEntry->usRinSilenceEventIndex,
														cOCT6100_EVENT_TYPE_SOUT_COPY );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex );
				if ( ulResult != cOCT6100_ERR_OK )
					return cOCT6100_ERR_FATAL_DF;

				pEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX;
			}
		}

		pNewParticipant->ulListenerMaskIndex = f_ulListenerMaskIndex;
		pNewParticipant->ulListenerMask = f_ulListenerMask;

		/* Remember this channel's input port. */
		pNewParticipant->ulInputPort = f_ulInputPort;

		/*=======================================================================*/
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		/* Configure the SIN copy mixer entry and memory - if using the SOUT port. */
		if ( ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( f_fTap == FALSE ) )
		{
			if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
			{
				ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																  pEchoChanEntry->usSinTsstIndex,
																  pEchoChanEntry->usExtraSinTsiMemIndex,
																  pEchoChanEntry->TdmConfig.bySinPcmLaw );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}

			/* If the silence TSI is loaded on this port, update with the extra sin TSI. */
			if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
			{
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

				WriteParams.ulWriteAddress += 2;
				WriteParams.usWriteData = pEchoChanEntry->usExtraSinTsiMemIndex;

				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}
		}

		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex );
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex );

		/*=======================================================================*/
		/* Program the Load event.*/
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		if ( ( f_fMute == FALSE ) || ( f_fTap == TRUE ) )
		{
			if ( pBridgeEntry->usLoadIndex != cOCT6100_INVALID_INDEX )
			{
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;

				/* Set the event type. */
				pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;

				if ( f_fTap == TRUE )
					return cOCT6100_ERR_FATAL_D1;
			}
			else /* pBridgeEntry->usLoadIndex == cOCT6100_INVALID_INDEX */
			{
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD;

				/* Modify the bridge entry to show store the new load index.*/
				pBridgeEntry->usLoadIndex = f_usLoadEventIndex;

				/* Set the event type.*/
				pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;
			}

			/* Select the TSI memory index according to the source port. */
			if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
			{
				if ( f_fTap == FALSE )
				{
					WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex;
				}
				else
				{
					tPOCT6100_API_CONF_BRIDGE	pTempBridgeEntry;
					UINT16						usTempWriteData;
					UINT32						ulTempWriteAddress;

					/* Save temp write data before trying to clear the Rin TSST. */
					usTempWriteData = WriteParams.usWriteData;
					ulTempWriteAddress = WriteParams.ulWriteAddress;
					
					/* Clear the Rin TSST if used. */
					if ( pTapEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX )
					{
						/* Deactivate the TSST entry.*/
						WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pTapEchoChanEntry->usRinTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE );
						WriteParams.usWriteData  = 0x0000;

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}

					/* Reassign write data that might have been cleared by write above. */
					WriteParams.usWriteData = usTempWriteData;
					WriteParams.ulWriteAddress = ulTempWriteAddress;
					WriteParams.usWriteData |= pTapEchoChanEntry->usRinRoutTsiMemIndex;

					/* Remember that this channel is being tapped by us. */
					pTapEchoChanEntry->fBeingTapped = TRUE;
					pTapEchoChanEntry->usTapChanIndex = f_usChanIndex;

					mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pTempBridgeEntry, f_usBridgeIndex );

					pTempBridgeEntry->usNumTappedClients++;
				}
			}
			else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
			{
				WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex;
			}
		}
		else /* f_fMute == TRUE */
		{
			/* Do not load the sample if the channel is muted. */
			if ( pBridgeEntry->usNumClients == 0 )
			{
				/* If the participant to be added is muted, and it would cause the conference to */
				/* be completely muted, load the silence TSI. */
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD;
				WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */

				/* We know for sure that the load of the bridge will be the silence one. */
				pBridgeEntry->usSilenceLoadEventPtr = f_usLoadEventIndex;
			}
			else
			{
				/* Do nothing! */
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
			}
			
			/* Set the event type. */
			pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
		}
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/
		
		/*=======================================================================*/
		/* Program the Substract and store event.*/
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		if ( ( f_fMute == FALSE ) && ( f_fTap == FALSE ) )
		{
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE;
			/* Select the TSI memory index and PCM law according to the source port. */
			if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
			{
				WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
				WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex;
			}
			else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
			{
				WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
				WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex;
			}
			
			/* Set the event type. */
			pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE;
		}
		else /* f_fMute == TRUE */
		{
			/* Do not substore the sample if the channel is muted. */
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE;

			/* Select the PCM law according to the source port. */
			if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
			{
				WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			}
			else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
			{
				WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			}
			/* Set the event type. */
			pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE;
		}

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		WriteParams.ulWriteAddress += 2;
		WriteParams.usWriteData = pEchoChanEntry->usRinRoutTsiMemIndex;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Program the Copy event - if using the SOUT port */
		if ( ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( f_fTap == FALSE ) )
		{
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY;
			WriteParams.usWriteData |= pEchoChanEntry->usExtraSinTsiMemIndex;
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK  )
				return ulResult;

			WriteParams.ulWriteAddress += 2;
			WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK  )
				return ulResult;

			/* Set add copy event flag. */
			fAddSinCopy = TRUE;

			/* For sure. */
			pEchoChanEntry->fCopyEventCreated = TRUE;
		}
		else if ( f_fTap == TRUE )
		{
			/* Accumulate the tapped channel's voice instead of building a copy event. */
			
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;
			WriteParams.usWriteData |= pTapEchoChanEntry->usSinSoutTsiMemIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Link to next operation. */
			WriteParams.ulWriteAddress += 4;
			WriteParams.usWriteData = f_usSubStoreEventIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Update the software model. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, f_usCopyEventIndex );

			pTempEntry->usSourceChanIndex = f_usTapChanIndex;
			pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;
			pTempEntry->usNextEventPtr = f_usSubStoreEventIndex;
			pTempEntry->usDestinationChanIndex = cOCT6100_INVALID_INDEX;
			pTempEntry->fReserved = TRUE;
		}
		/*=======================================================================*/

		/*=======================================================================*/
		/* Now insert the event into the list.*/
		if ( pBridgeEntry->usNumClients == 0 )
		{
			/* This is the first entry for this bridge. Insert the two events at the head
			   of the list just after the last sub-store event.*/
			if ( f_fTap == FALSE )
			{
				ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usLastSubStoreEventIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND )
					{
						if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
						{
							usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE;
						}
						else
						{
							usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
						}
					}
					else
					{
						return cOCT6100_ERR_FATAL_26;
					}
				}
			}
			else
			{
				if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
				{
					usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE;
				}
				else
				{
					usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
				}
			}

			/* An Entry was found, now, modify it's value.*/
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex );

			/* Set the Sub-Store event first.*/
			pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE;
			pSubStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr;

			/*=======================================================================*/
			/* Program the Sub-Store event. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;
			WriteParams.usWriteData = (UINT16)( pSubStoreEventEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/

			/* Set the load/accumulate event now.*/
			if ( f_fTap == FALSE )
			{
				pLoadEventEntry->usNextEventPtr = f_usSubStoreEventIndex;
			}
			else
			{
				/* This is a little tricky, we use the copy event index for accumulating the tapped channel's voice. */
				pLoadEventEntry->usNextEventPtr = f_usCopyEventIndex;
			}

			/*=======================================================================*/
			/* Program the load/accumulate event. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/

			/* Now modify the previous last Sub Store event from another bridge. */
			pTempEntry->usNextEventPtr = f_usLoadEventIndex;

			/*=======================================================================*/
			/* Modify the last node of the other bridge. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/
			
			/* Set the event pointer info in the bridge stucture. */
			pBridgeEntry->usFirstLoadEventPtr = f_usLoadEventIndex;
			pBridgeEntry->usFirstSubStoreEventPtr = f_usSubStoreEventIndex;
			pBridgeEntry->usLastSubStoreEventPtr = f_usSubStoreEventIndex;

			/* Update the global mixer pointers. */
			if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == cOCT6100_INVALID_INDEX )
			{
				/* This bridge is the first to generate mixer event. */
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadEventIndex;
				pSharedInfo->MixerInfo.usLastBridgeEventPtr	 = f_usSubStoreEventIndex;	
			}
			else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex )
			{
				/* The two entries were added at the end of the bridge section, */
				/* change only the last pointer. */
				pSharedInfo->MixerInfo.usLastBridgeEventPtr  = f_usSubStoreEventIndex;
			}
			else if ( usLastSubStoreEventIndex == cOCT6100_MIXER_HEAD_NODE ||
					  usLastSubStoreEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr )
			{
				/* The two entries were added at the start of the bridge section, */
				/* change only the first pointer. */
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadEventIndex;
			}
		}
		else /* pBridgeEntry->usNumClients != 0 */
		{
			/* For sanity. */
			if ( f_fTap == TRUE )
				return cOCT6100_ERR_FATAL_D2;
			
			/*=======================================================================*/
			/* Program the Load event. */

			/* Now find the last load entry of this bridge. */
			ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, pBridgeEntry->usFirstSubStoreEventPtr, 0, &usLastLoadEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Add the load/accumulate event to the list. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastLoadEventIndex  );
			
			/* Set the load event now. */
			pLoadEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr;

			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/


			/*=======================================================================*/
			/* Modify the previous last load event. */

			/* Now modify the previous last load event. */
			pTempEntry->usNextEventPtr = f_usLoadEventIndex;

			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/


			/*=======================================================================*/
			/* Program the Sub-Store event. */

			usLastSubStoreEventIndex = pBridgeEntry->usLastSubStoreEventPtr;

			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex );

			/* Set the Sub-Store event first. */
			pSubStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr;

			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pSubStoreEventEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/


			/*=======================================================================*/
			/* Modify the previous last sub store event of the bridge. */

			/* Now modify the last Load event of the bridge. */
			pTempEntry->usNextEventPtr = f_usSubStoreEventIndex;

			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/

			/* Update the bridge pointers. */
			pBridgeEntry->usLastSubStoreEventPtr = f_usSubStoreEventIndex;

			/* Check if modification to the global mixer pointer are required. */
			if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex )
			{
				/* We have a new last bridge pointer. */
				 pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usSubStoreEventIndex;
			}	
		}

		if ( f_fTap == TRUE )
		{
			if ( pEchoChanEntry->usRinTsstIndex == cOCT6100_INVALID_INDEX )
			{
				/* Remove the mute on the Rin port. */

				UINT32 ulTempData;
				UINT32 ulMask;
				UINT32 ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usChanIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst;

				/* Configure the level control. */

				UINT32 ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinLevelControlOfst.usDwordOffset * 4;
				UINT32 ulFeatureBitOffset	 = pSharedInfo->MemoryMap.RinLevelControlOfst.byBitOffset;
				UINT32 ulFeatureFieldLength = pSharedInfo->MemoryMap.RinLevelControlOfst.byFieldSize;

				mOCT6100_RETRIEVE_NLP_CONF_DWORD(	f_pApiInstance,
													pEchoChanEntry,
													ulBaseAddress + ulFeatureBytesOffset,
													&ulTempData,
													ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Clear previous value set in the feature field.*/
				mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask );

				ulTempData &= (~ulMask);

				/* Set the DC filter to pass through.*/
				ulTempData |= ( cOCT6100_PASS_THROUGH_LEVEL_CONTROL << ulFeatureBitOffset );

				/* First read the DWORD where the field is located. */
				mOCT6100_SAVE_NLP_CONF_DWORD(	f_pApiInstance,
												pEchoChanEntry,
												ulBaseAddress + ulFeatureBytesOffset,
												ulTempData,
												ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}
		}

		/* Set the event entries as reserved. */
		pLoadEventEntry->fReserved = TRUE;
		pSubStoreEventEntry->fReserved = TRUE;

		/* Store the event indexes into the channel structure. */
		pEchoChanEntry->usLoadEventIndex = f_usLoadEventIndex;
		pEchoChanEntry->usSubStoreEventIndex = f_usSubStoreEventIndex;

		/* Check if must insert the Sin copy event in the list. */
		if ( fAddSinCopy == TRUE )
		{
			/* Now insert the Sin copy event into the list. */
			ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance,
												f_usCopyEventIndex,
												cOCT6100_EVENT_TYPE_SIN_COPY,
												f_usChanIndex );
		}

		/* Check if the Rin silence event can be cleared now that the */
		/* channel has been added to a conference. */
		if ( ( f_fTap == FALSE ) && ( pEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) )
		{
			/* Remove the event from the list. */
			ulResult = Oct6100ApiMixerEventRemove(	f_pApiInstance,
													pEchoChanEntry->usRinSilenceEventIndex,
													cOCT6100_EVENT_TYPE_SOUT_COPY );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
				return cOCT6100_ERR_FATAL_DF;

			pEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX;
		}
	}

	/* Configure the RIN copy mixer entry and memory - if using the RIN port. */
	if ( ( f_fFlexibleConfBridge == TRUE ) && ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) )
	{
		if ( pEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX )
		{
			ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
															  pEchoChanEntry->usRinTsstIndex,
															  pEchoChanEntry->usExtraRinTsiMemIndex,
															  pEchoChanEntry->TdmConfig.byRinPcmLaw );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}
	}

	if ( pBridgeEntry->fDominantSpeakerSet == TRUE )
	{
		/* Dominant speaker is another channel.  Set accordingly for this new conference channel. */
		ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, pBridgeEntry->usDominantSpeakerChanIndex );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;
	}
	else
	{
		/* No dominant speaker set on this bridge yet. */
		ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;
	}

	/* Update the bridge entry. */
	pBridgeEntry->usNumClients++;

	/* Store the bridge index into the channel structure. */
	pEchoChanEntry->usBridgeIndex = f_usBridgeIndex;

	/* Store the copy event index into the channel structure. */
	if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
	{
		pEchoChanEntry->usSinCopyEventIndex	= f_usCopyEventIndex;
	}
	else
	{
		pEchoChanEntry->usSinCopyEventIndex	= cOCT6100_INVALID_INDEX;
	}

	/* Remember if the channel is muted in the conference. */
	pEchoChanEntry->fMute = f_fMute;

	/* Remember if the channel is a tap in a conference. */
	pEchoChanEntry->fTap = f_fTap;

	/* We start by not being tapped. */
	pEchoChanEntry->fBeingTapped = FALSE;
	pEchoChanEntry->usTapChanIndex = cOCT6100_INVALID_INDEX;

	/* Remember the tap bridge index if necessary. */
	if ( pEchoChanEntry->fTap == TRUE )
	{
		pEchoChanEntry->usTapBridgeIndex = f_usTapBridgeIndex;
	}
	else
	{
		pEchoChanEntry->usTapBridgeIndex = cOCT6100_INVALID_INDEX;
	}

	/* Indicate that the extra SIN TSI is currently in used by the conference bridge. */
	if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
	{
		pEchoChanEntry->usExtraSinTsiDependencyCnt++;
	}

	/* Indicate that the extra RIN TSI is currently in used by the conference bridge. */
	if ( ( f_fFlexibleConfBridge == TRUE ) && ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) )
	{
		pEchoChanEntry->usExtraRinTsiDependencyCnt++;
	}

	/* Update the chip stats structure. */
	pSharedInfo->ChipStats.usNumEcChanUsingMixer++;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeAddParticipantToChannel

Description:    Used for the flexible conference bridges.  Insert a participant
				onto a channel that is on a conference.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance					Pointer to API instance. This memory is used to keep the
								present state of the chip and all its resources.
f_usBridgeIndex					Bridge index where this channel is located.
f_usSourceChannelIndex			Source channel to copy voice from.
f_usDestinationChannelIndex		Destination channel to store resulting voice to.
f_usLoadOrAccumulateEventIndex	Load or Accumulate allocated event index.
f_usStoreEventIndex				Store allocated event index.
f_usCopyEventIndex				Copy allocated event index.
f_ulSourceInputPort				Source input port of the conference for this channel.
f_ulDestinationInputPort		Destination input port of the conference for this channel.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32	Oct6100ApiBridgeAddParticipantToChannel(
				IN OUT	tPOCT6100_INSTANCE_API	f_pApiInstance,
				IN		UINT16					f_usBridgeIndex, 
				IN		UINT16					f_usSourceChannelIndex,
				IN		UINT16					f_usDestinationChannelIndex,
				IN		UINT16					f_usLoadOrAccumulateEventIndex,
				IN		UINT16					f_usStoreEventIndex,
				IN		UINT16					f_usCopyEventIndex,
				IN		UINT32					f_ulSourceInputPort,
				IN		UINT32					f_ulDestinationInputPort )
{
	tPOCT6100_API_CONF_BRIDGE			pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT			pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT			pStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT			pTempEntry;

	tPOCT6100_API_CHANNEL				pSourceChanEntry;
	tPOCT6100_API_CHANNEL				pDestinationChanEntry;

	tPOCT6100_API_FLEX_CONF_PARTICIPANT	pSourceParticipant;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT	pDestinationParticipant;

	tPOCT6100_SHARED_INFO			pSharedInfo;
	tOCT6100_WRITE_PARAMS			WriteParams;

	UINT32							ulResult;
	UINT16							usLastSubStoreEventIndex;
	UINT16							usLastLoadEventIndex;
	BOOL							fInsertCopy = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex );

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceChanEntry, f_usSourceChannelIndex );
	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceParticipant, pSourceChanEntry->usFlexConfParticipantIndex );
	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationChanEntry, f_usDestinationChannelIndex );
	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationParticipant, pDestinationChanEntry->usFlexConfParticipantIndex );

	mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadOrAccumulateEventIndex );
	mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pStoreEventEntry, f_usStoreEventIndex );

	/* Check if we are creating the first event for this channel. */
	if ( pDestinationParticipant->fFlexibleMixerCreated == FALSE )
	{
		/*=======================================================================*/
		/* Before creating the participant's flexible mixer, make sure the extra Sin */
		/* mixer event is programmed correctly for sending the voice stream to the right place. */

		/* Configure the SIN copy mixer entry and memory - if using the SOUT port. */
		if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT )
		{
			if ( pDestinationChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
			{
				ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																  pDestinationChanEntry->usSinTsstIndex,
																  pDestinationChanEntry->usExtraSinTsiMemIndex,
																  pDestinationChanEntry->TdmConfig.bySinPcmLaw );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}

			/* If the silence TSI is loaded on this port, update with the extra sin TSI. */
			if ( pDestinationChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
			{
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

				WriteParams.ulWriteAddress += 2;
				WriteParams.usWriteData = pDestinationChanEntry->usExtraSinTsiMemIndex;

				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}
		}
		/*=======================================================================*/

		
		/*=======================================================================*/
		/* Program the load event.  This is the first event for this new destination channel. */

		/* First set the TSI buffer where the resulting stream should be written to. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

		/* For sure, we are loading. */
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD;

		/* Select the TSI memory index according to the source port. */
		if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_SOUT )
		{
			WriteParams.usWriteData |= pSourceChanEntry->usSinSoutTsiMemIndex;
		}
		else /* if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
		{
			WriteParams.usWriteData |= pSourceChanEntry->usExtraRinTsiMemIndex;
		}

		/* Set the event type. */
		pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;

		/* Set the source channel index. */
		pLoadEventEntry->usSourceChanIndex = f_usSourceChannelIndex;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/



		/*=======================================================================*/
		/* Program the store event. */

		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE;

		/* Select the TSI memory index and PCM law according to the source port. */
		if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT )
		{
			WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			WriteParams.usWriteData |= pDestinationChanEntry->usSinSoutTsiMemIndex;
		}
		else /* if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
		{
			WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			WriteParams.usWriteData |= pDestinationChanEntry->usRinRoutTsiMemIndex;
		}
		
		/* Set the event type. */
		pStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE;

		/* Set the destination channel index. */
		pStoreEventEntry->usDestinationChanIndex = f_usDestinationChannelIndex;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		WriteParams.ulWriteAddress += 2;
		WriteParams.usWriteData = pDestinationChanEntry->usRinRoutTsiMemIndex;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/



		/*=======================================================================*/
		/* Program the Copy event - if using the SOUT port */

		if ( ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pDestinationChanEntry->fCopyEventCreated == FALSE ) )
		{
			/* The copy event has not been created, create it once for the life of the participant on the bridge. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY;
			WriteParams.usWriteData |= pDestinationChanEntry->usExtraSinTsiMemIndex;
			WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			WriteParams.ulWriteAddress += 2;
			WriteParams.usWriteData = pDestinationChanEntry->usSinSoutTsiMemIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			pDestinationChanEntry->fCopyEventCreated = TRUE;

			/* Set insert copy flag. */
			fInsertCopy = TRUE;
		}
		
		/*=======================================================================*/



		/*=======================================================================*/
		/*=======================================================================*/
		/* Now, insert the events into the current list. */
		/*=======================================================================*/
		/*=======================================================================*/

		/* This is the first entry for this channel. Insert the two events at the head */
		/* of the list just after the last Sub-Store or Store event. */
		ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, f_usLoadOrAccumulateEventIndex, &usLastSubStoreEventIndex );
		if ( ulResult != cOCT6100_ERR_OK )
		{
			if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND )
			{
				if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
				{
					usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE;
				}
				else
				{
					usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
				}
			}
			else
			{
				return cOCT6100_ERR_FATAL_26;
			}
		}

		/* An entry was found, now, modify it's value. */
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex );

		/*=======================================================================*/


		/*=======================================================================*/
		/* Link the store event first. */
		
		pStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr;

		/* Link the store event. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.ulWriteAddress += 4;
		WriteParams.usWriteData = (UINT16)( pStoreEventEntry->usNextEventPtr );
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Link the load event now.*/

		pLoadEventEntry->usNextEventPtr = f_usStoreEventIndex;

		/* Link the load event.*/
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.ulWriteAddress += 4;

		WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr );
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Now modify the previous last Sub-Store or Store event from another bridge, */
		/* such that it links to us. */

		pTempEntry->usNextEventPtr = f_usLoadOrAccumulateEventIndex;

		/* Modify the last node of the other bridge. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.ulWriteAddress += 4;

		WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Set the event pointer info in the bridge stucture. */

		if ( pBridgeEntry->usFirstLoadEventPtr == cOCT6100_INVALID_INDEX )
		{
			/* We only do this once in case of the flexible conference bridges. */
			pBridgeEntry->usFirstLoadEventPtr = f_usLoadOrAccumulateEventIndex;
			pBridgeEntry->usFirstSubStoreEventPtr = f_usStoreEventIndex;
		}

		pBridgeEntry->usLastSubStoreEventPtr = f_usStoreEventIndex;

		/* Update the global mixer pointers. */
		if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == cOCT6100_INVALID_INDEX )
		{
			/* This bridge is the first to generate mixer event. */
			pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadOrAccumulateEventIndex;
			pSharedInfo->MixerInfo.usLastBridgeEventPtr	 = f_usStoreEventIndex;	
		}
		else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex )
		{
			/* The two entries were added at the end of the bridge section, */
			/* change only the last pointer. */
			pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usStoreEventIndex;
		}
		else if ( usLastSubStoreEventIndex == cOCT6100_MIXER_HEAD_NODE ||
				  usLastSubStoreEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr )
		{
			/* The two entries were added at the start of the bridge section, */
			/* change only the first pointer.*/
			pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadOrAccumulateEventIndex;
		}

		/*=======================================================================*/


		/*=======================================================================*/
		/* Insert the copy event if needed in the mixer's list. */

		if ( fInsertCopy == TRUE )
		{
			/* Now insert the Sin copy event into the list. */
			ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance,
												f_usCopyEventIndex,
												cOCT6100_EVENT_TYPE_SIN_COPY,
												f_usDestinationChannelIndex );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}

		/*=======================================================================*/


		/*=======================================================================*/
		/* Update the status of the instance structures. */

		pDestinationParticipant->fFlexibleMixerCreated = TRUE;

		/* Set the event entries as reserved. */
		pLoadEventEntry->fReserved = TRUE;
		pStoreEventEntry->fReserved = TRUE;

		/* Store the event indexes into the channel structure. */
		pDestinationChanEntry->usLoadEventIndex = f_usLoadOrAccumulateEventIndex;
		pDestinationChanEntry->usSubStoreEventIndex = f_usStoreEventIndex;

		/*=======================================================================*/
	}
	else /* if ( pDestinationChanEntry->fFlexibleMixerCreated == TRUE ) */
	{
		/*=======================================================================*/
		/* Program the Accumulate event. */

		/* First set the TSI buffer where the resulting stream should be written to. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

		/* For sure, we are accumulating. */
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;

		/* Select the TSI memory index according to the source port. */
		if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_SOUT )
		{
			WriteParams.usWriteData |= pSourceChanEntry->usSinSoutTsiMemIndex;
		}
		else /* if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_RIN ) */
		{
			WriteParams.usWriteData |= pSourceChanEntry->usExtraRinTsiMemIndex;
		}

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/



		/*=======================================================================*/
		/*=======================================================================*/
		/* Now, insert the Accumulate event into the current list. */
		/*=======================================================================*/
		/*=======================================================================*/

		/* Use the Load entry of this channel. */
		usLastLoadEventIndex = pDestinationChanEntry->usLoadEventIndex;

		/* Add the Accumulate event to the list. */
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastLoadEventIndex );
		
		/* Set the accumulate event now. */
		pLoadEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr;

		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.ulWriteAddress += 4;

		WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr );
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/



		/*=======================================================================*/
		/* Modify the previous Load event. */

		/* Now modify the previous Load event. */
		pTempEntry->usNextEventPtr = f_usLoadOrAccumulateEventIndex;

		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.ulWriteAddress += 4;

		WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/*=======================================================================*/


		
		/*=======================================================================*/
		/* Update the status of the instance structures. */

		/* Set the Accumulate event entry as reserved. */
		pLoadEventEntry->fReserved = TRUE;
		/* Set the Event type. */
		pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;
		/* Set the source channel index. */
		pLoadEventEntry->usSourceChanIndex = f_usSourceChannelIndex;

		/*=======================================================================*/
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanRemoveSer

Description:    Removes an echo channel from a conference bridge. 

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeRemove		Pointer to conference bridge channel remove structure.  

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanRemoveSer(
				IN OUT	tPOCT6100_INSTANCE_API					f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_REMOVE		f_pConfBridgeRemove )
{
	UINT16	usBridgeIndex;
	UINT16	usChanIndex;
	UINT16	usLoadEventIndex;
	UINT16	usSubStoreEventIndex;
	UINT16	usCopyEventIndex;
	UINT32	ulResult;
	UINT8	fFlexibleConfBridge;
	UINT8	fTap;

	/* Check the validity of the channel and conference bridge given. */
	ulResult = Oct6100ApiCheckChanRemoveParams(
										f_pApiInstance, 
										f_pConfBridgeRemove, 
										&usBridgeIndex, 
										&usChanIndex, 
										&fFlexibleConfBridge, 
										&fTap,
										&usLoadEventIndex, 
										&usSubStoreEventIndex, 
										&usCopyEventIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Release all resources reserved for the conference bridge. */
	ulResult = Oct6100ApiReleaseChanEventResources( 
										f_pApiInstance, 
										f_pConfBridgeRemove, 
										usBridgeIndex, 
										usChanIndex, 
										fFlexibleConfBridge, 
										usLoadEventIndex, 
										usSubStoreEventIndex, 
										usCopyEventIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Clear the memory entry for this channel within the bridge. */
	ulResult = Oct6100ApiBridgeEventRemove( 
										f_pApiInstance, 
										f_pConfBridgeRemove, 
										usBridgeIndex, 
										usChanIndex, 
										fFlexibleConfBridge, 
										usLoadEventIndex, 
										usSubStoreEventIndex, 
										usCopyEventIndex,
										fTap );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckChanRemoveParams

Description:	Check the validity of the channel and conference bridge given.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_pConfBridgeRemove			Pointer to conference bridge channenl add structure.  
f_pusBridgeIndex			Pointer to the bridge index.
f_pfFlexibleConfBridge		If this is a flexible conference bridge
f_pusChannelIndex			Pointer to the channel index to be added to the bridge.
f_pusLoadEventIndex			Pointer to the load mixer event.
f_pusSubStoreEventIndex		Pointer to the sub-store mixer event.
f_pusCopyEventIndex			Pointer to the copy mixer event.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckChanRemoveParams(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_REMOVE	f_pConfBridgeRemove,
				OUT		PUINT16								f_pusBridgeIndex, 
				OUT		PUINT16								f_pusChannelIndex,
				OUT		PUINT8								f_pfFlexibleConfBridge,
				OUT		PUINT8								f_pfTap,
				OUT		PUINT16								f_pusLoadEventIndex,
				OUT		PUINT16								f_pusSubStoreEventIndex,
				OUT		PUINT16								f_pusCopyEventIndex )
{
	UINT32						ulEntryOpenCnt;
	tPOCT6100_API_CHANNEL		pEchoChanEntry;
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;

	/* Verify if the remove all flag is valid. */
	if ( f_pConfBridgeRemove->fRemoveAll != TRUE && 
		 f_pConfBridgeRemove->fRemoveAll != FALSE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_REMOVE_ALL;

	/* Check the channel handle only if the remove all flag is set to FALSE. */
	if ( f_pConfBridgeRemove->fRemoveAll == FALSE )
	{
		/*=====================================================================*/
		/* Check the channel handle. */

		if ( (f_pConfBridgeRemove->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		*f_pusChannelIndex = (UINT16)( f_pConfBridgeRemove->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
		if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = (f_pConfBridgeRemove->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

		/* Check for errors. */
		if ( pEchoChanEntry->fReserved != TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
		if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;
		if ( pEchoChanEntry->fBeingTapped == TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_DEPENDENCY;

		/*=====================================================================*/

		*f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex;
		*f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex;
		*f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex;
		*f_pusCopyEventIndex = pEchoChanEntry->usSinCopyEventIndex;

		/* Check if the channel is really part of the bridge. */
		if ( *f_pusBridgeIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE;

		mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

		/* Return whether this is a flexible bridge or not. */
		*f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing;

		/* Return whether this is a tap or not. */
		*f_pfTap = pEchoChanEntry->fTap;
	}
	else /* f_pConfBridgeRemove->fRemoveAll == TRUE */
	{
		/* Check the provided handle. */
		if ( (f_pConfBridgeRemove->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		*f_pusBridgeIndex = (UINT16)( f_pConfBridgeRemove->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK );
		if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = (f_pConfBridgeRemove->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

		/* Check for errors. */
		if ( pBridgeEntry->fReserved != TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
		if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		/* This information is not currently available. */
		*f_pusLoadEventIndex = cOCT6100_INVALID_INDEX;
		*f_pusSubStoreEventIndex = cOCT6100_INVALID_INDEX;
		*f_pusCopyEventIndex = cOCT6100_INVALID_INDEX;

		/* Return whether this is a flexible bridge or not. */
		*f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing;

		*f_pfTap = FALSE;
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReleaseChanEventResources

Description:    Release all resources reserved to the channel part of the 
				conference bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_pConfBridgeRemove			Pointer to conference bridge channel add structure.  
f_usBridgeIndex				Index of the bridge structure within the API's bridge list.
f_usChanIndex				Index of the channel structure within the API's channel list
f_fFlexibleConfBridge		If this is a flexible conference bridge.
f_usLoadEventIndex			Index of the load mixer event.
f_usSubStoreEventIndex		Index of the sub-store mixer event.
f_usCopyEventIndex			Index of the copy mixer event.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReleaseChanEventResources(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_REMOVE	f_pConfBridgeRemove,
				IN		UINT16								f_usBridgeIndex, 
				IN		UINT16								f_usChanIndex,
				IN		UINT8								f_fFlexibleConfBridge,
				IN		UINT16								f_usLoadEventIndex,
				IN		UINT16								f_usSubStoreEventIndex,
				IN		UINT16								f_usCopyEventIndex )
{
	tPOCT6100_SHARED_INFO		pSharedInfo;
	tPOCT6100_API_CHANNEL		pEchoChanEntry;
	UINT32	ulResult;
	UINT32	i;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;

		if ( f_pConfBridgeRemove->fRemoveAll == FALSE )
		{
			tPOCT6100_API_CHANNEL		pTempEchoChanEntry;

			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );
			mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

			/* Release an entry for the store event in the mixer memory. */
			ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usSubStoreEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
			{
				return ulResult;
			}

			/* Release an entry for the Sin copy event in the mixer memory. */
			/* This value can be invalid if the Rin port was used - no need to release. */
			if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX )
			{
				ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usCopyEventIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					return ulResult;
				}
			}

			/* This value can be 0 if the Rin port was used - no need to release. */
			if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
			{
				/* Release the extra TSI entry.*/
				ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					return ulResult;
				}
			}

			/* This value can be 0 if the Sout port was used - no need to release. */
			if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 )
			{
				/* Release the extra TSI entry.*/
				ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraRinTsiMemIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					return ulResult;
				}
			}

			/* Must travel all clients of this conference and release the load or accumulate events for */
			/* all participants which can hear us and vice versa. */

			/* Search through the list of API channel entry for the ones on to this bridge. */
			for ( i = 0; ( i < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ); i++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, i );
			
				/* Channel reserved? */
				if ( ( i != f_usChanIndex ) && pTempEchoChanEntry->fReserved == TRUE )
				{
					/* On current bridge? */
					if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
					{
						mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

						/* Check if we can hear this participant. */
						if ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
						{
							/* Must release the allocated mixer event. */
							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
							
							pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
						}

						/* Check if this participant can hear us. */
						if ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 )
						{
							/* Must release the allocated mixer event. */
							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ] );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}

							pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
						}
					}
				}
			}
		}
		else /* f_pConfBridgeRemove->fRemoveAll == TRUE */
		{
			UINT32 ulListenerMaskIndex;

			ulResult = cOCT6100_ERR_OK;
			
			/* Search through the list of API channel entry for the ones on to this bridge.*/
			for ( i = 0; ( i < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ); i++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i );
				
				/* Channel reserved? */
				if ( pEchoChanEntry->fReserved == TRUE )
				{
					/* On current bridge? */
					if ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
					{
						mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

						/* Release an entry for the Store event in the Mixer memory. */
						ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSubStoreEventIndex );
						if ( ulResult != cOCT6100_ERR_OK )
						{
							return ulResult;
						}

						/* Release an entry for the Sin copy event in the Mixer memory. */
						/* This value can be invalid if the Rin port was used - no need to release. */
						if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
						{
							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
						}

						/* This value can be 0 if the Rin port was used - no need to release. */
						if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
						{
							/* Release the extra TSI entry.*/
							ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
						}

						/* This value can be 0 if the Sout port was used - no need to release. */
						if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 )
						{
							/* Release the extra TSI entry.*/
							ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraRinTsiMemIndex );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
						}

						/* Check if something can be freed. */
						for ( ulListenerMaskIndex = 0; ulListenerMaskIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulListenerMaskIndex ++ )
						{
							if ( pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX )
							{
								/* Must release the allocated mixer event. */
								ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] );
								if ( ulResult != cOCT6100_ERR_OK )
								{
									return ulResult;
								}
								
								pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
							}
						}
					}
				}
			}

			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		if ( f_pConfBridgeRemove->fRemoveAll == FALSE )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );
			
			/* Release the entry for the load event in the mixer memory. */
			ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usLoadEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
			{
				return ulResult;
			}

			/* Release an entry for the substract and store event in the mixer memory. */
			ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usSubStoreEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
			{
				return ulResult;
			}

			/* Release an entry for the Sin copy event in the Mixer memory. */
			/* This value can be invalid if the Rin port was used - no need to release. */
			if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX )
			{
				ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usCopyEventIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					return ulResult;
				}
			}

			/* This value can be 0 if the Rin port was used - no need to release. */
			if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
			{
				/* Release the extra TSI entry. */
				ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex );
				if ( ulResult != cOCT6100_ERR_OK )
				{
					return ulResult;
				}
			}
		}
		else /* f_pConfBridgeRemove->fRemoveAll == TRUE */
		{
			/* Search through the list of API channel entry for the ones on to the specified bridge.*/
			for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i );
				
				if ( pEchoChanEntry->fReserved == TRUE )
				{
					if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) )
					{
						/* Release the entry for the load event in the mixer memory. */
						ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, 
																	  pEchoChanEntry->usLoadEventIndex );
						if ( ulResult != cOCT6100_ERR_OK )
						{
							return ulResult;
						}

						/* Release an entry for the substract and store event in the Mixer memory. */
						ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, 
																	  pEchoChanEntry->usSubStoreEventIndex );
						if ( ulResult != cOCT6100_ERR_OK )
						{
							return ulResult;
						}

						/* Release an entry for the Sin copy event in the Mixer memory. */
						/* This value can be invalid if the Rin port was used - no need to release. */
						if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
						{
							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, 
																		  pEchoChanEntry->usSinCopyEventIndex );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
						}

						/* This value can be 0 if the Rin port was used - no need to release. */
						if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
						{
							/* Release the extra TSI entry.*/
							ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex );
							if ( ulResult != cOCT6100_ERR_OK )
							{
								return ulResult;
							}
						}
					}
				}
			}
		}
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeEventRemove

Description:    Remove the event from the global event list of the chip and 
				update the bridge and channel structures.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_pConfBridgeRemove			Pointer to a conference bridge channel remove structure.
f_usBridgeIndex				Index of the current bridge in the API list.
f_usChanIndex				Index of the current channel in the API list.
f_fFlexibleConfBridge		If this is a flexible conference bridge.
f_usLoadEventIndex			Allocated entry for the Load event of the channel.
f_usSubStoreEventIndex		Allocated entry for the substract and store event of the channel.
f_usCopyEventIndex			Allocated entry for the copy event of the channel.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiBridgeEventRemove (
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_REMOVE	f_pConfBridgeRemove,
				IN		UINT16								f_usBridgeIndex, 
				IN		UINT16								f_usChanIndex,
				IN		UINT8								f_fFlexibleConfBridge,
				IN		UINT16								f_usLoadEventIndex,
				IN		UINT16								f_usSubStoreEventIndex,
				IN		UINT16								f_usCopyEventIndex,
				IN		UINT8								f_fTap )
{
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT		pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT		pSubStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT		pCopyEventEntry = NULL;
	tPOCT6100_API_MIXER_EVENT		pTempEntry;

	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	tPOCT6100_API_CHANNEL			pTempEchoChanEntry;

	tPOCT6100_SHARED_INFO			pSharedInfo;
	tOCT6100_WRITE_PARAMS			WriteParams;
	tOCT6100_READ_PARAMS			ReadParams;

	UINT32	ulResult;
	UINT16	usPreviousEventIndex;
	UINT16	usTempEventIndex;
	UINT32	ulLoopCount = 0;
	UINT16	usReadData;
	UINT16	usChannelIndex;
	UINT32	i;

	BOOL	fRemoveSinCopy = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
	ReadParams.pusReadData = &usReadData;
	
	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usBridgeIndex );
	
	/* If no client on the bridge, and the remove all option is specified, return here. */
	if ( ( pBridgeEntry->usNumClients == 0 ) && ( f_pConfBridgeRemove->fRemoveAll == TRUE ) )
		return cOCT6100_ERR_OK;

	/* Make sure the dominant speaker feature is disabled first. */
	if ( pBridgeEntry->fDominantSpeakerSet == TRUE )
	{
		/* If all channels are to be removed or if the dominant speaker is the current channel to be removed. */
		if ( ( f_pConfBridgeRemove->fRemoveAll == TRUE )
			|| ( ( f_pConfBridgeRemove->fRemoveAll == FALSE ) && ( pBridgeEntry->usDominantSpeakerChanIndex == f_usChanIndex ) ) )
		{
			/* Disable on all channels part of this conference. */

			/* Search through the list of API channel entry for the ones on to this bridge. */
			for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
				
				if ( pTempEchoChanEntry->fReserved == TRUE )
				{
					if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
					{
						ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, usChannelIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}
				}
			}

			/* Save this in the conference bridge structure. */
			pBridgeEntry->fDominantSpeakerSet = FALSE;
			pBridgeEntry->usDominantSpeakerChanIndex = cOCT6100_INVALID_INDEX;
		}
		else
		{
			/* Only disable this current channel. */
			ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}
	}

	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;
		UINT16	ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ];
		UINT32	ulMutePortChannelIndex;

		for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
			ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX;

		if ( f_pConfBridgeRemove->fRemoveAll == FALSE )
		{
			/* The channel index is valid. */
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );
			mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

			/* Search through the list of API channel entry for the ones on to this bridge. */
			for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );

				if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
				{
					if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
					{
						mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

						/* Check if we can hear this participant. */
						if ( ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
							&& ( pParticipant->fFlexibleMixerCreated == TRUE ) 
							&& ( pTempEchoChanEntry->fMute == FALSE ) )
						{
							/* First update the current channel's mixer. */
							ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
														f_pApiInstance,
														f_usBridgeIndex,
														usChannelIndex,
														f_usChanIndex,
														TRUE );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;
						}

						/* Check if this participant can hear us. */
						if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 )
							&& ( pTempParticipant->fFlexibleMixerCreated == TRUE ) 
							&& ( pEchoChanEntry->fMute == FALSE ) )
						{
							/* Then update this channel's mixer. */
							ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
														f_pApiInstance,
														f_usBridgeIndex,
														f_usChanIndex,
														usChannelIndex,
														TRUE );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							/* Remember to mute the port on this channel. */
							for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
							{
								if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usChannelIndex )
								{
									break;
								}
								else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX )
								{
									ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usChannelIndex;
									break;
								}
							}
						}
					}
				}
			}

			/* Check if must manually clear the Sin copy event. */
			if ( ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
				&& ( pEchoChanEntry->fCopyEventCreated == TRUE ) )
			{
				/* Transform event into no-operation. */
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Now remove the copy event from the event list. */
				ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				pEchoChanEntry->fCopyEventCreated = FALSE;
			}

			/* Release an entry for the participant. */
			ulResult = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pEchoChanEntry->usFlexConfParticipantIndex );
			if ( ulResult != cOCT6100_ERR_OK )
			{
				return ulResult;
			}

			/*=======================================================================*/
			/* Update the event and channel API structure */
			pEchoChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX;

			/* Indicate that the extra SIN TSI is not needed anymore by the mixer. */
			if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
			{
				pEchoChanEntry->usExtraSinTsiDependencyCnt--;
				pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
			}
			else
			{
				/* Decrement the dependency count, but do not clear the mem index. */
				pEchoChanEntry->usExtraSinTsiDependencyCnt--;
			}
			
			/* Indicate that the extra RIN TSI is not needed anymore by the mixer. */
			if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 )
			{
				pEchoChanEntry->usExtraRinTsiDependencyCnt--;
				pEchoChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX;
			}

			/* Update the chip stats structure. */
			pSharedInfo->ChipStats.usNumEcChanUsingMixer--;

			pBridgeEntry->usNumClients--;

			/* For sure we have to mute the ports of this channel to be removed. */
			ulResult = Oct6100ApiMutePorts( 
									f_pApiInstance, 
									f_usChanIndex, 
									pEchoChanEntry->usRinTsstIndex, 
									pEchoChanEntry->usSinTsstIndex,
									FALSE );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */
			for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
			{
				if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX )
				{
					mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] );

					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );
					
					if ( pTempParticipant->fFlexibleMixerCreated == FALSE )
					{
						/* Check if the Rin port must be muted on this channel. */
						ulResult = Oct6100ApiMutePorts( 
												f_pApiInstance, 
												ausMutePortChannelIndexes[ ulMutePortChannelIndex ], 
												pTempEchoChanEntry->usRinTsstIndex, 
												pTempEchoChanEntry->usSinTsstIndex,
												FALSE );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}
				}
				else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */
				{
					/* No more channels to check for muting. */
					break;
				}
			}
		}
		else /* if ( f_pConfBridgeRemove->fRemoveAll == TRUE ) */
		{
			UINT16 usMainChannelIndex;

			for ( usMainChannelIndex = 0 ; usMainChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ; usMainChannelIndex++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usMainChannelIndex );

				/* If this channel is on the bridge we are closing all the channels. */
				if ( ( pEchoChanEntry->fReserved == TRUE ) && ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) )
				{
					/* Remember to mute the port on this channel. */
					for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
					{
						if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usMainChannelIndex )
						{
							break;
						}
						else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX )
						{
							ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usMainChannelIndex;
							break;
						}
					}

					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

					/* Search through the list of API channel entry for the ones on to this bridge. */
					for ( usChannelIndex = (UINT16)( usMainChannelIndex + 1 ); usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
					{
						mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
						if ( pTempEchoChanEntry->fReserved == TRUE )
						{
							if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
							{
								mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

								/* Everyone that we can hear must be removed. */
								if ( ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
									&& ( pParticipant->fFlexibleMixerCreated == TRUE ) 
									&& ( pTempEchoChanEntry->fMute == FALSE ) )
								{
									/* First update the current channel's mixer. */
									ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
																f_pApiInstance,
																f_usBridgeIndex,
																usChannelIndex,
																usMainChannelIndex,
																TRUE );
									if ( ulResult != cOCT6100_ERR_OK )
										return ulResult;
								}

								/* Check if this participant can hear us. */
								if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 )
									&& ( pTempParticipant->fFlexibleMixerCreated == TRUE ) 
									&& ( pEchoChanEntry->fMute == FALSE ) )
								{
									/* Then update this channel's mixer. */
									ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
																f_pApiInstance,
																f_usBridgeIndex,
																usMainChannelIndex,
																usChannelIndex,
																TRUE );
									if ( ulResult != cOCT6100_ERR_OK )
										return ulResult;
								}
							}
						}
					}

					/* Check if must manually clear the Sin copy event. */
					if ( ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
						&& ( pEchoChanEntry->fCopyEventCreated == TRUE ) )
					{
						/* Transform event into no-operation. */
						WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
						WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						/* Now remove the copy event from the event list. */
						ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						pEchoChanEntry->fCopyEventCreated = FALSE;
					}

					/* Release an entry for the participant. */
					ulResult = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pEchoChanEntry->usFlexConfParticipantIndex );
					if ( ulResult != cOCT6100_ERR_OK )
					{
						return ulResult;
					}

					/*=======================================================================*/
					/* Update the event and channel API structure */

					pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX;

					pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX;
					pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX;
					pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX;

					/* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */
					if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
					{
						pEchoChanEntry->usExtraSinTsiDependencyCnt--;
						pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
					}
					else
					{
						/* Decrement the dependency count, but do not clear the mem index. */
						pEchoChanEntry->usExtraSinTsiDependencyCnt--;
					}
					
					/* Indicate that the Extra RIN TSI is not needed anymore by the mixer. */
					if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 )
					{
						pEchoChanEntry->usExtraRinTsiDependencyCnt--;
						pEchoChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX;
					}

					/* Update the chip stats structure. */
					pSharedInfo->ChipStats.usNumEcChanUsingMixer--;
				}
			}

			/* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */
			for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
			{
				if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX )
				{
					mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] );

					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );
					
					if ( pTempParticipant->fFlexibleMixerCreated == FALSE )
					{
						/* Check if the Rin port must be muted on this channel. */
						ulResult = Oct6100ApiMutePorts( 
												f_pApiInstance, 
												ausMutePortChannelIndexes[ ulMutePortChannelIndex ], 
												pTempEchoChanEntry->usRinTsstIndex, 
												pTempEchoChanEntry->usSinTsstIndex,
												FALSE );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}
				}
				else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */
				{
					/* No more channels to check for muting. */
					break;
				}

				/* Clear the flexible conf bridge participant index. */
				pTempEchoChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX;
			}

			/* No more clients on bridge. */
			pBridgeEntry->usNumClients = 0;
		}
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		if ( f_pConfBridgeRemove->fRemoveAll == FALSE )
		{
			/* The channel index is valid. */
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );

			if ( f_fTap == TRUE )
			{
				mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, pEchoChanEntry->usTapBridgeIndex );
			}

			/* Get a pointer to the event entry. */
			if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX )
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, f_usCopyEventIndex );
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex );
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex );

			/*=======================================================================*/
			/* Check if have to modify the silence load event. */

			if ( pBridgeEntry->usNumClients != 1 )
			{
				if ( pBridgeEntry->usSilenceLoadEventPtr != cOCT6100_INVALID_INDEX )
				{
					if ( pBridgeEntry->usSilenceLoadEventPtr == f_usLoadEventIndex )
					{
						/* Make sure the next event becomes the silence event. */
						WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pLoadEventEntry->usNextEventPtr * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

						WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD;
						WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
						
						/* Update the software model to remember the silence load. */
						pBridgeEntry->usSilenceLoadEventPtr = pLoadEventEntry->usNextEventPtr;
					}
					else
					{
						/* Somebody else is the silence event, no need to worry. */
					}
				}
			}

			/*=======================================================================*/


			/*=======================================================================*/
			/* Clear the Load event. */

			/* First verify if the event to be removed was a load event. */
			if ( f_usLoadEventIndex == pBridgeEntry->usLoadIndex )
			{
				/* Change the next entry if one is present to a load event to keep the bridge alive. */
				if ( pBridgeEntry->usNumClients == 1 )
				{
					/* There is no other entry on the bridge, no need to search for an Accumulate event. */
					pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX;

					/* Clear the silence event, for sure it's invalid. */
					pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX;
				}
				else
				{
					/* Search for an accumulate event to tranform into a Load event. */
					usTempEventIndex = pLoadEventEntry->usNextEventPtr;
					ulLoopCount = 0;

					/* Find the copy entry before the entry to remove. */
					mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

					while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && 
						   pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE )
					{
						if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE )
						{
							/* Change this entry into a load event. */
							ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
							mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							WriteParams.ulWriteAddress = ReadParams.ulReadAddress;
							WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD);

							mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;
							
							/* Set this entry as the load index. */
							pBridgeEntry->usLoadIndex = usTempEventIndex;

							/* Update the software model. */
							pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;

							/* Stop searching. */
							break;
						}
						
						/* Go to the next entry into the list. */
						usTempEventIndex = pTempEntry->usNextEventPtr;
						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

						ulLoopCount++;
						if ( ulLoopCount == cOCT6100_MAX_LOOP )
							return cOCT6100_ERR_FATAL_9B;
					}
				}
			}
			
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/
			
			/*=======================================================================*/
			/* Clear the substract and store event. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/

			/*=======================================================================*/
			/* Clear the Copy event - if needed. */

			if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX )
			{
				/* Transform event into no-operation. */
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
				
				if ( f_fTap == FALSE )
				{
					/* Set remove Sin copy event flag to remove the event from the mixer's list. */
					fRemoveSinCopy = TRUE;

					/* Clear the copy event created flag. */
					pEchoChanEntry->fCopyEventCreated = FALSE;
				}
			}

			/*=======================================================================*/
		
			
			/*=======================================================================*/
			/* Now remove the event from the event list. */
			
			/* Look for the entry that is pointing at the first entry of our bridge. */
			if ( f_fTap == FALSE )
			{
				ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex );
			}
			else
			{
				ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, pEchoChanEntry->usTapBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex );
			}
			
			if ( ulResult != cOCT6100_ERR_OK )
			{
				/* If the entry was not found, we now check for the Sout copy event section/list. */
				if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND )
				{
					if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
					{
						/* No Sout copy, it has to be the head node. */
						usPreviousEventIndex = cOCT6100_MIXER_HEAD_NODE;
					}
					else
					{
						/* Use the last Sout copy event. */
						usPreviousEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
					}
				}
				else
				{
					return cOCT6100_ERR_FATAL_27;
				}
			}

			if ( pBridgeEntry->usNumClients == 1 )
			{
				/* An entry was found, now, modify it's value. */
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex );

				/* Now modify the previous last Sub Store event from another bridge. */
				pTempEntry->usNextEventPtr = pSubStoreEventEntry->usNextEventPtr;

				/*=======================================================================*/
				/* Modify the last node of the previous bridge to point to the next bridge. */
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
				WriteParams.ulWriteAddress += 4;

				WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
				
				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/*=======================================================================*/
				
				/* Set the event pointer info in the bridge stucture. */
				pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX;
				pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX;
				pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX;

				/*=======================================================================*/
				/* Update the global mixer pointers. */
				if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex &&
					 pSharedInfo->MixerInfo.usLastBridgeEventPtr  == f_usSubStoreEventIndex )
				{
					/* There is no more bridge entry in the mixer link list. */
					pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX;
					pSharedInfo->MixerInfo.usLastBridgeEventPtr  = cOCT6100_INVALID_INDEX;
				}
				else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex )
				{
					pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pSubStoreEventEntry->usNextEventPtr;
				}
				else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == f_usSubStoreEventIndex )
				{
					pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex;
				}
				/*=======================================================================*/

				if ( f_fTap == TRUE )
				{
					/* The channel being tapped is not tapped anymore.  */
					/* There is no direct way of finding the tap, so loop through all channels and find the */
					/* tapped channel index. */
					for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
					{
						mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );

						if ( pTempEchoChanEntry->usTapChanIndex == f_usChanIndex )
						{
							tPOCT6100_API_CONF_BRIDGE	pTempBridgeEntry;

							pTempEchoChanEntry->fBeingTapped = FALSE;
							pTempEchoChanEntry->usTapChanIndex = cOCT6100_INVALID_INDEX;

							mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pTempBridgeEntry, f_usBridgeIndex );

							pTempBridgeEntry->usNumTappedClients--;
							
							/* Re-assign Rin TSST for tapped channel. */
							if ( pTempEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX )
							{
								ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																				  pTempEchoChanEntry->usRinTsstIndex,
																				  pTempEchoChanEntry->usRinRoutTsiMemIndex,
																				  pTempEchoChanEntry->TdmConfig.byRinPcmLaw );
								if ( ulResult != cOCT6100_ERR_OK )
									return ulResult;
							}

							break;
						}
					}

					/* Check if our model is broken. */
					if ( usChannelIndex == pSharedInfo->ChipConfig.usMaxChannels )
						return cOCT6100_ERR_FATAL_D3;
				}
			}
			else /* pBridgeEntry->usNumClients > 1 */
			{
				if ( pBridgeEntry->usFirstLoadEventPtr != f_usLoadEventIndex )
				{
					/* Now find the load entry of this bridge pointing at this load event */
					ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, f_usLoadEventIndex, 0, &usPreviousEventIndex );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}

				/* Remove the load event to the list. */
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex );
				
				/* Now modify the previous last Sub Store event from another bridge. */
				pTempEntry->usNextEventPtr = pLoadEventEntry->usNextEventPtr;

				/*=======================================================================*/
				/* Modify the previous node. */
				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
				WriteParams.ulWriteAddress += 4;

				WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
				
				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/*=======================================================================*/

				/* Now find the last load entry of this bridge ( the one pointing at the first sub-store event ). */
				if ( pBridgeEntry->usFirstSubStoreEventPtr == f_usSubStoreEventIndex )
				{
					/* Must start with the first load to get the entry before the first sub store. */
					ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, f_usSubStoreEventIndex, 0, &usPreviousEventIndex );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
				else
				{
					/* Must start with the first load to get the entry before the first sub store. */
					ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstSubStoreEventPtr, f_usSubStoreEventIndex, 0, &usPreviousEventIndex );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}

				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex );
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex );

				/* Now modify the last load event of the bridge. */
				pTempEntry->usNextEventPtr = pSubStoreEventEntry->usNextEventPtr;

				/*=======================================================================*/
				/* Modify the last node of the other bridge. */

				WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
				WriteParams.ulWriteAddress += 4;

				WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr );
				
				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/*=======================================================================*/

				/*=======================================================================*/
				/* Update the bridge pointers. */

				if ( pBridgeEntry->usFirstLoadEventPtr == f_usLoadEventIndex )
					pBridgeEntry->usFirstLoadEventPtr = pLoadEventEntry->usNextEventPtr;

				if ( pBridgeEntry->usFirstSubStoreEventPtr == f_usSubStoreEventIndex )
					pBridgeEntry->usFirstSubStoreEventPtr = pSubStoreEventEntry->usNextEventPtr;

				if ( pBridgeEntry->usLastSubStoreEventPtr == f_usSubStoreEventIndex )
					pBridgeEntry->usLastSubStoreEventPtr = usPreviousEventIndex;
			
				/*=======================================================================*/


				/*=======================================================================*/
				/* Update the global mixer pointers. */

				if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex )
				{
					pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pLoadEventEntry->usNextEventPtr;
				}

				if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == f_usSubStoreEventIndex )
				{
					pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex;
				}
				/*=======================================================================*/

			}

			/* Check if must remove the Sin copy event from the event list. */
			if ( fRemoveSinCopy == TRUE )
			{
				/* Now remove the copy event from the event list. */
				ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, f_usCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}

			/* Get the channel. */
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );

			/* Reprogram the TSST entry correctly if the Extra SIN TSI entry was released. */
			if ( ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) && ( f_fTap == FALSE ) )
			{
				if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
				{
					ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																	  pEchoChanEntry->usSinTsstIndex,
																	  pEchoChanEntry->usSinSoutTsiMemIndex,
																	  pEchoChanEntry->TdmConfig.bySinPcmLaw );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}

				/* If the silence TSI is loaded on this port, update with the original sin TSI. */
				if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
				{
					WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

					WriteParams.ulWriteAddress += 2;
					WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex;

					mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
			}
			/* Set the event entries as free. */
			pLoadEventEntry->fReserved		= FALSE;
			pLoadEventEntry->usEventType	= cOCT6100_INVALID_INDEX;
			pLoadEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;

			pSubStoreEventEntry->fReserved		= FALSE;
			pSubStoreEventEntry->usEventType	= cOCT6100_INVALID_INDEX;
			pSubStoreEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;

			if ( pCopyEventEntry != NULL )
			{
				pCopyEventEntry->fReserved		= FALSE;
				pCopyEventEntry->usEventType	= cOCT6100_INVALID_INDEX;
				pCopyEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;
			}

			pBridgeEntry->usNumClients--;

			/*=======================================================================*/
			/* Update the event and channel API structure */
			pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX;
			pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX;

			/* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */
			if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
			{
				pEchoChanEntry->usExtraSinTsiDependencyCnt--;
				pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
			}
			else
			{
				/* Decrement the dependency count, but do not clear the mem index. */
				pEchoChanEntry->usExtraSinTsiDependencyCnt--;
			}

			/* Update the chip stats structure. */
			pSharedInfo->ChipStats.usNumEcChanUsingMixer--;

			if ( f_fTap == TRUE )
			{
				/* Can now close the bridge. */
				tOCT6100_CONF_BRIDGE_CLOSE	BridgeClose;

				Oct6100ConfBridgeCloseDef( &BridgeClose );

				BridgeClose.ulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pBridgeEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pEchoChanEntry->usTapBridgeIndex;

				ulResult = Oct6100ConfBridgeCloseSer( f_pApiInstance, &BridgeClose );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				pEchoChanEntry->usTapBridgeIndex = cOCT6100_INVALID_INDEX;
				pEchoChanEntry->fTap = FALSE;
			}

			/* Check if the Rin port must be muted. */
			ulResult = Oct6100ApiMutePorts( 
									f_pApiInstance, 
									f_usChanIndex, 
									pEchoChanEntry->usRinTsstIndex, 
									pEchoChanEntry->usSinTsstIndex,
									FALSE );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/
		}
		else /* f_ulBridgeChanRemove->fRemoveAll == TRUE ) */
		{
			UINT16 usNextEventPtr;

			/* Save the next event pointer before invalidating everything. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, pBridgeEntry->usLastSubStoreEventPtr );

			usNextEventPtr = pSubStoreEventEntry->usNextEventPtr;

			/* Search through the list of API channel entry for the ones on to the specified bridge. */
			for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i );
				
				if ( pEchoChanEntry->fReserved == TRUE )
				{
					if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) )
					{
						/* Check if we are being tapped.  If so, remove the channel that taps us from the conference. */
						/* The removal of the channel will make sure the Rin TSST is re-assigned. */
						if ( pEchoChanEntry->fBeingTapped == TRUE )
						{
							tOCT6100_CONF_BRIDGE_CHAN_REMOVE	ChanRemove;

							mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, pEchoChanEntry->usTapChanIndex );

							ulResult = Oct6100ConfBridgeChanRemoveDef( &ChanRemove );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;
							
							ChanRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | (pTempEchoChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pEchoChanEntry->usTapChanIndex;

							ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &ChanRemove );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;
						}
					
						/*=======================================================================*/
						/* Clear the Load event. */
						WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
						WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						/*=======================================================================*/
						
						/*=======================================================================*/
						/* Clear the Substract and store event. */
						WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
						WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
						
						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
						/*=======================================================================*/

						/*=======================================================================*/
						/* Clear the SIN copy event.*/
						
						if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
						{
							/* Transform event into no-operation. */
							WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
							WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
							
							mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							/* Get a pointer to the event entry. */
							mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, pEchoChanEntry->usSinCopyEventIndex );

							/* Update the next event pointer if required. */
							if ( usNextEventPtr == pEchoChanEntry->usSinCopyEventIndex )
								usNextEventPtr = pCopyEventEntry->usNextEventPtr;

							/* Now remove the copy event from the event list. */
							ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							/* Clear the copy event created flag. */
							pEchoChanEntry->fCopyEventCreated = FALSE;
						}

						/*=======================================================================*/


						/*=======================================================================*/
						/* Update the event and channel API structure */

						/* Reprogram the TSST entry correctly if the Extra SIN TSI entry was released.*/
						if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
						{
							if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
							{
								ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																				  pEchoChanEntry->usSinTsstIndex,
																				  pEchoChanEntry->usSinSoutTsiMemIndex,
																				  pEchoChanEntry->TdmConfig.bySinPcmLaw );
								if ( ulResult != cOCT6100_ERR_OK )
									return ulResult;
							}

							/* If the silence TSI is loaded on this port, update with the original Sin TSI. */
							if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
							{
								WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

								WriteParams.ulWriteAddress += 2;
								WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex;

								mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
								if ( ulResult != cOCT6100_ERR_OK )
									return ulResult;
							}
						}

						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, pEchoChanEntry->usLoadEventIndex );
						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, pEchoChanEntry->usSubStoreEventIndex );

						/* Set the event entries as free. */
						pLoadEventEntry->fReserved		= FALSE;
						pLoadEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
						pLoadEventEntry->usNextEventPtr	= cOCT6100_INVALID_INDEX;

						pSubStoreEventEntry->fReserved		= FALSE;
						pSubStoreEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
						pSubStoreEventEntry->usNextEventPtr	= cOCT6100_INVALID_INDEX;

						if ( pCopyEventEntry != NULL )
						{
							pCopyEventEntry->fReserved		= FALSE;
							pCopyEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
							pCopyEventEntry->usNextEventPtr	= cOCT6100_INVALID_INDEX;
						}

						/* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */
						if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 )
						{
							pEchoChanEntry->usExtraSinTsiDependencyCnt--;
							pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;
						}
						else
						{
							/* Decrement the dependency count, but do not clear the mem index. */
							pEchoChanEntry->usExtraSinTsiDependencyCnt--;
						}

						/* Invalidate the channel entry. */
						pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX;
						pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX;
						pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX;

						/* Update the chip stats structure. */
						pSharedInfo->ChipStats.usNumEcChanUsingMixer--;

						/*=======================================================================*/
					}
				}
			}
		
			ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
			{
				if ( cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND == ulResult )
				{
					if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
					{
						usPreviousEventIndex = cOCT6100_MIXER_HEAD_NODE;
					}
					else
					{
						usPreviousEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
					}
				}
				else
				{
					return cOCT6100_ERR_FATAL_28;
				}
			}

			/* An Entry was found, now, modify it's value. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex );

			/* Now modify the previous last Sub Store event from another bridge.*/
			/* It will now point at the next bridge, or copy events. */
			pTempEntry->usNextEventPtr = usNextEventPtr;

			/*=======================================================================*/
			/* Modify the last node of the other bridge. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = pTempEntry->usNextEventPtr;
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
			/*=======================================================================*/
			
			/*=======================================================================*/
			/* Update the global mixer pointers. */
			if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == pBridgeEntry->usFirstLoadEventPtr &&
				 pSharedInfo->MixerInfo.usLastBridgeEventPtr  == pBridgeEntry->usLastSubStoreEventPtr )
			{
				/* This bridge was the only one with event in the list. */
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX;
				pSharedInfo->MixerInfo.usLastBridgeEventPtr  = cOCT6100_INVALID_INDEX;
			}
			else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == pBridgeEntry->usFirstLoadEventPtr )
			{
				/* This bridge was the first bridge. */
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = usNextEventPtr;
			}
			else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == pBridgeEntry->usLastSubStoreEventPtr )
			{
				/* This bridge was the last bridge.*/
				pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex;
			}
			/*=======================================================================*/

			/* Set the event pointer info in the bridge stucture. */
			pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX;
			pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX;
			pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX;
			pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX;

			pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX;

			/* Set the number of clients to 0. */
			pBridgeEntry->usNumClients = 0;

			/* Search through the list of API channel entry for the ones on to the specified bridge. */
			for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i );
				
				if ( pEchoChanEntry->fReserved == TRUE )
				{
					if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) )
					{
						pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX;

						/* Check if the Rin port must be muted. */
						ulResult = Oct6100ApiMutePorts( 
												f_pApiInstance, 
												(UINT16)( i & 0xFFFF ), 
												pEchoChanEntry->usRinTsstIndex, 
												pEchoChanEntry->usSinTsstIndex,
												FALSE );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
					}
				}
			}
		}
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeRemoveParticipantFromChannel

Description:    This will remove a flexible conference participant from
				a channel.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_usBridgeIndex				Bridge index where this channel is located.
f_usSourceChannelIndex		Source channel to copy voice from.
f_usDestinationChannelIndex	Destination channel to store resulting voice to.
f_fRemovePermanently		Whether to remove permanently this participant.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiBridgeRemoveParticipantFromChannel(
				IN OUT	tPOCT6100_INSTANCE_API	f_pApiInstance, 
				IN		UINT16					f_usBridgeIndex,
				IN		UINT16					f_usSourceChannelIndex,
				IN		UINT16					f_usDestinationChannelIndex,
				IN		UINT8					f_fRemovePermanently )
{
	tPOCT6100_API_CONF_BRIDGE			pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT			pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT			pStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT			pCopyEventEntry;
	tPOCT6100_API_MIXER_EVENT			pTempEntry;
	tPOCT6100_API_MIXER_EVENT			pLoadTempEntry;
	tPOCT6100_API_MIXER_EVENT			pLastEventEntry;
	tPOCT6100_API_MIXER_EVENT			pLastLoadOrAccumulateEventEntry;

	tPOCT6100_API_CHANNEL				pSourceChanEntry;
	tPOCT6100_API_CHANNEL				pDestinationChanEntry;

	tPOCT6100_API_FLEX_CONF_PARTICIPANT	pSourceParticipant;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT	pDestinationParticipant;

	tPOCT6100_SHARED_INFO				pSharedInfo;
	tOCT6100_WRITE_PARAMS				WriteParams;
	tOCT6100_READ_PARAMS				ReadParams;

	UINT32								ulResult;
	UINT32								ulLoopCount;
	UINT16								usLastLoadEventIndex;
	UINT16								usLoadOrAccumulateEventIndex;
	UINT16								usTempEventIndex;
	UINT16								usPreviousEventIndex;
	UINT16								usLastEventIndex;

	UINT16								usReadData;
	BOOL								fLastEvent = FALSE;
	BOOL								fSoutCopyEvent = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
	ReadParams.pusReadData = &usReadData;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex );

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceChanEntry, f_usSourceChannelIndex );
	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceParticipant, pSourceChanEntry->usFlexConfParticipantIndex );
	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationChanEntry, f_usDestinationChannelIndex );
	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationParticipant, pDestinationChanEntry->usFlexConfParticipantIndex );

	/* Check if the mixer has been created on this channel. */
	if ( pDestinationParticipant->fFlexibleMixerCreated == TRUE )
	{
		/*=======================================================================*/
		/* Clear the Load or Accumulate event.*/

		usTempEventIndex = pDestinationChanEntry->usLoadEventIndex;
		ulLoopCount = 0;

		/* Find the Load or Accumulate event entry. */
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, usTempEventIndex );
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pStoreEventEntry, pDestinationChanEntry->usSubStoreEventIndex );
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

		pLastEventEntry = pLoadEventEntry;
		pLastLoadOrAccumulateEventEntry = pLoadEventEntry;
		usLastLoadEventIndex = usTempEventIndex;
		usLastEventIndex = usTempEventIndex;

		while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && 
			   pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE )
		{
			/* If this is the entry we are looking for. */
			if ( pTempEntry->usSourceChanIndex == f_usSourceChannelIndex )
			{
				/* Check if this is a Load or Accumulate event. */
				if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD )
				{
					/* This is the first entry.  Check if next entry is an accumulate. */
					pLoadTempEntry = pTempEntry;
					mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, pTempEntry->usNextEventPtr );

					if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE )
					{
						/* Change this entry into a Load event. */
						ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pLoadTempEntry->usNextEventPtr * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
						mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						WriteParams.ulWriteAddress = ReadParams.ulReadAddress;
						WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD);

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
						
						/* Update the channel information with this new load event. */
						pDestinationChanEntry->usLoadEventIndex = pLoadTempEntry->usNextEventPtr;

						/* Update the software model. */
						pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;

						/* Get the previous event. */
						ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex );
						usLastEventIndex = usPreviousEventIndex;

						/* Stop searching. */
						break;
					}
					else if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE )
					{
						/* Get back the event to remove. */
						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

						/* This is the only event on this channel so we can clear everything up. */
						fLastEvent = TRUE;

						/* Get the previous event. */
						ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex );
						usLastEventIndex = usPreviousEventIndex;

						/* Stop searching. */
						break;
					}
					else
					{
						/* Software model is broken. */
						return cOCT6100_ERR_FATAL_C5;
					}
					
				}
				else if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE )
				{
					/* Simply remove the entry. */

					/* Get the previous event. */
					ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;

					mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex );
					usLastEventIndex = usPreviousEventIndex;

					/* Stop searching. */
					break;
				}
				else
				{
					/* Software model is broken. */
					return cOCT6100_ERR_FATAL_C6;
				}
			}

			pLastLoadOrAccumulateEventEntry = pTempEntry;
			usLastLoadEventIndex = usTempEventIndex;

			/* Go to the next entry into the list. */
			usTempEventIndex = pTempEntry->usNextEventPtr;
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

			ulLoopCount++;
			if ( ulLoopCount == cOCT6100_MAX_LOOP )
				return cOCT6100_ERR_FATAL_C8;
		}

		/* Check if we found what we were looking for. */
		if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE 
			|| pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_SUB_STORE )
		{
			/* Software model is broken. */
			return cOCT6100_ERR_FATAL_C7;
		}

		/*=======================================================================*/


		/*=======================================================================*/
		/* Clear the Store event - if needed. */

		if ( fLastEvent == TRUE )
		{
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}

		/*=======================================================================*/


		/*=======================================================================*/
		/* Clear the Load or Accumulate event. */

		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/* Save this event index.  It's the Load or Accumulate we want to remove from the list later. */
		usLoadOrAccumulateEventIndex = usTempEventIndex;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Clear the Copy event - if needed. */
		
		if ( ( fLastEvent == TRUE ) && ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( f_fRemovePermanently == TRUE ) )
		{
			/* Transform event into no-operation. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* The event remove from the list will be done below. */

			/* Clear the copy event created flag. */
			pDestinationChanEntry->fCopyEventCreated = FALSE;
		}

		/*=======================================================================*/


		/*=======================================================================*/
		/*=======================================================================*/
		/* Remove the events from the mixer event list.*/
		/*=======================================================================*/
		/*=======================================================================*/

		/*=======================================================================*/
		/* Remove the Load or Accumulate event from the event list. */
		
		if ( fLastEvent == FALSE )
		{
			/*=======================================================================*/
			/* Remove the Accumulate event from the event list. */

			/* We saved the Load or Accumulate event above.  We also saved the previous event.  Use those. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, usLoadOrAccumulateEventIndex );
			
			/* Now modify the previous last event. */
			pLastEventEntry->usNextEventPtr = pLoadEventEntry->usNextEventPtr;

			/* Modify the previous node. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = pLastEventEntry->usNextEventPtr;
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
			
			/* Check if this is the first load event on the bridge. */
			if ( pBridgeEntry->usFirstLoadEventPtr == usLoadOrAccumulateEventIndex )
			{
				pBridgeEntry->usFirstLoadEventPtr = pLoadEventEntry->usNextEventPtr;
			}

			/* Check if this was the first load of all bridges. */
			if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex )
			{
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pLoadEventEntry->usNextEventPtr;
			}

			/*=======================================================================*/
		}
		else /* if ( fLastEvent == TRUE ) */
		{
			/*=======================================================================*/
			/* Remove the Load event from the event list. */

			/* Look for the entry that is pointing at the first entry of our mixer. */
			ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usLoadOrAccumulateEventIndex, 0, &usPreviousEventIndex );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* An Entry was found, now, modify it's value. */
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex );

			/* Check if this is a Sout copy event. */
			if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_COPY )
			{
				/* No more previous bridges. */
				fSoutCopyEvent = TRUE;
			}

			/* Now modify the previous last Store or Sub-Store or Head-Node event from another bridge/channel. */
			pTempEntry->usNextEventPtr = pStoreEventEntry->usNextEventPtr;

			/*=======================================================================*/


			/*=======================================================================*/
			/* Modify the last node of the previous bridge/channel to point to the next bridge. */

			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			WriteParams.ulWriteAddress += 4;

			WriteParams.usWriteData = pTempEntry->usNextEventPtr;
			
			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/
			
			
			/*=======================================================================*/
			/* Set the event pointer info in the bridge stucture. */

			if ( pBridgeEntry->usFirstLoadEventPtr == pDestinationChanEntry->usLoadEventIndex )
			{
				UINT16					usChannelIndex;
				tPOCT6100_API_CHANNEL	pTempEchoChanEntry;

				pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX;
				pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX;

				/* Find the next channel in this conference that could give us valid values. */
				for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
				{
					mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );

					if ( ( usChannelIndex != f_usDestinationChannelIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
					{
						if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
						{
							tPOCT6100_API_FLEX_CONF_PARTICIPANT	pTempParticipant;

							mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

							if ( pTempParticipant->fFlexibleMixerCreated == TRUE )
							{
								pBridgeEntry->usFirstSubStoreEventPtr = pTempEchoChanEntry->usSubStoreEventIndex;
								pBridgeEntry->usFirstLoadEventPtr = pTempEchoChanEntry->usLoadEventIndex;
								break;
							}
						}
					}
				}
			}

			/* Reprogram the TSST entry correctly if the extra SIN TSI entry was released. */
			if ( ( pDestinationChanEntry->usExtraSinTsiDependencyCnt == 1 ) && ( f_fRemovePermanently == TRUE ) )
			{
				if ( pDestinationChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
				{
					ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																	  pDestinationChanEntry->usSinTsstIndex,
																	  pDestinationChanEntry->usSinSoutTsiMemIndex,
																	  pDestinationChanEntry->TdmConfig.bySinPcmLaw );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}

				/* If the silence TSI is loaded on this port, update with the original sin TSI. */
				if ( pDestinationChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
				{
					WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

					WriteParams.ulWriteAddress += 2;
					WriteParams.usWriteData = pDestinationChanEntry->usSinSoutTsiMemIndex;

					mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
			}

			/* Reprogram the TSST entry correctly if the extra RIN TSI entry was released. */
			if ( ( pDestinationChanEntry->usExtraRinTsiDependencyCnt == 1 ) && ( f_fRemovePermanently == TRUE ) )
			{
				if ( pDestinationChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX )
				{
					ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																	  pDestinationChanEntry->usRinTsstIndex,
																	  pDestinationChanEntry->usRinRoutTsiMemIndex,
																	  pDestinationChanEntry->TdmConfig.byRinPcmLaw );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
			}

			/*=======================================================================*/
			/* Update the global mixer pointers. */

			if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex &&
				 pSharedInfo->MixerInfo.usLastBridgeEventPtr  == pDestinationChanEntry->usSubStoreEventIndex )
			{
				/* There is no more bridge entry in the mixer link list. */
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX;
				pSharedInfo->MixerInfo.usLastBridgeEventPtr  = cOCT6100_INVALID_INDEX;
			}
			else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex )
			{
				pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pStoreEventEntry->usNextEventPtr;
			}
			else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == pDestinationChanEntry->usSubStoreEventIndex )
			{
				pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex;
			}

			/*=======================================================================*/


			/*=======================================================================*/
			/* Check if must remove the Sin copy event from the list. */

			if ( ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( f_fRemovePermanently == TRUE ) )
			{
				/* Now remove the copy event from the event list. */
				ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pDestinationChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
			}

			/*=======================================================================*/



			/*=======================================================================*/

			if ( f_fRemovePermanently == TRUE )
			{
				/* Set the event entries as free. */
				pLoadEventEntry->fReserved		= FALSE;
				pLoadEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
				pLoadEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;

				pStoreEventEntry->fReserved		= FALSE;
				pStoreEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
				pStoreEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;

				if ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
				{
					mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, pDestinationChanEntry->usSinCopyEventIndex );
					
					pCopyEventEntry->fReserved		= FALSE;
					pCopyEventEntry->usEventType	= cOCT6100_INVALID_EVENT;
					pCopyEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX;
				}
			}

			/* Flexible mixer for this channel not created anymore. */
			pDestinationParticipant->fFlexibleMixerCreated = FALSE;

			/*=======================================================================*/
		}

		/*=======================================================================*/
	}
	else /* if ( pDestinationChanEntry->fFlexibleMixerCreated == FALSE ) */
	{
		/* This point should never be reached. */
		return cOCT6100_ERR_FATAL_C9;
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanMuteSer

Description:    Mute an echo channel present on a conference bridge. 

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeMute		Pointer to conference bridge mute structure.  

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanMuteSer(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_MUTE		f_pConfBridgeMute )
{
	UINT16	usChanIndex;
	UINT16	usLoadEventIndex;
	UINT16	usSubStoreEventIndex;
	UINT32	ulResult;
	UINT8	fFlexibleConferencing;

	/* Check the validity of the channel and conference bridge given. */
	ulResult = Oct6100ApiCheckBridgeMuteParams( 
										f_pApiInstance, 
										f_pConfBridgeMute, 
										&usChanIndex, 
										&usLoadEventIndex, 
										&usSubStoreEventIndex, 
										&fFlexibleConferencing );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Modify all resources needed by the conference bridge. */
	ulResult = Oct6100ApiUpdateBridgeMuteResources( 
										f_pApiInstance, 
										usChanIndex, 
										usLoadEventIndex, 
										usSubStoreEventIndex,
										fFlexibleConferencing );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeMuteParams

Description:	Check the validity of the channel and conference bridge given.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_pConfBridgeMute			Pointer to conference bridge channel mute structure.  
f_pusChannelIndex		Pointer to a channel index.
f_pusLoadEventIndex		Pointer to a load mixer event index.
f_pusSubStoreEventIndex	Pointer to a sub-store mixer event index.
f_pfFlexibleConfBridge	If this is a flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeMuteParams(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_MUTE		f_pConfBridgeMute,
				OUT		PUINT16								f_pusChannelIndex,
				OUT		PUINT16								f_pusLoadEventIndex,
				OUT		PUINT16								f_pusSubStoreEventIndex, 
				OUT		PUINT8								f_pfFlexibleConfBridge )
{
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;
	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	UINT32	ulEntryOpenCnt;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;
	
	if ( f_pConfBridgeMute->ulChannelHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE;

	/*=====================================================================*/
	/* Check the channel handle.*/

	if ( (f_pConfBridgeMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	*f_pusChannelIndex = (UINT16)( f_pConfBridgeMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pEchoChanEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/* Check if the channel is bound to a conference bridge. */
	if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;

	/* Check if channel is already muted. */
	if ( pEchoChanEntry->fMute == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_ALREADY_MUTED;

	/* Check if this is a tap channel, which is always mute. */
	if ( pEchoChanEntry->fTap == TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_ALWAYS_MUTE;

	/*=====================================================================*/

	/*=====================================================================*/
	/* Check the conference bridge handle. */

	if ( pEchoChanEntry->usBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pEchoChanEntry->usBridgeIndex )

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;

	if ( pBridgeEntry->fFlexibleConferencing == FALSE )
	{
		/* Check the event entries.*/
		if ( pEchoChanEntry->usLoadEventIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;

		if ( pEchoChanEntry->usSubStoreEventIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;
	}

	/*=====================================================================*/

	/* Return the config of the channel and all other important information. */
	*f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex;
	*f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex;
	*f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiUpdateBridgeMuteResources

Description:    Modify the conference bridge entry for this channel in order 
				to mute the specified channel.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_usChanIndex				Index of the channel to be muted.	
f_usLoadEventIndex			Allocated entry for the Load event of the channel.
f_usSubStoreEventIndex		Allocated entry for the substract and store event of the channel.
f_fFlexibleConfBridge		If this is a flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiUpdateBridgeMuteResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usChanIndex,
				IN		UINT16							f_usLoadEventIndex,
				IN		UINT16							f_usSubStoreEventIndex, 
				IN		UINT8							f_fFlexibleConfBridge )
{
	tOCT6100_WRITE_PARAMS			WriteParams;
	tOCT6100_READ_PARAMS			ReadParams;

	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	tPOCT6100_SHARED_INFO			pSharedInfo;

	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT		pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT		pSubStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT		pTempEntry;
	UINT32	ulResult;
	UINT16	usTempEventIndex;
	UINT32	ulLoopCount;
	UINT16	usReadData;

	BOOL	fCreateSilenceLoad = FALSE;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
	ReadParams.pusReadData = &usReadData;
	
	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );
	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry,  pEchoChanEntry->usBridgeIndex )

	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_CHANNEL				pTempEchoChanEntry;
		UINT16								usChannelIndex;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;

		UINT16	ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ];
		UINT32	ulMutePortChannelIndex;

		for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
			ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX;

		mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

		/* Search through the list of API channel entry for the ones on to this bridge. */
		for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );

			if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
			{
				if ( pTempEchoChanEntry->usBridgeIndex == pEchoChanEntry->usBridgeIndex )
				{
					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

					/* Check if this participant can hear us. */
					if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 )
						&& ( pTempParticipant->fFlexibleMixerCreated == TRUE ) )
					{
						/* Then update this channel's mixer. */
						ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
													f_pApiInstance,
													pEchoChanEntry->usBridgeIndex,
													f_usChanIndex,
													usChannelIndex,
													FALSE );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						if ( pTempParticipant->fFlexibleMixerCreated == FALSE )
						{
							/* Remember to mute the port on this channel. */
							for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
							{
								if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usChannelIndex )
								{
									break;
								}
								else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX )
								{
									ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usChannelIndex;
									break;
								}
							}
						}
					}
				}
			}
		}

		/* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */
		for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
		{
			if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] );

				mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );
				
				if ( pTempParticipant->fFlexibleMixerCreated == FALSE )
				{
					/* Check if the Rin port must be muted on this channel. */
					ulResult = Oct6100ApiMutePorts( 
											f_pApiInstance, 
											ausMutePortChannelIndexes[ ulMutePortChannelIndex ], 
											pTempEchoChanEntry->usRinTsstIndex, 
											pTempEchoChanEntry->usSinTsstIndex,
											FALSE );
					if ( ulResult != cOCT6100_ERR_OK )
					{
						if ( ulResult == cOCT6100_ERR_MIXER_ALL_MIXER_EVENT_ENTRY_OPENED )
						{
							UINT32 ulTempResult;

							/* Cleanup resources, unmute channel... */
							ulTempResult = Oct6100ApiUpdateBridgeUnMuteResources(
											f_pApiInstance,
											f_usChanIndex,
											f_usLoadEventIndex,
											f_usSubStoreEventIndex, 
											TRUE );
							if ( ulTempResult != cOCT6100_ERR_OK )
								return ulTempResult;
							else
								return ulResult;
						}
						else
						{
							return ulResult;
						}
					}
				}
			}
			else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */
			{
				/* No more channels to check for muting. */
				break;
			}
		}
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex );
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex );

		/*=======================================================================*/
		/* Program the Load event. */

		/* Create silence load if this is the first event of the bridge. */
		if ( f_usLoadEventIndex == pBridgeEntry->usFirstLoadEventPtr )
			fCreateSilenceLoad = TRUE;

		/* First check if this event was a load or an accumulate event, if it's a load */
		/* we need to find a new load. */
		if ( f_usLoadEventIndex == pBridgeEntry->usLoadIndex )
		{
			/* Change the next entry if one is present to a load event to keep the bridge alive. */
			if ( pBridgeEntry->usNumClients == 1 )
			{
				/* There is no other entry on the bridge, no need to search for an Accumulate event. */
				pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX;
			}
			else
			{
				/* Search for an accumulate event to tranform into a Load event. */
				usTempEventIndex = pLoadEventEntry->usNextEventPtr;
				ulLoopCount = 0;

				/* Find the copy entry before the entry to remove. */
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

				while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && 
					   pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE )
				{
					if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE )
					{
						/* Change this entry into a load event. */
						ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
						mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						WriteParams.ulWriteAddress = ReadParams.ulReadAddress;
						WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD);

						mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;
						
						/* Set this entry as the load index. */
						pBridgeEntry->usLoadIndex = usTempEventIndex;

						/* Update the software model. */
						pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;

						/* Stop searching. */
						break;
					}
					
					/* Go to the next entry into the list. */
					usTempEventIndex = pTempEntry->usNextEventPtr;
					mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

					ulLoopCount++;
					if ( ulLoopCount == cOCT6100_MAX_LOOP )
						return cOCT6100_ERR_FATAL_9B;
				}
			}
		}

		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

		/* Do not load the sample if the channel is muted. */
		if ( fCreateSilenceLoad == TRUE )
		{
			if ( pBridgeEntry->usSilenceLoadEventPtr == cOCT6100_INVALID_INDEX )
			{
				/* Instead of No-oping, load the silence TSI, to make sure the other conferences before us are not heard. */
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD;
				WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */

				/* Remember the silence load event. */
				pBridgeEntry->usSilenceLoadEventPtr = f_usLoadEventIndex;
			}
			else
			{
				/* Do nothing. */
				WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
			}
		}
		else
		{
			/* Do nothing. */
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
		}

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/* Update the software model. */
		pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP;

		/*=======================================================================*/
		
		/*=======================================================================*/
		/* Program the Substract and store event. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		/* Do not load the sample if the channel is muted. */
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE;

		/* If we have an extra Sin copy event, we know we are using the Sout port as a source. */
		if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
		{
			/* Sout input. */
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
		}
		else /* if ( pEchoChanEntry->usSinCopyEventIndex == cOCT6100_INVALID_INDEX ) */
		{
			/* Rin input. */
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
		}

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/* Update the software model. */
		pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE;

		/*=======================================================================*/
	}

	/* Update the channel entry API structure */
	pEchoChanEntry->fMute = TRUE;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeChanUnMuteSer

Description:    UnMute an echo channel present on a conference bridge. 

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeUnMute		Pointer to conference bridge channel unmute structure.  

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeChanUnMuteSer(
				IN OUT	tPOCT6100_INSTANCE_API					f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE		f_pConfBridgeUnMute )
{
	UINT16	usChanIndex;
	UINT16	usLoadEventIndex;
	UINT16	usSubStoreEventIndex;
	UINT8	fFlexibleConfBridge;
	UINT32	ulResult;

	/* Check the validity of the channel and conference bridge given. */
	ulResult = Oct6100ApiCheckBridgeUnMuteParams( 
											f_pApiInstance, 
											f_pConfBridgeUnMute, 
											&usChanIndex, 
											&usLoadEventIndex, 
											&usSubStoreEventIndex, 
											&fFlexibleConfBridge );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Modify all resources needed by the conference bridge. */
	ulResult = Oct6100ApiUpdateBridgeUnMuteResources( 
											f_pApiInstance, 
											usChanIndex, 
											usLoadEventIndex, 
											usSubStoreEventIndex, 
											fFlexibleConfBridge );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeUnMuteParams

Description:	Check the validity of the channel and conference bridge given.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_pConfBridgeUnMute			Pointer to conference bridge channel unmute structure.  
f_pusChannelIndex			Pointer to the channel index fo the channel to be unmuted.
f_pusLoadEventIndex			Pointer to the load index of the channel.
f_pusSubStoreEventIndex		Pointer to the sub-store event of the channel.
f_pfFlexibleConfBridge		If this is a flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeUnMuteParams(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE	f_pConfBridgeUnMute,
				OUT		PUINT16								f_pusChannelIndex,
				OUT		PUINT16								f_pusLoadEventIndex,
				OUT		PUINT16								f_pusSubStoreEventIndex, 
				OUT		PUINT8								f_pfFlexibleConfBridge )
{
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;
	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	UINT32	ulEntryOpenCnt;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;
	
	if ( f_pConfBridgeUnMute->ulChannelHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE;

	/*=====================================================================*/
	/* Check the channel handle.*/

	if ( (f_pConfBridgeUnMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	*f_pusChannelIndex = (UINT16)( f_pConfBridgeUnMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeUnMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pEchoChanEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/* Check if the channel is bound to a conference bridge.*/
	if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;

	/* Check if channel is already muted.*/
	if ( pEchoChanEntry->fMute == FALSE )
		return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_NOT_MUTED;

	/*=====================================================================*/

	/*=====================================================================*/
	/* Check the conference bridge handle. */

	if (  pEchoChanEntry->usBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry,  pEchoChanEntry->usBridgeIndex )

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	
	/* Check the event entries.*/
	if ( pBridgeEntry->fFlexibleConferencing == FALSE )
	{
		if ( pEchoChanEntry->usLoadEventIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;

		/* Check the event entries.*/
		if ( pEchoChanEntry->usSubStoreEventIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE;
	}

	/*=====================================================================*/

	/* Return the config of the channel and all other important information.*/
	*f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex;
	*f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex;
	*f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiUpdateBridgeUnMuteResources

Description:    Modify the conference bridge entry for this channel in order 
				to un-mute the specified channel.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_usChanIndex				Index of the channel to be unmuted.	
f_usLoadEventIndex			Allocated entry for the Load event of the channel.
f_usSubStoreEventIndex		Allocated entry for the substract and store event of the channel.
f_fFlexibleConfBridge		If this is a flexible conference bridge.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiUpdateBridgeUnMuteResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usChanIndex,
				IN		UINT16							f_usLoadEventIndex,
				IN		UINT16							f_usSubStoreEventIndex, 
				IN		UINT8							f_fFlexibleConfBridge )
{
	tOCT6100_WRITE_PARAMS			WriteParams;
	tOCT6100_READ_PARAMS			ReadParams;

	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	tPOCT6100_SHARED_INFO			pSharedInfo;

	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;

	tPOCT6100_API_MIXER_EVENT		pLoadEventEntry;
	tPOCT6100_API_MIXER_EVENT		pSubStoreEventEntry;
	tPOCT6100_API_MIXER_EVENT		pTempEntry;
	UINT32	ulResult;
	UINT16	usTempEventIndex;
	UINT32	ulLoopCount;
	UINT16	usReadData;
	
	UINT16	usLoadEventType		= cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;
	UINT16	usPreviousLoadIndex = cOCT6100_INVALID_INDEX;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;
	
	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
	ReadParams.pusReadData = &usReadData;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex );
	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry,  pEchoChanEntry->usBridgeIndex )
	
	if ( f_fFlexibleConfBridge == TRUE )
	{
		tPOCT6100_API_CHANNEL				pTempEchoChanEntry;
		UINT16								usChannelIndex;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
		tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;

		mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex );

		/* Before doing anything, check if the copy events must be created. */
		if ( ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChanEntry->fCopyEventCreated == FALSE ) )
		{
			/* The copy event has not been created, create it once for the life of the participant on the bridge. */
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			
			WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY;
			WriteParams.usWriteData |= pEchoChanEntry->usExtraSinTsiMemIndex;
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			WriteParams.ulWriteAddress += 2;
			WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Now insert the Sin copy event into the list. */
			ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance,
												pEchoChanEntry->usSinCopyEventIndex,
												cOCT6100_EVENT_TYPE_SIN_COPY,
												f_usChanIndex );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			pEchoChanEntry->fCopyEventCreated = TRUE;
		}
		
		/* Search through the list of API channel entry for the ones onto this bridge. */
		for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
			
			/* Channel reserved? */
			if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
			{
				/* On current bridge? */
				if ( pTempEchoChanEntry->usBridgeIndex == pEchoChanEntry->usBridgeIndex )
				{
					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

					/* Check if this participant can hear us. */
					if ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 )
					{
						/* Then create/update this channel's mixer. */
						ulResult = Oct6100ApiBridgeAddParticipantToChannel(
													f_pApiInstance,
													pEchoChanEntry->usBridgeIndex,
													f_usChanIndex,
													usChannelIndex,
													pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ],
													pTempEchoChanEntry->usSubStoreEventIndex,
													pTempEchoChanEntry->usSinCopyEventIndex,
													pParticipant->ulInputPort,
													pTempParticipant->ulInputPort );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						/* Check if the Rin silence event can be cleared now that the */
						/* channel has unmuted. */
						if ( ( pTempParticipant->fFlexibleMixerCreated == TRUE )
							&& ( pTempEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) )
						{
							/* Remove the event from the list. */
							ulResult = Oct6100ApiMixerEventRemove(	f_pApiInstance,
																	pTempEchoChanEntry->usRinSilenceEventIndex,
																	cOCT6100_EVENT_TYPE_SOUT_COPY );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex );
							if ( ulResult != cOCT6100_ERR_OK )
								return cOCT6100_ERR_FATAL_DF;

							pTempEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX;
						}
					}
				}
			}
		}
	}
	else /* if ( f_fFlexibleConfBridge == FALSE ) */
	{
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex );
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex );

		/*=======================================================================*/
		/* Program the Load event. */

		/* Before reactivating this event, check what type of event this event must be. */
		if ( f_usLoadEventIndex == pBridgeEntry->usFirstLoadEventPtr ||
			 pBridgeEntry->usLoadIndex == cOCT6100_INVALID_INDEX )
		{
			/* This event must become a Load event. */
			usLoadEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;
			pBridgeEntry->usLoadIndex = f_usLoadEventIndex;
		}

		usTempEventIndex = pBridgeEntry->usFirstLoadEventPtr;
		mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

		ulLoopCount = 0;

		while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && 
			   pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE )
		{
			if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD )
			{
				usPreviousLoadIndex = usTempEventIndex;
			}

			/* Check if the previous load event is before or after the event about to be unmuted. */
			if ( pTempEntry->usNextEventPtr == f_usLoadEventIndex )
			{
				if ( usPreviousLoadIndex == cOCT6100_INVALID_INDEX )
				{
					/* We did not find a load event before our node, this mean this one */
					/* is about to become the new load event. */
					usLoadEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD;
				}
			}
			
			/* Go to the next entry into the list. */
			usTempEventIndex = pTempEntry->usNextEventPtr;
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex );

			ulLoopCount++;
			if ( ulLoopCount == cOCT6100_MAX_LOOP )
				return cOCT6100_ERR_FATAL_9B;
		}	
		
		/* Now program the current event node. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		WriteParams.usWriteData = usLoadEventType;

		/* If we have an extra Sin copy event, we know we are using the Sout port as a source. */
		if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
		{
			/* Sout source */
			WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex;
		}
		else
		{
			/* Rin source */
			WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex;
		}
		
		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;
		
		/* Update the software event to reflect the hardware. */
		pLoadEventEntry->usEventType = usLoadEventType;

		/* Check if we need to change another node. */
		if ( usLoadEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD )
		{
			if ( usPreviousLoadIndex != cOCT6100_INVALID_INDEX )
			{
				/* Now program the old load event. */
				ReadParams.ulReadAddress =  cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousLoadIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			
				mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
				
				WriteParams.ulWriteAddress = ReadParams.ulReadAddress;
				WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE );
				
				mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;
		
				/* Update the software event to reflect the hardware. */
				mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousLoadIndex );
				pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE;
			}
		}

		/*=======================================================================*/
		
		/*=======================================================================*/
		/* Program the Substract and store event. */
		WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
		
		WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE;
		/* If we have an extra Sin copy event, we know we are using the Sout port as a source. */
		if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX )
		{
			/* Sout port source */
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex;
		}
		else
		{
			/* Rin port source */
			WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex;
		}

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		WriteParams.ulWriteAddress += 2;
		WriteParams.usWriteData = pEchoChanEntry->usRinRoutTsiMemIndex;

		mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/* Update the software event to reflect the hardware. */
		pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE;

		/*=======================================================================*/


		/*=======================================================================*/
		/* Check if have to remove silence load event. */

		if ( pBridgeEntry->usSilenceLoadEventPtr != cOCT6100_INVALID_INDEX )
		{
			if ( pBridgeEntry->usSilenceLoadEventPtr == f_usLoadEventIndex )
			{
				/* Clear the silence load event ptr. */
				pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX;
			}
		}
	}

	/* Update the channel entry API structure */
	pEchoChanEntry->fMute = FALSE;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeDominantSpeakerSetSer

Description:    This function sets the dominant speaker of a bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to 
						keep the present state of the chip and all its 
						resources.

f_pConfBridgeDominant	Pointer to conference bridge dominant speaker 
						structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeDominantSpeakerSetSer(
				IN OUT	tPOCT6100_INSTANCE_API						f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET	f_pConfBridgeDominantSpeaker )
{
	UINT16	usChanIndex;
	UINT16	usBridgeIndex;
	UINT32	ulResult;

	/* Check the validity of the channel handle given. */
	ulResult = Oct6100ApiCheckBridgeDominantSpeakerParams( f_pApiInstance, f_pConfBridgeDominantSpeaker, &usChanIndex, &usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Modify all resources needed by the conference bridge. */
	ulResult = Oct6100ApiUpdateBridgeDominantSpeakerResources( f_pApiInstance, usChanIndex, usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeDominantSpeakerParams

Description:	Check the validity of the channel given for setting the
				dominant speaker.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.
f_pConfBridgeDominant	Pointer to conference bridge channel dominant speaker structure.  
f_pusChannelIndex		Pointer to a channel index.
f_pusChannelIndex		Pointer to a bridge index.
\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeDominantSpeakerParams(
				IN OUT	tPOCT6100_INSTANCE_API						f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET	f_pConfBridgeDominantSpeaker,
				OUT		PUINT16										f_pusChannelIndex,
				OUT		PUINT16										f_pusBridgeIndex )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_CHANNEL		pEchoChanEntry;
	UINT32	ulEntryOpenCnt;
	BOOL	fCheckEntryOpenCnt = FALSE;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;
	
	if ( f_pConfBridgeDominantSpeaker->ulChannelHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/*=====================================================================*/
	/* Check the channel handle. */

	if ( f_pConfBridgeDominantSpeaker->ulChannelHndl != cOCT6100_CONF_NO_DOMINANT_SPEAKER_HNDL )
	{
		if ( (f_pConfBridgeDominantSpeaker->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		*f_pusChannelIndex = (UINT16)( f_pConfBridgeDominantSpeaker->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
		if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = (f_pConfBridgeDominantSpeaker->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

		/* Check for errors. */
		if ( pEchoChanEntry->fReserved != TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
		if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		/* Check if the channel is bound to a conference bridge. */
		if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX )
			return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE;

		/* Check if the NLP is enabled on this channel. */
		if ( pEchoChanEntry->VqeConfig.fEnableNlp == FALSE )
			return cOCT6100_ERR_CONF_BRIDGE_NLP_MUST_BE_ENABLED;

		/* Check if conferencing noise reduction is enabled on this channel. */
		if ( pEchoChanEntry->VqeConfig.fSoutConferencingNoiseReduction == FALSE )
			return cOCT6100_ERR_CONF_BRIDGE_CNR_MUST_BE_ENABLED;

		/* Check if this is a tap channel.  If it is, it will never be the dominant speaker! */
		if ( pEchoChanEntry->fTap == TRUE )
			return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_ALWAYS_MUTE;

		/* Set the bridge index. */
		*f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex;
	}
	else
	{
		/* Set this such that there is no dominant speaker on this conference bridge. */
		*f_pusChannelIndex = cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED;

		/* Check the conference bridge handle. */
		if ( (f_pConfBridgeDominantSpeaker->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

		/* Set the bridge index. */
		*f_pusBridgeIndex = (UINT16)( f_pConfBridgeDominantSpeaker->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK );

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = (f_pConfBridgeDominantSpeaker->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;
		fCheckEntryOpenCnt = TRUE;
	}

	/*=====================================================================*/

	/*=====================================================================*/

	if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( fCheckEntryOpenCnt == TRUE )
	{
		if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;
	}

	/*=====================================================================*/
	/* Check if dominant speaker is supported in this firmware version. */
	
	if ( f_pApiInstance->pSharedInfo->ImageInfo.fDominantSpeakerEnabled == FALSE )
		return cOCT6100_ERR_NOT_SUPPORTED_DOMINANT_SPEAKER;

	/*=====================================================================*/

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiUpdateBridgeDominantSpeakerResources

Description:    Modify the conference bridge such that the new dominant
				speaker is the one specified by the index.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
							
f_usChanIndex				Index of the channel to be set as the dominant speaker.	
f_usBridgeIndex				Index of the bridge where this channel is on.	

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiUpdateBridgeDominantSpeakerResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usChanIndex,
				IN		UINT16							f_usBridgeIndex )
{
	tPOCT6100_API_CHANNEL			pEchoChanEntry;
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;
	tPOCT6100_SHARED_INFO			pSharedInfo;

	UINT16	usChannelIndex;
	UINT32	ulResult;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	/* Get the bridge entry for this channel. */
	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex )

	/* Set the dominant speaker index for all channels in this conference. */

	/* Search through the list of API channel entry for the ones on to this bridge.*/
	for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
	{
		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usChannelIndex );
		
		if ( pEchoChanEntry->fReserved == TRUE )
		{
			if ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
			{
				/* If we are unsetting the dominant speaker, of if it is not our channel index. */
				if ( ( f_usChanIndex == cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED )
					|| ( f_usChanIndex != usChannelIndex ) )
				{
					ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, usChannelIndex, f_usChanIndex );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
			}
		}
	}

	/* Make sure this channel is disabled. */
	if ( f_usChanIndex != cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED )
	{
		ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;
	}

	/* Save this in the conference bridge structure. */
	/* This will be needed later when removing the channel. */
	pBridgeEntry->fDominantSpeakerSet = TRUE;
	pBridgeEntry->usDominantSpeakerChanIndex = f_usChanIndex;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeMaskChangeSer

Description:    This function changes the mask of flexible bridge
				participant.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to 
						keep the present state of the chip and all its 
						resources.

f_pConfBridgeMaskChange	Pointer to conference bridge participant mask
						change structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeMaskChangeSer(
				IN OUT	tPOCT6100_INSTANCE_API						f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_MASK_CHANGE			f_pConfBridgeMaskChange )
{
	UINT16	usChanIndex;
	UINT16	usBridgeIndex;
	UINT32	ulResult;
	UINT32	ulNewParticipantMask;

	/* Check the validity of the channel handle given. */
	ulResult = Oct6100ApiCheckBridgeMaskChangeParams( f_pApiInstance, f_pConfBridgeMaskChange, &usChanIndex, &usBridgeIndex, &ulNewParticipantMask );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Update all resources needed by the new mask. */
	ulResult = Oct6100ApiUpdateMaskModifyResources( f_pApiInstance, usBridgeIndex, usChanIndex, ulNewParticipantMask );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Commit the changes to the chip's internal memories. */
	ulResult = Oct6100ApiBridgeUpdateMask( f_pApiInstance, usBridgeIndex, usChanIndex, ulNewParticipantMask );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiCheckBridgeMaskChangeParams

Description:	Check the validity of the channel given for setting the
				mask.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_pConfBridgeMaskChange		Pointer to conference bridge channel mask change structure.  
f_pusChannelIndex			Pointer to a channel index.
f_pusBridgeIndex			Pointer to a bridge index.
f_pulNewParticipantMask		New mask to apply for this participant.
\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiCheckBridgeMaskChangeParams(
				IN OUT	tPOCT6100_INSTANCE_API					f_pApiInstance,
				IN		tPOCT6100_CONF_BRIDGE_MASK_CHANGE		f_pConfBridgeMaskChange,
				OUT		PUINT16									f_pusChannelIndex,
				OUT		PUINT16									f_pusBridgeIndex,
				OUT		PUINT32									f_pulNewParticipantMask )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_CHANNEL		pEchoChanEntry;
	UINT32	ulEntryOpenCnt;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;
	
	if ( f_pConfBridgeMaskChange->ulChannelHndl == cOCT6100_INVALID_HANDLE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/*=====================================================================*/
	/* Check the channel handle.*/

	if ( (f_pConfBridgeMaskChange->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	*f_pusChannelIndex = (UINT16)( f_pConfBridgeMaskChange->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeMaskChange->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pEchoChanEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/* Check if the channel is bound to a conference bridge. */
	if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX )
		return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE;

	/* Set the bridge index. */
	*f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex;

	/*=====================================================================*/

	/*=====================================================================*/

	if ( ( *f_pusBridgeIndex == cOCT6100_INVALID_INDEX )
		|| ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex )

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;

	/* Check if this is bridge is a flexible conference bridge. */
	if ( pBridgeEntry->fFlexibleConferencing == FALSE )
		return cOCT6100_ERR_CONF_BRIDGE_SIMPLE_BRIDGE;
	
	/*=====================================================================*/

	/* Return new mask to apply. */
	*f_pulNewParticipantMask = f_pConfBridgeMaskChange->ulNewListenerMask;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiUpdateMaskModifyResources

Description:    Modify/reserve all resources needed for the modification of
				the participant's mask.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_usBridgeIndex				Bridge index of the bridge where this channel is residing.
f_usChanIndex				Channel index of the channel to be modified.
f_ulNewListenerMask			New mask to apply to the selected participant.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiUpdateMaskModifyResources(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex,
				IN		UINT16							f_usChanIndex,
				IN		UINT32							f_ulNewListenerMask )
{
	tPOCT6100_API_CHANNEL				pChanEntry;
	tPOCT6100_API_CHANNEL				pTempEchoChanEntry;
	tPOCT6100_SHARED_INFO				pSharedInfo;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;

	UINT32	ulResult = cOCT6100_ERR_OK;
	UINT32	ulTempVar;
	UINT32	ulOldListenerMask;
	UINT16	usChannelIndex;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	/* Get a pointer to the channel's list entry. */
	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex )

	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pChanEntry->usFlexConfParticipantIndex );

	/* Must travel all clients of this conference and reserve a load or accumulate event for */
	/* all participants which could not hear us but now can. While at it, check for events that */
	/* could be released, for example a participant that we cannot hear anymore. */

	ulOldListenerMask = pParticipant->ulListenerMask;

	/* Search through the list of API channel entry for the ones on to this bridge.*/
	for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ )
	{
		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
		
		/* Channel reserved? */
		if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
		{
			/* On current bridge? */
			if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
			{
				mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

				/* Check if we can now hear this participant, but could not before. */
				if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
					&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) )
				{
					/* Must reserve a load or accumulate entry mixer event here! */
					ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] );
					if ( ulResult != cOCT6100_ERR_OK )
					{
						/* Most probably, the hardware is out of mixer events. */
						break;
					}
				}

				/* Check if we can now NOT hear this participant, but could before. */
				if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 )
					&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) )
				{
					/* Must release the load or accumulate entry mixer event. */
					ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] );
					if ( ulResult != cOCT6100_ERR_OK )
					{
						break;
					}
				}
			}
		}
	}

	/* If an error is returned, make sure everything is cleaned up properly. */
	if ( ulResult != cOCT6100_ERR_OK )
	{
		/* Search through the list of API channel entry for the ones on to this bridge.*/
		for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
		{
			mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
			
			/* Channel reserved? */
			if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
			{
				/* On current bridge? */
				if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
				{
					mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

					/* Check if we can now hear this participant, but could not before. */
					if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
						&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) )
					{
						/* If the load or event entry in the mixer memory was reserved. */
						if ( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX )
						{
							/* Must release the load or accumulate entry mixer event. */
							ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] );
							if ( ulTempVar != cOCT6100_ERR_OK )
								return ulTempVar;

							pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
						}
					}

					/* Check if we can now NOT hear this participant, but could before. */
					if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 )
						&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) )
					{
						/* If the load or event entry in the mixer memory was reserved. */
						if ( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] == cOCT6100_INVALID_INDEX )
						{
							/* Must release the load or accumulate entry mixer event. */
							ulTempVar = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ) );
							if ( ulTempVar != cOCT6100_ERR_OK )
								return ulTempVar;
						}
					}
				}
			}
		}

		return ulResult;
	}

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeUpdateMask

Description:    Update the participant's mask.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.
f_usBridgeIndex				Bridge index of the bridge where this channel is residing.
f_usChanIndex				Channel index of the channel to be modified.
f_ulNewListenerMask			New mask to apply to the selected participant.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiBridgeUpdateMask( 
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance, 
				IN		UINT16								f_usBridgeIndex, 
				IN		UINT16								f_usChanIndex, 
				IN		UINT32								f_ulNewListenerMask )
{
	tPOCT6100_API_CHANNEL				pChanEntry;
	tPOCT6100_API_CHANNEL				pTempEchoChanEntry;
	tPOCT6100_SHARED_INFO				pSharedInfo;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant;
	tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant;
	tOCT6100_WRITE_PARAMS				WriteParams;

	UINT32	ulResult;
	UINT32	ulOldListenerMask;
	UINT16	usChannelIndex;

	UINT16	ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ];
	UINT32	ulMutePortChannelIndex;

	for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
		ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX;

	/* Obtain local pointer to shared portion of instance. */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	/* Get a pointer to the channel's list entry. */
	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex )

	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pChanEntry->usFlexConfParticipantIndex );

	ulOldListenerMask = pParticipant->ulListenerMask;

	/* Search through the list of API channel entry for the ones onto this bridge. */
	for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ )
	{
		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex );
		
		/* Channel reserved? */
		if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) )
		{
			/* On current bridge? */
			if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex )
			{
				mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );

				/* Check if we can now hear this participant, but could not before. */
				if ( ( pTempEchoChanEntry->fMute == FALSE ) 
					&& ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
					&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) )
				{
					/* First create/update the current channel's mixer. */
					ulResult = Oct6100ApiBridgeAddParticipantToChannel(
												f_pApiInstance,
												f_usBridgeIndex,
												usChannelIndex,
												f_usChanIndex,
												pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ],
												pChanEntry->usSubStoreEventIndex,
												pChanEntry->usSinCopyEventIndex,
												pTempParticipant->ulInputPort,
												pParticipant->ulInputPort );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;

					if ( pParticipant->fFlexibleMixerCreated == TRUE )
					{
						/* Check if the Rin silence event can be cleared now that the */
						/* channel has been added to a conference. */
						if ( pChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX )
						{
							/* Remove the event from the list.*/
							ulResult = Oct6100ApiMixerEventRemove(	f_pApiInstance,
																	pChanEntry->usRinSilenceEventIndex,
																	cOCT6100_EVENT_TYPE_SOUT_COPY );
							if ( ulResult != cOCT6100_ERR_OK )
								return ulResult;

							ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usRinSilenceEventIndex );
							if ( ulResult != cOCT6100_ERR_OK  )
								return cOCT6100_ERR_FATAL_DF;

							pChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX;
						}
					}
				}

				/* Check if we can now NOT hear this participant, but could before. */
				if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 )
					&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 )
					&& ( pParticipant->fFlexibleMixerCreated == TRUE ) 
					&& ( pTempEchoChanEntry->fMute == FALSE ) )
				{
					/* First update the current channel's mixer. */
					ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel(
												f_pApiInstance,
												f_usBridgeIndex,
												usChannelIndex,
												f_usChanIndex,
												TRUE );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
					
					if ( pParticipant->fFlexibleMixerCreated == FALSE )
					{
						/* Remember to mute the port on this channel. */
						for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
						{
							if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == f_usChanIndex )
							{
								break;
							}
							else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX )
							{
								ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = f_usChanIndex;
								break;
							}
						}
					}
				}

				/* Clear the load or accumulate event index for this participant. */
				if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 )
					&& ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) )
				{
					pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX;
				}
			}
		}

		/* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */
		for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ )
		{
			if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX )
			{
				mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] );

				mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex );
				
				if ( pTempParticipant->fFlexibleMixerCreated == FALSE )
				{
					/* Check if the Rin port must be muted on this channel. */
					ulResult = Oct6100ApiMutePorts( 
											f_pApiInstance, 
											ausMutePortChannelIndexes[ ulMutePortChannelIndex ], 
											pTempEchoChanEntry->usRinTsstIndex, 
											pTempEchoChanEntry->usSinTsstIndex,
											FALSE );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
			}
			else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */
			{
				/* No more channels to check for muting. */
				break;
			}
		}
	}
	
	/* Configure the SIN copy mixer entry and memory - if using the SOUT port. */
	if ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_SOUT )
	{
		if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
		{
			ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
															  pChanEntry->usSinTsstIndex,
															  pChanEntry->usExtraSinTsiMemIndex,
															  pChanEntry->TdmConfig.bySinPcmLaw );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}

		/* If the silence TSI is loaded on this port, update with the extra sin TSI. */
		if ( pChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX )
		{
			WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

			WriteParams.ulWriteAddress += 2;
			WriteParams.usWriteData = pChanEntry->usExtraSinTsiMemIndex;

			mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK  )
				return ulResult;
		}
	}

	/* Configure the RIN copy mixer entry and memory - if using the RIN port. */
	if ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_RIN )
	{
		if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX )
		{
			ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
															  pChanEntry->usRinTsstIndex,
															  pChanEntry->usExtraRinTsiMemIndex,
															  pChanEntry->TdmConfig.byRinPcmLaw );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
		}
	}

	/* Save the new mask permanently in the API instance. */
	pParticipant->ulListenerMask = f_ulNewListenerMask;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ConfBridgeGetStatsSer

Description:    This function returns the statistics from the specified bridge.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pConfBridgeStats		Pointer to conference bridge stats structure.  

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ConfBridgeGetStatsSer(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN OUT	tPOCT6100_CONF_BRIDGE_STATS		f_pConfBridgeStats )
{
	tPOCT6100_API_CONF_BRIDGE		pBridgeEntry;
	UINT16	usConfBridgeIndex;
	UINT32	ulEntryOpenCnt;

	/* Check for errors. */
	if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 )
		return cOCT6100_ERR_CONF_BRIDGE_DISABLED;

	/*=====================================================================*/
	/* Check the conference bridge handle. */

	/* Check the provided handle. */
	if ( (f_pConfBridgeStats->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	usConfBridgeIndex = (UINT16)( f_pConfBridgeStats->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK );
	if ( usConfBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, usConfBridgeIndex )

	/* Extract the entry open count from the provided handle. */
	ulEntryOpenCnt = (f_pConfBridgeStats->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

	/* Check for errors. */
	if ( pBridgeEntry->fReserved != TRUE )
		return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN;
	if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt )
		return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE;

	/*=====================================================================*/

	/* Return the stats.*/
	f_pConfBridgeStats->ulNumChannels = pBridgeEntry->usNumClients;
	f_pConfBridgeStats->ulNumTappedChannels = pBridgeEntry->usNumTappedClients;
	f_pConfBridgeStats->fFlexibleConferencing = pBridgeEntry->fFlexibleConferencing;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReserveBridgeEntry

Description:    Reserves a free entry in the Bridge list.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.
f_pusBridgeIndex		List entry reserved.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReserveBridgeEntry(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				OUT		PUINT16							f_pusBridgeIndex )
{
	PVOID	pBridgeAlloc;
	UINT32	ulResult;
	UINT32	ulBridgeIndex;

	mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBridgeAlloc )

	ulResult = OctapiLlmAllocAlloc( pBridgeAlloc, &ulBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK  )
	{
		if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT )
			return cOCT6100_ERR_CONF_BRIDGE_ALL_BUFFERS_OPEN;
		else
			return cOCT6100_ERR_FATAL_29;
	}

	*f_pusBridgeIndex = (UINT16)( ulBridgeIndex & 0xFFFF );

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReleaseBridgeEntry

Description:    Release an entry from the bridge list.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance		Pointer to API instance. This memory is used to keep the
					present state of the chip and all its resources.

f_usBridgeIndex		List entry reserved.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReleaseBridgeEntry(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex )
{
	PVOID	pBridgeAlloc;
	UINT32	ulResult;

	mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBridgeAlloc )

	ulResult = OctapiLlmAllocDealloc( pBridgeAlloc, f_usBridgeIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return cOCT6100_ERR_FATAL_2A;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiGetPrevLastSubStoreEvent

Description:    This function will search for the first valid LastSubStoreEvent 
				in a bridge located before the current bridge in the bridge 
				link list.
				
				If the function does not find an event before reaching the end
				of the mixers list, then the event head node will be used as the
				last Store or SubStore event.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_pusBridgeEntry			Bridge entry.
f_usBridgeFirstLoadEventPtr	Load index to check against.
First						valid sub store index.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiGetPrevLastSubStoreEvent(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usBridgeIndex,
				IN		UINT16							f_usBridgeFirstLoadEventPtr,
				OUT		PUINT16							f_pusLastSubStoreEventIndex )
{
	tPOCT6100_API_CONF_BRIDGE	pBridgeEntry;
	tPOCT6100_API_MIXER_EVENT	pTempMixerEntry;
	UINT16						usNextEventPtr;
	UINT16						usHeadEventPtr;
	UINT16						usLastSubStoreEventPtr;
	UINT32						ulLoopCount = 0;
	UINT16						usCurrentPtr;
	UINT32						ulResult = cOCT6100_ERR_OK;

	/* Get current entry to obtain the link to the previous entry.*/
	mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex );

	/* Since we have flexible bridges, we have to */
	/* run down the list and check for the appropriate event. */

	/* Travel down the list for the last Store or Sub/Store event before the bridge. */

	if ( f_pApiInstance->pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX )
	{
		/* The only node in the list then is the head node.*/
		usHeadEventPtr = cOCT6100_MIXER_HEAD_NODE;
	}
	else
	{
		usHeadEventPtr = f_pApiInstance->pSharedInfo->MixerInfo.usLastSoutCopyEventPtr;
	}

	mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempMixerEntry, usHeadEventPtr );
	usLastSubStoreEventPtr = usHeadEventPtr;
	usNextEventPtr = pTempMixerEntry->usNextEventPtr;
	usCurrentPtr = usHeadEventPtr;
	while( usCurrentPtr != f_usBridgeFirstLoadEventPtr )
	{
		if ( ( pTempMixerEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE )
			|| ( pTempMixerEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_SUB_STORE ) )
		{
			usLastSubStoreEventPtr = usNextEventPtr;
		}

		/* Next pointer. */
		usCurrentPtr = usNextEventPtr;
		usNextEventPtr = pTempMixerEntry->usNextEventPtr;

		/* Check if next event pointer is valid. */
		if ( ( ( f_usBridgeFirstLoadEventPtr != usCurrentPtr ) 
			&& ( pTempMixerEntry->usNextEventPtr == cOCT6100_INVALID_INDEX ) )
				|| ( pTempMixerEntry->usNextEventPtr == cOCT6100_MIXER_HEAD_NODE ) )
			return cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND;

		if ( usNextEventPtr != cOCT6100_INVALID_INDEX )
			mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempMixerEntry, usNextEventPtr );
		
		ulLoopCount++;
		if ( ulLoopCount == cOCT6100_MAX_LOOP )
			return cOCT6100_ERR_FATAL_CA;
	}
	
	/* Return the result to the user. */
	*f_pusLastSubStoreEventIndex = usLastSubStoreEventPtr;

	return ulResult;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiGetPreviousEvent

Description:    This is a recursive function, it requires an entry event index and 
				will run down the list until it finds the node just before the one
				required.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_usEntryIndex			Event entry index.
f_pusBridgeEntry		Bridge entry.
f_pusPreviousIndex		Previous index.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiGetPreviousEvent(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usEntryIndex,
				IN		UINT16							f_usSearchedIndex,
				IN		UINT16							f_usLoopCnt,
				OUT		PUINT16							f_pusPreviousIndex )
{
	tPOCT6100_API_MIXER_EVENT	pCurrentEntry;
	UINT32	ulResult;

	/* Get current entry to obtain the link to the previous entry. */
	mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pCurrentEntry, f_usEntryIndex );

	/* Avoid stack overflows. */
	if ( f_usLoopCnt == cOCT6100_MAX_MIXER_EVENTS )
		return cOCT6100_ERR_FATAL_E3;

	if ( pCurrentEntry->usNextEventPtr == cOCT6100_INVALID_INDEX )
	{
		/* Event not found. */
		ulResult = cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND;
	}
	else if ( pCurrentEntry->usNextEventPtr == f_usSearchedIndex )
	{
		/* We found our node. */
		*f_pusPreviousIndex = f_usEntryIndex;
		ulResult = cOCT6100_ERR_OK; 
	}
	else
	{
		/* Keep searching.*/
		f_usLoopCnt++;
		ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pCurrentEntry->usNextEventPtr, f_usSearchedIndex, f_usLoopCnt, f_pusPreviousIndex );
	}

	return ulResult;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiBridgeSetDominantSpeaker

Description:    This function will set the index of the dominant speaker
				for the channel index specified.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance					Pointer to API instance. This memory is used to 
								keep the present state of the chip and all its 
								resources.

f_usChannelIndex				Index of the channel where the API must set the
								current dominant speaker for the conference.
f_usDominantSpeakerIndex		Index of the channel which is the dominant
								speaker in the conference.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiBridgeSetDominantSpeaker(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usChannelIndex,
				IN		UINT16							f_usDominantSpeakerIndex )
{
	UINT32	ulBaseAddress;
	UINT32	ulFeatureBytesOffset;
	UINT32	ulFeatureBitOffset;
	UINT32	ulFeatureFieldLength;
	UINT32	ulResult;
	UINT32	ulTempData;
	UINT32	ulMask;

	tPOCT6100_API_CHANNEL	pEchoChanEntry;

	mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, f_usChannelIndex );

	ulBaseAddress		 = cOCT6100_CHANNEL_ROOT_BASE + ( f_usChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanRootConfOfst;
	ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.usDwordOffset * 4;
	ulFeatureBitOffset	 = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.byBitOffset;
	ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.byFieldSize;

	/* Retrieve the current configuration. */
	mOCT6100_RETRIEVE_NLP_CONF_DWORD(	f_pApiInstance,
										pEchoChanEntry,
										ulBaseAddress + ulFeatureBytesOffset,
										&ulTempData,
										ulResult );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	/* Clear previous value set in the feature field.*/
	mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask );

	ulTempData &= (~ulMask);
	ulTempData |= ( ( f_usDominantSpeakerIndex ) << ulFeatureBitOffset );

	/* Save the new dominant speaker. */
	mOCT6100_SAVE_NLP_CONF_DWORD(	f_pApiInstance,
									pEchoChanEntry,
									ulBaseAddress + ulFeatureBytesOffset,
									ulTempData,
									ulResult );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;	

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReserveFlexConfParticipantEntry

Description:    Reserves a free entry in the participant list.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.
f_pusParticipantIndex	List entry reserved.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReserveFlexConfParticipantEntry(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				OUT		PUINT16							f_pusParticipantIndex )
{
	PVOID	pParticipantAlloc;
	UINT32	ulResult;
	UINT32	ulParticipantIndex;

	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pParticipantAlloc )

	ulResult = OctapiLlmAllocAlloc( pParticipantAlloc, &ulParticipantIndex );
	if ( ulResult != cOCT6100_ERR_OK )
	{
		if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT )
			return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_ALL_BUFFERS_OPEN;
		else
			return cOCT6100_ERR_FATAL_29;
	}

	*f_pusParticipantIndex = (UINT16)( ulParticipantIndex & 0xFFFF );

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100ApiReleaseFlexConfParticipantEntry

Description:    Release an entry from the flexible conferencing participant 
				list.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_usParticipantIndex	List entry reserved.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100ApiReleaseFlexConfParticipantEntry(
				IN OUT	tPOCT6100_INSTANCE_API			f_pApiInstance,
				IN		UINT16							f_usParticipantIndex )
{
	PVOID	pParticipantAlloc;
	UINT32	ulResult;

	mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pParticipantAlloc )

	ulResult = OctapiLlmAllocDealloc( pParticipantAlloc, f_usParticipantIndex );
	if ( ulResult != cOCT6100_ERR_OK )
		return cOCT6100_ERR_FATAL_2A;

	return cOCT6100_ERR_OK;
}
