Logo Search packages:      
Sourcecode: zaptel version File versions  Download package

oct6100_playout_buf.c

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

File: oct6100_playout_buf.c

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

      This file contains functions used to manage buffer playout.

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.00-PR43 $

$Octasic_Revision: 109 $

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


/*****************************  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_playout_buf_inst.h"

#include "oct6100api/oct6100_interrupts_pub.h"
#include "oct6100api/oct6100_chip_open_pub.h"
#include "oct6100api/oct6100_channel_pub.h"
#include "oct6100api/oct6100_events_pub.h"
#include "oct6100api/oct6100_playout_buf_pub.h"

#include "oct6100_chip_open_priv.h"
#include "oct6100_miscellaneous_priv.h"
#include "oct6100_memory_priv.h"
#include "oct6100_channel_priv.h"
#include "oct6100_events_priv.h"
#include "oct6100_playout_buf_priv.h"

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

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

Function:         Oct6100BufferPlayoutLoad

Description:    This function loads a playout buffer into external memory.

-------------------------------------------------------------------------------
|     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_pBufferLoad                 Pointer to buffer playout load structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutLoadDef
UINT32 Oct6100BufferPlayoutLoadDef(
                        tPOCT6100_BUFFER_LOAD               f_pBufferLoad )
{
      f_pBufferLoad->pbyBufferPattern = NULL;
      f_pBufferLoad->ulBufferSize = 128;
      f_pBufferLoad->ulBufferPcmLaw = cOCT6100_PCM_U_LAW;
      
      f_pBufferLoad->pulBufferIndex = NULL;
      f_pBufferLoad->pulPlayoutFreeMemSize = NULL;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutLoad
UINT32 Oct6100BufferPlayoutLoad(
                        tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        tPOCT6100_BUFFER_LOAD                     f_pBufferLoad )
{
      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 = Oct6100BufferLoadSer( f_pApiInstance, f_pBufferLoad, TRUE, cOCT6100_INVALID_INDEX );
      }
      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;
}
#endif

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

Function:         Oct6100BufferPlayoutLoadBlockInit

Description:    This function allows the user to initialize loading a buffer 
                        into external memory using blocks.

-------------------------------------------------------------------------------
|     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_pBufferLoadBlockInit  Pointer to buffer playout load block init structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutLoadBlockInitDef
UINT32 Oct6100BufferPlayoutLoadBlockInitDef(
                        tPOCT6100_BUFFER_LOAD_BLOCK_INIT    f_pBufferLoadBlockInit )
{
      f_pBufferLoadBlockInit->ulBufferSize = 128;
      f_pBufferLoadBlockInit->ulBufferPcmLaw = cOCT6100_PCM_U_LAW;
      
      f_pBufferLoadBlockInit->pulBufferIndex = NULL;
      f_pBufferLoadBlockInit->pulPlayoutFreeMemSize = NULL;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutLoadBlockInit
UINT32 Oct6100BufferPlayoutLoadBlockInit(
                        tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        tPOCT6100_BUFFER_LOAD_BLOCK_INIT    f_pBufferLoadBlockInit )
{
      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 = Oct6100BufferLoadBlockInitSer( f_pApiInstance, f_pBufferLoadBlockInit );
      }
      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;
}
#endif


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

Function:         Oct6100BufferPlayoutLoadBlock

Description:      This function allows the user to load a buffer block into 
                        external memory.

-------------------------------------------------------------------------------
|     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_pBufferLoadBlock            Pointer to buffer playout load block structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutLoadBlockDef
UINT32 Oct6100BufferPlayoutLoadBlockDef(
                        tPOCT6100_BUFFER_LOAD_BLOCK         f_pBufferLoadBlock )
{
      f_pBufferLoadBlock->ulBufferIndex = cOCT6100_INVALID_VALUE;
      f_pBufferLoadBlock->ulBlockLength = cOCT6100_INVALID_VALUE;
      f_pBufferLoadBlock->ulBlockOffset = cOCT6100_INVALID_VALUE;
      
      f_pBufferLoadBlock->pbyBufferPattern = NULL;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutLoadBlock
UINT32 Oct6100BufferPlayoutLoadBlock(
                        tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        tPOCT6100_BUFFER_LOAD_BLOCK               f_pBufferLoadBlock )
{
      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 = Oct6100BufferLoadBlockSer( f_pApiInstance, f_pBufferLoadBlock );
      }
      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;
}
#endif


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

Function:         Oct6100BufferPlayoutUnload

Description:    This function unloads a playout buffer from external memory.

-------------------------------------------------------------------------------
|     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_pBufferUnload               Pointer to buffer playout unload structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutUnloadDef
UINT32 Oct6100BufferPlayoutUnloadDef(
                        tPOCT6100_BUFFER_UNLOAD             f_pBufferUnload )
{
      f_pBufferUnload->ulBufferIndex = cOCT6100_INVALID_VALUE;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutUnload
UINT32 Oct6100BufferPlayoutUnload(
                        tPOCT6100_INSTANCE_API              f_pApiInstance,
                        tPOCT6100_BUFFER_UNLOAD             f_pBufferUnload )
{
      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 = Oct6100BufferUnloadSer( f_pApiInstance, f_pBufferUnload, TRUE );
      }
      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;
}
#endif


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

Function:         Oct6100BufferPlayoutAdd

Description:    This function adds a buffer to a port's playout list on the 
                        selected 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_pBufferPlayoutAdd           Pointer to buffer playout add structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutAddDef
UINT32 Oct6100BufferPlayoutAddDef(
                        tPOCT6100_BUFFER_PLAYOUT_ADD              f_pBufferPlayoutAdd )
{
      f_pBufferPlayoutAdd->ulChannelHndl = cOCT6100_INVALID_HANDLE;
      f_pBufferPlayoutAdd->ulBufferIndex = cOCT6100_INVALID_VALUE;

      f_pBufferPlayoutAdd->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT;
      f_pBufferPlayoutAdd->ulMixingMode = cOCT6100_MIXING_MINUS_6_DB;
      f_pBufferPlayoutAdd->lGainDb = 0;

      f_pBufferPlayoutAdd->fRepeat = FALSE;
      f_pBufferPlayoutAdd->ulRepeatCount = cOCT6100_REPEAT_INFINITELY;

      f_pBufferPlayoutAdd->ulDuration = cOCT6100_INVALID_VALUE;
      
      f_pBufferPlayoutAdd->ulBufferLength = cOCT6100_AUTO_SELECT;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutAdd
UINT32 Oct6100BufferPlayoutAdd(
                        tPOCT6100_INSTANCE_API                          f_pApiInstance,
                        tPOCT6100_BUFFER_PLAYOUT_ADD              f_pBufferPlayoutAdd )
{
      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 = Oct6100BufferPlayoutAddSer( f_pApiInstance, f_pBufferPlayoutAdd );
      }
      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;
}
#endif


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

Function:         Oct6100BufferPlayoutStart

Description:    This function enables playout of the specified buffer on the 
                        requested 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_pBufferPlayoutStart   Pointer to buffer playout start structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutStartDef
UINT32 Oct6100BufferPlayoutStartDef(
                        tPOCT6100_BUFFER_PLAYOUT_START      f_pBufferPlayoutStart )
{
      f_pBufferPlayoutStart->ulChannelHndl = cOCT6100_INVALID_HANDLE;
      f_pBufferPlayoutStart->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT;
      f_pBufferPlayoutStart->fNotifyOnPlayoutStop = FALSE;
      f_pBufferPlayoutStart->ulUserEventId = cOCT6100_INVALID_VALUE;
      f_pBufferPlayoutStart->fAllowStartWhileActive = FALSE;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutStart
UINT32 Oct6100BufferPlayoutStart(
                        tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        tPOCT6100_BUFFER_PLAYOUT_START            f_pBufferPlayoutStart )
{
      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 = Oct6100BufferPlayoutStartSer( f_pApiInstance, f_pBufferPlayoutStart, cOCT6100_BUFFER_PLAYOUT_EVENT_STOP );
      }
      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;
}
#endif


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

Function:         Oct6100BufferPlayoutStop

Description:    This function disables playout of a buffer on 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_pBufferPlayoutStop    Pointer to buffer playout stop structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutStopDef
UINT32 Oct6100BufferPlayoutStopDef(
                        tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop )
{
      f_pBufferPlayoutStop->ulChannelHndl = cOCT6100_INVALID_HANDLE;
      f_pBufferPlayoutStop->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT;
      f_pBufferPlayoutStop->fStopCleanly = TRUE;
      f_pBufferPlayoutStop->pfAlreadyStopped = NULL;
      f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = NULL;

      return cOCT6100_ERR_OK;
}
#endif

#if !SKIP_Oct6100BufferPlayoutStop
UINT32 Oct6100BufferPlayoutStop(
                        tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop )
{
      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 = Oct6100BufferPlayoutStopSer( f_pApiInstance, f_pBufferPlayoutStop );
      }
      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;
}
#endif


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

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

Function:         Oct6100ApiGetPlayoutBufferSwSizes

Description:    Gets the sizes of all portions of the API instance pertinent
                        to the management of playout buffers.

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

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiGetPlayoutBufferSwSizes
UINT32 Oct6100ApiGetPlayoutBufferSwSizes(
                        IN          tPOCT6100_CHIP_OPEN                       f_pOpenChip,
                        OUT         tPOCT6100_API_INSTANCE_SIZES  f_pInstSizes )
{
      UINT32      ulTempVar;
      UINT32      ulResult;

      /* Calculate memory needed for playout buffer list. */
      f_pInstSizes->ulPlayoutBufList = f_pOpenChip->ulMaxPlayoutBuffers * sizeof( tOCT6100_API_BUFFER );

      f_pInstSizes->ulPlayoutBufMemoryNodeList = 0;
      
      /* Calculate memory needed for playout buffer allocation software. */
      if ( f_pOpenChip->ulMaxPlayoutBuffers > 0 )
      {
            ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxPlayoutBuffers, &f_pInstSizes->ulPlayoutBufAlloc );
            if ( ulResult != cOCT6100_ERR_OK )
                  return cOCT6100_ERR_FATAL_3C;
            
            f_pInstSizes->ulPlayoutBufMemoryNodeList = 2 * f_pOpenChip->ulMaxPlayoutBuffers * sizeof( tOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE );
      }
      else
      {
            f_pInstSizes->ulPlayoutBufAlloc  = 0;
      }

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

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiPlayoutBufferSwInit

Description:    Initializes all elements of the instance structure associated
                        to playout buffers.

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

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiPlayoutBufferSwInit
UINT32 Oct6100ApiPlayoutBufferSwInit(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance )
{
      tPOCT6100_SHARED_INFO               pSharedInfo;
      tPOCT6100_API_BUFFER                pBufferList;
      PVOID pBufferPlayoutAlloc;
      UINT32      ulMaxBufferPlayout;
      UINT32      ulResult, i;

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

      /* Get the maximum number of buffer playout. */
      ulMaxBufferPlayout = pSharedInfo->ChipConfig.usMaxPlayoutBuffers;

      /* Set all entries in the buffer playout list to unused. */
      mOCT6100_GET_BUFFER_LIST_PNT( pSharedInfo, pBufferList )

      for ( i = 0; i < ulMaxBufferPlayout; i++ )
      {
            pBufferList[ i ].fReserved = FALSE;
            pBufferList[ i ].ulBufferSize = 0;
            pBufferList[ i ].ulBufferBase = cOCT6100_INVALID_VALUE;
            pBufferList[ i ].usDependencyCnt = 0;
            pBufferList[ i ].byBufferPcmLaw = cOCT6100_PCM_U_LAW;
            
      }

      /* Initialize the buffer playout allocation software to "all free". */
      if ( ulMaxBufferPlayout > 0 )
      {
            mOCT6100_GET_BUFFER_ALLOC_PNT( pSharedInfo, pBufferPlayoutAlloc )
            
            ulResult = OctapiLlmAllocInit( &pBufferPlayoutAlloc, ulMaxBufferPlayout );
            if ( ulResult != cOCT6100_ERR_OK )
                  return cOCT6100_ERR_FATAL_3D;
      }

      /* Initialize the amount of free memory used by playout. */
      f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed = 0;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferLoadSer

Description:    Loads a buffer in external memory.

-------------------------------------------------------------------------------
|     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_pBufferLoad                 Pointer to buffer configuration structure. The handle
                                    identifying the buffer in all future function calls is
                                    returned in this structure.
                                    
f_fReserveListStruct    Flag indicating if a list structure should be reserved
                                    or if the structure has been reserved before.  If this
                                    is set, the f_ulBufIndex variable must also be set.

f_ulBufIndex                  If the f_fReserveListStruct flag is set, this index
                                    will identify the buffer playout list structure
                                    that must be used to load the specified buffer.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferLoadSer
UINT32 Oct6100BufferLoadSer(
                        IN OUT      tPOCT6100_INSTANCE_API        f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_LOAD         f_pBufferLoad,
                        IN          BOOL                                f_fReserveListStruct, 
                        IN          UINT32                                    f_ulBufIndex )
{
      UINT32      ulBufferIndex;
      UINT32      ulBufferBase;
      UINT32      ulResult;

      /* Check the user's configuration of the buffer for errors. */
      ulResult = Oct6100ApiCheckBufferParams( f_pApiInstance, f_pBufferLoad, TRUE );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Reserve all resources needed by the buffer. */
      ulResult = Oct6100ApiReserveBufferResources( f_pApiInstance, f_pBufferLoad, f_fReserveListStruct, f_ulBufIndex, &ulBufferIndex, &ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      /* Write the buffer in external memory. */
      ulResult = Oct6100ApiWriteBufferInMemory( f_pApiInstance, ulBufferBase, f_pBufferLoad->ulBufferSize, f_pBufferLoad->pbyBufferPattern );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Update the new buffer's entry in the buffer list. */
      ulResult = Oct6100ApiUpdateBufferEntry( f_pApiInstance, f_pBufferLoad, ulBufferIndex, ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferLoadBlockInitSer

Description:    Reserve resources for loading a buffer into external memory.

-------------------------------------------------------------------------------
|     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_pBufferLoadBlockInit  Pointer to buffer configuration structure. The 
                                    handle identifying the buffer in all future 
                                    function calls is returned in this structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferLoadBlockInitSer
UINT32 Oct6100BufferLoadBlockInitSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_LOAD_BLOCK_INIT    f_pBufferLoadBlockInit )
{
      UINT32                              ulBufferIndex;
      UINT32                              ulBufferBase;
      UINT32                              ulResult;
      tOCT6100_BUFFER_LOAD    BufferLoad;

      Oct6100BufferPlayoutLoadDef( &BufferLoad );

      /* Not to replicate the code, we use the BufferLoad functions directly. */
      BufferLoad.pulBufferIndex                 = f_pBufferLoadBlockInit->pulBufferIndex;
      BufferLoad.pulPlayoutFreeMemSize    = f_pBufferLoadBlockInit->pulPlayoutFreeMemSize;
      BufferLoad.ulBufferPcmLaw                 = f_pBufferLoadBlockInit->ulBufferPcmLaw;
      BufferLoad.ulBufferSize                   = f_pBufferLoadBlockInit->ulBufferSize;
      BufferLoad.pbyBufferPattern               = NULL;  /* Must not check this for now */

      /* Check the user's configuration of the buffer for errors, but do */
      /* not check if the buffer pointer is NULL.  It is NULL for sure! */
      ulResult = Oct6100ApiCheckBufferParams( f_pApiInstance, &BufferLoad, FALSE );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Reserve all resources needed by the buffer. */
      ulResult = Oct6100ApiReserveBufferResources( f_pApiInstance, &BufferLoad, TRUE, cOCT6100_INVALID_INDEX, &ulBufferIndex, &ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Update the new buffer's entry in the buffer list. */
      ulResult = Oct6100ApiUpdateBufferEntry( f_pApiInstance, &BufferLoad, ulBufferIndex, ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferLoadBlockSer

Description:    Loads a buffer in external memory using blocks.

-------------------------------------------------------------------------------
|     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_pBufferLoadBlock            Pointer to buffer block to be loaded into external 
                                    memory descriptor. 

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferLoadBlockSer
UINT32 Oct6100BufferLoadBlockSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_LOAD_BLOCK               f_pBufferLoadBlock )
{
      UINT32      ulBufferBase;
      UINT32      ulResult;

      /* Check the user's configuration for errors. */
      ulResult = Oct6100ApiCheckBufferLoadBlockParams( f_pApiInstance, f_pBufferLoadBlock, &ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Write the buffer in external memory at the appropriate offset - must do some pointer arithmetic. */
      ulResult = Oct6100ApiWriteBufferInMemory( f_pApiInstance, ulBufferBase + f_pBufferLoadBlock->ulBlockOffset, 
                              f_pBufferLoadBlock->ulBlockLength, f_pBufferLoadBlock->pbyBufferPattern + f_pBufferLoadBlock->ulBlockOffset );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiCheckBufferParams

Description:    Checks the user's buffer playout load 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_pBufferLoad                 Pointer to buffer configuration structure.
f_fCheckBufferPtr       Check if the buffer pointer is NULL or not.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiCheckBufferParams
UINT32 Oct6100ApiCheckBufferParams(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_LOAD               f_pBufferLoad,
                        IN          BOOL                                      f_fCheckBufferPtr )
{
      /* Check for errors. */
      if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED;

      if ( f_pApiInstance->pSharedInfo->ImageInfo.fBufferPlayout == FALSE )
            return cOCT6100_ERR_NOT_SUPPORTED_BUFFER_PLAYOUT;

      if ( f_pBufferLoad->pulBufferIndex == NULL )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX;

      if( f_fCheckBufferPtr )
      {
            if ( f_pBufferLoad->pbyBufferPattern == NULL )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_PATTERN;
      }

      if ( f_pBufferLoad->ulBufferSize < cOCT6100_MINIMUM_BUFFER_SIZE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_TOO_SMALL;

      if ( ( f_pBufferLoad->ulBufferSize % cOCT6100_BUFFER_SIZE_GRANULARITY ) != 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE;

      if ( f_pBufferLoad->ulBufferPcmLaw != cOCT6100_PCM_U_LAW && 
             f_pBufferLoad->ulBufferPcmLaw != cOCT6100_PCM_A_LAW )
            return cOCT6100_ERR_BUFFER_PLAYOUT_PCM_LAW;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiCheckBufferLoadBlockParams

Description:    Checks the user's buffer playout load block 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_pBufferLoadBlock            Pointer to buffer block descriptor.
f_pulBufferBase               Pointer to the base address of the buffer in external 
                                    memory.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiCheckBufferLoadBlockParams
UINT32 Oct6100ApiCheckBufferLoadBlockParams(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN          tPOCT6100_BUFFER_LOAD_BLOCK         f_pBufferLoadBlock,
                        OUT         PUINT32                                         f_pulBufferBase )
{
      /* Check for errors. */
      tPOCT6100_API_BUFFER    pBufEntry;

      if ( f_pBufferLoadBlock->ulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX;

      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_pBufferLoadBlock->ulBufferIndex )

      if ( pBufEntry->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN;

      if ( ( f_pBufferLoadBlock->ulBlockLength % 2 ) != 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_LENGTH_INVALID;

      if ( ( f_pBufferLoadBlock->ulBlockOffset % 2 ) != 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_OFFSET_INVALID;

      if ( f_pBufferLoadBlock->pbyBufferPattern == NULL )
            return cOCT6100_ERR_BUFFER_PLAYOUT_PATTERN;

      /* Check boundaries */
      if ( ( f_pBufferLoadBlock->ulBlockLength + f_pBufferLoadBlock->ulBlockOffset ) > pBufEntry->ulBufferSize )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE;

      *f_pulBufferBase = pBufEntry->ulBufferBase;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiReserveBufferResources

Description:    Reserves all resources needed for the new buffer.

-------------------------------------------------------------------------------
|     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_pBufferLoad                 Pointer to buffer configuration structure.

f_fReserveListStruct    Flag indicating if a list structure should be reserved
                                    or if the structure has been reserved before.

f_ulBufIndex                  If the f_fReserveListStruct flag is set, this index
                                    will identifying the buffer playout list structure
                                    that must be used to load the specified buffer.

f_pulBufferIndex        Allocated entry in buffer playout list.
      
f_pulBufferBase               Allocated external memory block for the buffer.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiReserveBufferResources
UINT32 Oct6100ApiReserveBufferResources(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN          tPOCT6100_BUFFER_LOAD               f_pBufferLoad,
                        IN          BOOL                                      f_fReserveListStruct,
                        IN          UINT32                                          f_ulBufIndex,
                        OUT         PUINT32                                         f_pulBufferIndex,
                        OUT         PUINT32                                         f_pulBufferBase )
{
      tPOCT6100_SHARED_INFO   pSharedInfo;
      UINT32      ulResult = cOCT6100_ERR_OK;
      UINT32      ulTempVar;

      /* Obtain local pointer to shared portion of instance. */
      pSharedInfo = f_pApiInstance->pSharedInfo;
      
      /* Reserve an entry in the buffer list. */
      if ( f_fReserveListStruct == TRUE )
      {
            ulResult = Oct6100ApiReserveBufPlayoutListEntry( f_pApiInstance, f_pulBufferIndex );
      }
      else
      {
            *f_pulBufferIndex = f_ulBufIndex;
      }
      if ( ulResult == cOCT6100_ERR_OK )
      {
            /* Find a free block to store the buffer. */
            ulResult = Oct6100ApiReserveBufferPlayoutMemory( f_pApiInstance, f_pBufferLoad->ulBufferSize, f_pulBufferBase );
            if ( ulResult != cOCT6100_ERR_OK )
            {
                  /* Release the list entry. */
                  if ( f_fReserveListStruct == TRUE )
                  {
                        ulTempVar = Oct6100ApiReleaseBufPlayoutListEntry( f_pApiInstance, *f_pulBufferIndex );
                        if ( ulTempVar != cOCT6100_ERR_OK )
                              return ulTempVar;
                  }
            }
      }

      return ulResult;
}
#endif


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

Function:         Oct6100ApiWriteBufferInMemory

Description:    Writes the buffer in external memory.

-------------------------------------------------------------------------------
|     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_ulBufferBase                Allocated external memory address for the buffer.

f_ulBufferLength        Length in bytes of the buffer to be copied in memory.

f_pbyBuffer                   Address where the buffer should be copied from.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiWriteBufferInMemory
UINT32 Oct6100ApiWriteBufferInMemory( 
                        IN OUT      tPOCT6100_INSTANCE_API  f_pApiInstance,
                        IN          UINT32                              f_ulBufferBase,
                        IN          UINT32                              f_ulBufferLength,
                        IN          PUINT8                              f_pbyBuffer )
{
      tPOCT6100_SHARED_INFO         pSharedInfo;
      tOCT6100_WRITE_BURST_PARAMS   BurstParams;
      tOCT6100_WRITE_PARAMS         WriteParams;
      UINT32                                    ulResult;
      UINT32                                    ulNumWrites;
      PUINT16                                   pusSuperArray;
      PUINT8                                    pbyPlayoutBuffer;
      UINT32                                    ulByteCount = 0;
      UINT32                                    i;

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

      /* Set the process context and user chip ID parameters once and for all. */
      BurstParams.pProcessContext = f_pApiInstance->pProcessContext;

      BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

      WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

      WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

      /* Write the buffer in external memory. */
      ulNumWrites = f_ulBufferLength / 2;

      BurstParams.ulWriteAddress = f_ulBufferBase;
      BurstParams.pusWriteData = pSharedInfo->MiscVars.ausSuperArray;

      pusSuperArray = pSharedInfo->MiscVars.ausSuperArray;
      pbyPlayoutBuffer = f_pbyBuffer;
      
      /* Check if we can maximize the bandwidth through the CPU port. */
      if ( f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels == 0 )
      {
            WriteParams.ulWriteAddress = 0x234;
            WriteParams.usWriteData = 0x08ff;
            mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
            if ( ulResult != cOCT6100_ERR_OK  )
                  return ulResult;
      }

      while ( ulNumWrites != 0 )
      {
            if ( ulNumWrites >= pSharedInfo->ChipConfig.usMaxRwAccesses )
                  BurstParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses;
            else
                  BurstParams.ulWriteLength = ulNumWrites;

            for ( i = 0; i < BurstParams.ulWriteLength; i++ )
            {
                  pusSuperArray[ i ]  = ( UINT16 )(( pbyPlayoutBuffer [ ulByteCount++ ]) << 8);
                  pusSuperArray[ i ] |= ( UINT16 )pbyPlayoutBuffer [ ulByteCount++ ];
            }

            mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult )
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            BurstParams.ulWriteAddress += 2 * BurstParams.ulWriteLength;
            ulNumWrites -= BurstParams.ulWriteLength;

      }

      /* Make sure we revert back the changes made to the CPU bandwidth register. */
      if ( f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels == 0 )
      {
            WriteParams.ulWriteAddress = 0x234;
            WriteParams.usWriteData = 0x0804;
            mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;
      }

      return cOCT6100_ERR_OK;
}
#endif
      

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

Function:         Oct6100ApiUpdateBufferEntry

Description:    Updates the new buffer's entry in the buffer playout 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_pBufferLoad                 Pointer to buffer configuration structure.
f_ulBufferIndex               Allocated entry in buffer playout list.
f_ulBufferBase                Allocated external memory block for the buffer.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiUpdateBufferEntry
UINT32 Oct6100ApiUpdateBufferEntry(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_LOAD               f_pBufferLoad,
                        IN          UINT32                                          f_ulBufferIndex,
                        IN          UINT32                                          f_ulBufferBase )
{
      tPOCT6100_API_BUFFER    pBufEntry;
      UINT32                              ulBufferSize = f_pBufferLoad->ulBufferSize;

      /* Obtain a pointer to the new buffer's list entry. */
      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_ulBufferIndex )

      /* Copy the buffer's configuration and allocated resources. */
      pBufEntry->ulBufferSize = f_pBufferLoad->ulBufferSize;
      pBufEntry->byBufferPcmLaw = (UINT8)( f_pBufferLoad->ulBufferPcmLaw & 0xFF );
      pBufEntry->ulBufferBase = f_ulBufferBase;
      
      /* Update the entries flags. */
      pBufEntry->usDependencyCnt = 0;

      /* Mark the buffer as opened. */
      pBufEntry->fReserved = TRUE;

      /* Increment the number of buffer loaded into the chip.*/
      f_pApiInstance->pSharedInfo->ChipStats.usNumberPlayoutBuffers++;
      
      /* Refresh the amount of memory used by buffer playout. */

      /* Reserved size is divisible by 64. */
      if ( ulBufferSize % 64 )
            ulBufferSize = ulBufferSize + ( 64 - ( ulBufferSize % 64 ) );
      f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed += ulBufferSize;
      
      /* Return the buffer index to the user. */
      *f_pBufferLoad->pulBufferIndex = f_ulBufferIndex;

      /* Return the amount of free memory left in the chip. */
      /* Note that this value does not give the "fragmentation" state of the available memory. */
      /* This value only gives the amount of free memory */
      if( f_pBufferLoad->pulPlayoutFreeMemSize )
            *f_pBufferLoad->pulPlayoutFreeMemSize = ( f_pApiInstance->pSharedInfo->MiscVars.ulTotalMemSize - ( f_pApiInstance->pSharedInfo->MemoryMap.ulFreeMemBaseAddress - cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) ) - ( f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed );

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferUnloadSer

Description:    Unloads a buffer from external memory.

-------------------------------------------------------------------------------
|     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_pBufferUnload               Pointer to buffer unload structure.
f_fReleaseListStruct    Whether to release the buffer playout list structure
                                    or not.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferUnloadSer
UINT32 Oct6100BufferUnloadSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_UNLOAD                   f_pBufferUnload,
                        IN          BOOL                                            f_fReleaseListStruct )
{
      UINT32      ulBufferIndex;
      UINT32      ulBufferBase;
      UINT32      ulResult;

      /* Verify that all the parameters given match the state of the API. */
      ulResult = Oct6100ApiAssertBufferParams( f_pApiInstance, f_pBufferUnload, &ulBufferIndex, &ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Release all resources associated to the unloaded buffer. */
      ulResult = Oct6100ApiReleaseBufferResources( f_pApiInstance, ulBufferIndex, ulBufferBase, f_fReleaseListStruct );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiAssertBufferParams

Description:    Checks the buffer playout unload 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_pBufferUnload               Pointer to buffer unload structure.
f_pulBufferIndex        Pointer to the index of the buffer in the API's buffers list.
f_pulBufferBase               Pointer to the base address of the buffer in external memory.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiAssertBufferParams
UINT32 Oct6100ApiAssertBufferParams(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_UNLOAD                   f_pBufferUnload,
                        OUT         PUINT32                                               f_pulBufferIndex,
                        OUT         PUINT32                                               f_pulBufferBase )
{
      tPOCT6100_API_BUFFER    pBufEntry;

      *f_pulBufferIndex = f_pBufferUnload->ulBufferIndex;

      if ( *f_pulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX;

      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, *f_pulBufferIndex )

      /* Check for errors. */
      if ( pBufEntry->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN;
      if ( pBufEntry->usDependencyCnt != 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ACTIVE_DEPENDENCIES;
      
      /* Return all info needed to invalidate buffer. */
      *f_pulBufferBase = pBufEntry->ulBufferBase;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiReleaseBufferResources

Description:    Release resources needed by the buffer.

-------------------------------------------------------------------------------
|     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_ulBufferIndex               Allocated entry in buffer playout list.
f_ulBufferBase                Allocated external memory block for the buffer.
f_fReleaseListStruct    Free the list structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiReleaseBufferResources
UINT32 Oct6100ApiReleaseBufferResources(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN          UINT32                                          f_ulBufferIndex,
                        IN          UINT32                                          f_ulBufferBase,
                        IN          BOOL                                      f_fReleaseListStruct )
{
      tPOCT6100_SHARED_INFO   pSharedInfo;
      tPOCT6100_API_BUFFER    pBufEntry;
      UINT32      ulResult;
      UINT32      ulBufferSize;

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

      /* Free the external memory reserved for the buffer. */
      ulResult = Oct6100ApiReleaseBufferPlayoutMemory( f_pApiInstance, f_ulBufferBase );
      if ( ulResult != cOCT6100_ERR_OK )
            return cOCT6100_ERR_FATAL_3E;

      /* Release the entry from the buffer list. */
      if ( f_fReleaseListStruct == TRUE )
            ulResult = Oct6100ApiReleaseBufPlayoutListEntry( f_pApiInstance, f_ulBufferIndex );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_ulBufferIndex );

      /* Save buffer size before releasing that entry, will be needed to calculate the amount of */
      /* free memory left for the user. */
      ulBufferSize = pBufEntry->ulBufferSize;
      
      /* Flag the buffer entry as free. */
      pBufEntry->fReserved = FALSE;

      /* Decrement the number of buffer loaded into the chip. */
      f_pApiInstance->pSharedInfo->ChipStats.usNumberPlayoutBuffers--;

      /* Refresh the amount of memory used by buffer playout. */
      /* Reserved size is divisible by 64. */
      if ( ulBufferSize % 64 )
            ulBufferSize = ulBufferSize + ( 64 - ( ulBufferSize % 64 ) );
      f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed -= ulBufferSize;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferPlayoutAddSer

Description:    This function adds a buffer to a channel buffer 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_pBufferPlayoutAdd           Pointer to buffer playout add structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutAddSer
UINT32 Oct6100BufferPlayoutAddSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_PLAYOUT_ADD        f_pBufferPlayoutAdd )
{
      UINT32      ulBufferIndex;
      UINT32      ulChannelIndex;
      UINT32      ulResult;

      /* Check the user's configuration of the buffer for errors. */
      ulResult = Oct6100ApiCheckPlayoutAddParams( f_pApiInstance, f_pBufferPlayoutAdd, &ulChannelIndex, &ulBufferIndex );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Write to  all resources needed to activate buffer playout. */
      ulResult = Oct6100ApiWriteBufferAddStructs( f_pApiInstance, f_pBufferPlayoutAdd, ulChannelIndex, ulBufferIndex );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiCheckPlayoutAddParams

Description:      Check the validity of the channel and buffer requested.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutAdd           Pointer to buffer playout add structure.  
f_pulChannelIndex       Pointer to the channel index of the selected channel.
f_pulBufferIndex        Pointer to the buffer index within the API's buffer list.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiCheckPlayoutAddParams
UINT32 Oct6100ApiCheckPlayoutAddParams(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_PLAYOUT_ADD        f_pBufferPlayoutAdd,
                        OUT         PUINT32                                               f_pulChannelIndex, 
                        OUT         PUINT32                                               f_pulBufferIndex )
{
      tPOCT6100_API_BUFFER                pBufferEntry;
      tPOCT6100_API_CHANNEL               pEchoChannel;
      UINT32      ulEntryOpenCnt;

      /* Check for errors. */
      if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED;
      
      if ( f_pBufferPlayoutAdd->ulChannelHndl == cOCT6100_INVALID_HANDLE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      if ( f_pBufferPlayoutAdd->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && 
             f_pBufferPlayoutAdd->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT )
            return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT;

      if ( f_pBufferPlayoutAdd->fRepeat != TRUE && f_pBufferPlayoutAdd->fRepeat != FALSE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT;

      if ( f_pBufferPlayoutAdd->fRepeat == TRUE )
      {
            if ( f_pBufferPlayoutAdd->ulRepeatCount != cOCT6100_REPEAT_INFINITELY )
            {
                  if ( f_pBufferPlayoutAdd->ulRepeatCount == 0x0 
                        || f_pBufferPlayoutAdd->ulRepeatCount > cOCT6100_REPEAT_MAX)
                  {
                        return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT_COUNT;
                  }
            }
      }

      if ( f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_0_DB &&
             f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MINUS_6_DB &&
             f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MINUS_12_DB &&
             f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MUTE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_MIXING;

      if ( ( f_pBufferPlayoutAdd->lGainDb < -24 )
            || ( f_pBufferPlayoutAdd->lGainDb > 24 ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_GAIN_DB;

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

      if ( (f_pBufferPlayoutAdd->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      *f_pulChannelIndex = f_pBufferPlayoutAdd->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK;
      if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex )

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

      /* Check for errors. */
      if ( pEchoChannel->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN;
      if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      /* Check if repeat flag has been used for this port. */
      if ( ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinBufPlayoutRepeatUsed == TRUE ) )
            || ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutBufPlayoutRepeatUsed == TRUE ) ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_REPEAT_USED;

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

      /*=====================================================================*/
      /* Check the buffer information. */

      *f_pulBufferIndex = f_pBufferPlayoutAdd->ulBufferIndex;
      if ( *f_pulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX;

      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, *f_pulBufferIndex )

      if ( pBufferEntry->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN;

      /* Check if the play length is not larger then the currently uploaded buffer. */
      if ( ( f_pBufferPlayoutAdd->ulBufferLength > pBufferEntry->ulBufferSize ) &&
              ( f_pBufferPlayoutAdd->ulBufferLength != cOCT6100_AUTO_SELECT ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE;

      if( f_pBufferPlayoutAdd->ulBufferLength != cOCT6100_AUTO_SELECT )
      {
            if ( f_pBufferPlayoutAdd->ulBufferLength < cOCT6100_MINIMUM_BUFFER_SIZE )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_TOO_SMALL;

            if ( ( f_pBufferPlayoutAdd->ulBufferLength % cOCT6100_BUFFER_SIZE_GRANULARITY ) != 0 )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE;
      }

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

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiWriteBufferAddStructs

Description:    Write the buffer playout event in the channel's port playout
                        circular buffer.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutAdd           Pointer to buffer playout add structure.  
f_ulChannelIndex        Index of the channel on which the buffer is to be added.
f_ulBufferIndex               Index of the buffer structure within the API's buffer list.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiWriteBufferAddStructs
UINT32 Oct6100ApiWriteBufferAddStructs(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_PLAYOUT_ADD        f_pBufferPlayoutAdd,
                        IN          UINT32                                                f_ulChannelIndex, 
                        IN          UINT32                                                f_ulBufferIndex )
{
      tPOCT6100_API_BUFFER          pBufferEntry;
      tPOCT6100_API_CHANNEL         pEchoChannel;
      tPOCT6100_SHARED_INFO         pSharedInfo;
      tOCT6100_READ_PARAMS          ReadParams;
      UINT32      ulResult;
      UINT32      ulTempData;
      UINT32      ulEventBuffer;

      UINT32      ulReadPtrBytesOfst;
      UINT32      ulReadPtrBitOfst;
      UINT32      ulReadPtrFieldSize;

      UINT32      ulWritePtrBytesOfst;
      UINT32      ulWritePtrBitOfst;
      UINT32      ulWritePtrFieldSize;

      UINT32      ulWritePtr;
      UINT32      ulReadPtr;

      UINT32      ulPlayoutBaseAddress;
      UINT32      ulAddress;
      UINT32      ulEventIndex;
      UINT32      ulMask;

      UINT32      ulRepeatCount = 0;
      BOOL  fRepeatCountSet = FALSE;
      UINT32      ulDurationModulo = 0;
      UINT32      ulEventsToCreate = 1;
      UINT32      ulBufferDurationMs;
      
      UINT32      ulBufferLength;
      UINT16      usTempData = 0;

      UINT16      usReadData;
      UINT32      ulChipWritePtr;
      UINT32      ulReadData;
      UINT32      ulLoopCnt = 0;
      BOOL  fStillPlaying = TRUE;
      BOOL  fCheckHardStop = FALSE;
      BOOL  fOldBufferPlayoutVersion = FALSE;

      UINT32                  aulWaitTime[ 2 ];

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

      mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex );
      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, f_ulBufferIndex );

      /* Select the buffer of interest. */
      if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst;
            ulWritePtr = pEchoChannel->ulRinBufWritePtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4;
            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset;
            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize;

            ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4;
            ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset;
            ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize;
      }
      else /* f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst;
            ulWritePtr = pEchoChannel->ulSoutBufWritePtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4;
            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset;
            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize;

            ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4;
            ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset;
            ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize;
      }

      /*=======================================================================*/
      /* Calculate the repeat count. */

      /* The buffer length is either the total buffer size or the value specified by the user */
      if ( f_pBufferPlayoutAdd->ulBufferLength == cOCT6100_AUTO_SELECT )
      {
            ulBufferLength = pBufferEntry->ulBufferSize;
      }
      else
      {
            ulBufferLength = f_pBufferPlayoutAdd->ulBufferLength;
      }

      if ( f_pBufferPlayoutAdd->ulDuration != cOCT6100_INVALID_VALUE )
      {
            /* With duration and buffer length, we can find the number of times we must repeat playing this buffer. */
            ulBufferDurationMs = ulBufferLength / cOCT6100_SAMPLES_PER_MS;
            ulRepeatCount = f_pBufferPlayoutAdd->ulDuration / ulBufferDurationMs;
            fRepeatCountSet = TRUE;

            /* Check if buffer is larger then asked duration. */
            if ( ulRepeatCount != 0x0 )
            {
                  /* We might have to create more then 1 event to accomodate for the repeat-max limit. */
                  ulEventsToCreate = ( ulRepeatCount / cOCT6100_REPEAT_MAX ) + 1;
            }
            else
            {
                  /* No repeat event.  Maybe only the duration modulo! */
                  ulEventsToCreate = 0x0;
            }

            /* Check if must create a second event for a buffer that cannot be played completely. */
            ulDurationModulo = f_pBufferPlayoutAdd->ulDuration % ulBufferDurationMs;
            if ( ulDurationModulo != 0x0 )
            {
                  ulDurationModulo *= cOCT6100_SAMPLES_PER_MS;
                  if ( ulDurationModulo / cOCT6100_BUFFER_SIZE_GRANULARITY )
                  {
                        /* Round the modulo to be on a buffer size granularity. */
                        /* This will round down. */
                        ulDurationModulo = ( ulDurationModulo / cOCT6100_BUFFER_SIZE_GRANULARITY ) * cOCT6100_BUFFER_SIZE_GRANULARITY;

                        /* If the event about to be created is smaller then the minimum buffer size, */
                        /* round up to the minimum required by the hardware. */
                        if ( ulDurationModulo < cOCT6100_MINIMUM_BUFFER_SIZE )
                              ulDurationModulo = cOCT6100_MINIMUM_BUFFER_SIZE;
                        ulEventsToCreate++;
                  }
                  else
                  {
                        /* The modulo is too small to be played.  Skip. */
                        ulDurationModulo = 0;
                  }
            }
      }
      else if ( f_pBufferPlayoutAdd->fRepeat == TRUE 
            && f_pBufferPlayoutAdd->ulRepeatCount != cOCT6100_REPEAT_INFINITELY )
      {
            /* The repeat count is set directly from the user. */
            ulRepeatCount = f_pBufferPlayoutAdd->ulRepeatCount;
            fRepeatCountSet = TRUE;
      }
      
      /*=======================================================================*/

      /* Set the playout feature base address. */
      ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst;

      /* Read the read pointer. */
      ulAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst;

      /* Must read in memory directly since this value is changed by hardware. */
      ulResult = Oct6100ApiReadDword( f_pApiInstance, ulAddress, &ulTempData );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask );
      
      /* Store the read pointer. */
      ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst;

      /* Compare the pointers...  Are they different?  If so, there is something already in the list.  */
      if ( ulReadPtr != ulWritePtr )
      {
            /* Check if there is enough room for the playout events. */
            if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE )
                  && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) )
            {
                  /* 127 or 31 events image. */
                  if ( (UINT8)( ( ulWritePtr - ulReadPtr ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ) ) >= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - (UINT8)ulEventsToCreate ) )
                        fCheckHardStop = TRUE;
            }
            else
            {
                  /* Old 31 events image. */
                  if ( ( ( ulWritePtr - ulReadPtr ) & 0x1F ) >= ( 0x20 - ulEventsToCreate ) )
                        fCheckHardStop = TRUE;

                  fOldBufferPlayoutVersion = TRUE;
            }

            if ( fCheckHardStop == TRUE )
            {
                  /* Ok.  From what was read, the list is full.  But we might still have a chance if the hard-stop */
                  /* version was used.  In this case, some of the buffers in the list might */
                  /* become free in a couple of milliseconds, so try to wait for this. */
                  
                  if ( ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinHardStop == TRUE ) )
                        || ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutHardStop == TRUE ) ) )
                  {
                        /* Read the 'chip' write pointer in the hardware. */
                        ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

                        ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
                        ReadParams.pusReadData = &usReadData;
                        ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst;

                        /* Get the write pointer in the chip. */
                        ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst;

                        mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulReadData, ulResult );
                        if ( ulResult != cOCT6100_ERR_OK )
                              return ulResult;

                        mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask );

                        /* Store the write pointer. */
                        ulChipWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst;

                        /* Optimize this access by only reading the word we are interested in. */
                        if ( ulReadPtrBitOfst < 16 )
                              ReadParams.ulReadAddress += 2;

                        while( fStillPlaying == TRUE )
                        {                       
                              /* Read the read pointer until equals to the write pointer. */
                              mOCT6100_DRIVER_READ_API( ReadParams, ulResult )
                              if ( ulResult != cOCT6100_ERR_OK )
                                    return ulResult;

                              /* Move data at correct position according to what was read. */
                              if ( ulReadPtrBitOfst < 16 )
                                    ulTempData = usReadData;
                              else
                                    ulTempData = usReadData << 16;
                              
                              mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask );
                              
                              /* Store the read pointer.*/
                              ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst;

                              /* Playout has finished when the read pointer reaches the write pointer. */
                              if ( ulReadPtr == ulChipWritePtr )
                                    break;

                              ulLoopCnt++;
                              if ( ulLoopCnt > cOCT6100_MAX_LOOP )
                              {
                                    return cOCT6100_ERR_FATAL_E7;
                              }

                              aulWaitTime[ 0 ] = 100;
                              aulWaitTime[ 1 ] = 0;
                              ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime );
                              if ( ulResult != cOCT6100_ERR_OK )
                                    return ulResult;              
                        }

                        /* Clear hard-stop flag. */
                        if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
                        {
                              /* No hard stop for now. */
                              pEchoChannel->fRinHardStop = FALSE;
                        }
                        else /* if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */
                        {
                              /* No hard stop for now. */
                              pEchoChannel->fSoutHardStop = FALSE;
                        }

                        /* Now check again if the event can be added... */
                        if ( fOldBufferPlayoutVersion == FALSE )
                        {
                              if ( (UINT8)( ( ulWritePtr - ulReadPtr ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ) ) >= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - (UINT8)ulEventsToCreate ) )
                                    return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL;
                        }
                        else /* if ( fOldBufferPlayoutVersion == TRUE ) */
                        {
                              /* Old 31 events image. */
                              if ( ( ( ulWritePtr - ulReadPtr ) & 0x1F ) >= ( 0x20 - ulEventsToCreate ) )
                                    return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL;
                        }

                        /* Good, at least another buffer can be added!  Add the buffer to the list. */
                  }
                  else
                  {
                        /* Well the list is full! */
                        return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL;
                  }
            }
      }

      /*=======================================================================*/
      /* Write the events. */

      for ( ulEventIndex = 0; ulEventIndex < ulEventsToCreate; ulEventIndex ++  )
      {
            /* Set the playout event base address. */
            if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE )
                  && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) )
            {
                  /* 127 or 31 events image. */
                  ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + (f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * (ulWritePtr & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 )));
            }
            else
            {
                  /* Old 31 events image. */
                  ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + (f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * (ulWritePtr & 0x1F));
            }
      
            /* EVENT BASE + 0 */
            /* Make sure the xIS and xHS bits are cleared. */
            ulTempData = 0;

            /* Set the repeat count. */
            if ( fRepeatCountSet == TRUE )
            {
                  if ( ( ulRepeatCount != 0x0 ) && ( ulRepeatCount <= cOCT6100_REPEAT_MAX ) )
                  {
                        /* Use repeat count directly. */
                        ulTempData |= ulRepeatCount;

                        /* Will be used later when creating the duration modulo event. */
                        ulRepeatCount = 0;
                  }
                  else if ( ulRepeatCount != 0x0 )
                  {
                        /* Get ready for next event. */
                        ulRepeatCount -= cOCT6100_REPEAT_MAX;

                        /* Set maximum for this event. */
                        ulTempData |= cOCT6100_REPEAT_MAX;
                  }
                  else
                  {
                        /* Duration modulo case.  Nothing to set here. */
                  }
            }
            else /* if ( fRepeatCountSet != TRUE ) */
            {
                  /* Repeat only once. */
                  ulTempData |= 0x1;
            }

            ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            /* EVENT BASE + 4 */
            /* Set the buffer base address and playout configuration. */
            ulAddress += 4;
            ulTempData = pBufferEntry->ulBufferBase & 0x07FFFFFF;

            /* Set play indefinitely or loop N times. */
            if ( ( fRepeatCountSet == FALSE ) && ( f_pBufferPlayoutAdd->fRepeat == TRUE ) )
            {
                  /* Repeat indefinitely. */
                  ulTempData |= 0x1 << cOCT6100_PLAYOUT_EVENT_REPEAT_OFFSET;

                  if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
                        pEchoChannel->fRinBufPlayoutRepeatUsed = TRUE;
                  else /* if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */
                        pEchoChannel->fSoutBufPlayoutRepeatUsed = TRUE;
            }
            
            /* Use loop N times feature. */
            ulTempData |= 0x1 << cOCT6100_PLAYOUT_EVENT_LOOP_TIMES_OFFSET;

            /* Set the law.*/
            ulTempData |= ( pBufferEntry->byBufferPcmLaw << cOCT6100_PLAYOUT_EVENT_LAW_OFFSET );

            /* Set the mixing configuration.*/
            ulTempData |= f_pBufferPlayoutAdd->ulMixingMode << cOCT6100_PLAYOUT_EVENT_MIX_OFFSET;

            ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            
            /* EVENT BASE + 8 */
            /* Set the buffer size and playout gain. */
            ulAddress += 4;

            /* Check if we are setting the duration modulo.  This would be the last event and this */
            /* event is of a very specific size. */
            if ( ( fRepeatCountSet == TRUE ) 
                  && ( ulEventIndex == ( ulEventsToCreate - 1 ) ) 
                  && ( ulDurationModulo != 0x0 ) )
            {
                  /* The duration modulo variable contains all that is needed here. */
                  ulBufferLength = ulDurationModulo;
            }
            ulTempData = ulBufferLength;

            /* Adjust playout gain. */
            if ( f_pBufferPlayoutAdd->lGainDb != 0 )
            {
                  /* Convert the dB value into OctFloat format. */
                  usTempData = Oct6100ApiDbAmpHalfToOctFloat( f_pBufferPlayoutAdd->lGainDb );
                  ulTempData |= ( usTempData & 0xFF00 ) << 16;
            }
            else
            {
                  ulTempData |= cOCT6100_PLAYOUT_GAIN;
            }

            ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;
                  
            /* EVENT BASE + 0xC */
            ulAddress += 4;
            ulTempData = ( ulBufferLength - 1 ) & 0xFFFFFFC0;     /* Must be multiple of 64 bytes */

            /* Adjust playout gain. */
            if ( f_pBufferPlayoutAdd->lGainDb != 0 )
            {
                  ulTempData |= ( usTempData & 0xFF ) << 24;
            }

            ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            /* Next event. */
            ulWritePtr++;
      }

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


      /*=======================================================================*/
      /* Increment the write pointer to make it point to the next empty entry. */

      if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            pEchoChannel->ulRinBufWritePtr = ( pEchoChannel->ulRinBufWritePtr + ulEventsToCreate ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 );
            /* Remember that a buffer was added on the rin port. */
            pEchoChannel->fRinBufAdded = TRUE;
      }
      else /* f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            pEchoChannel->ulSoutBufWritePtr = ( pEchoChannel->ulSoutBufWritePtr + ulEventsToCreate ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 );
            /* Remember that a buffer was added on the sout port. */
            pEchoChannel->fSoutBufAdded = TRUE;
      }

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

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferPlayoutStartSer

Description:    Starts buffer playout on 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_pBufferPlayoutStart         Pointer to buffer playout start structure.

f_ulPlayoutStopEventType      Playout stop event type to be generated if required.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutStartSer
UINT32 Oct6100BufferPlayoutStartSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_PLAYOUT_START            f_pBufferPlayoutStart,
                        IN          UINT32                                                f_ulPlayoutStopEventType )
{
      UINT32      ulBufferIndex = 0;
      UINT32      ulChannelIndex;
      BOOL  fNotifyOnPlayoutStop;
      UINT32      ulUserEventId;
      BOOL  fAddToCurrentlyPlayingList;
      UINT32      ulResult;

      /* Check the user's configuration of the buffer for errors. */
      ulResult = Oct6100ApiCheckPlayoutStartParams( f_pApiInstance, f_pBufferPlayoutStart, &ulChannelIndex, &ulBufferIndex, &fNotifyOnPlayoutStop, &ulUserEventId, &fAddToCurrentlyPlayingList );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Write to all resources needed to activate buffer playout. */
      ulResult = Oct6100ApiWriteChanPlayoutStructs( f_pApiInstance, f_pBufferPlayoutStart, ulChannelIndex, ulBufferIndex, fNotifyOnPlayoutStop, ulUserEventId, fAddToCurrentlyPlayingList, f_ulPlayoutStopEventType );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiCheckPlayoutStartParams

Description:      Check the validity of the channel and buffer requested.
                        Check the validity of the flags requested.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutStart   Pointer to buffer playout start structure.  
f_pulChannelIndex       Pointer to the channel index of the selected channel.
f_pulBufferIndex        Pointer to the buffer index within the API's buffer list.
f_pfNotifyOnPlayoutStop Pointer to the notify on playout stop flag.
f_pulUserEventId        Pointer to the user event id specified.
f_pfAllowStartIfActive  Pointer to the add to currently playing list flag.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiCheckPlayoutStartParams
UINT32 Oct6100ApiCheckPlayoutStartParams(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_PLAYOUT_START            f_pBufferPlayoutStart,
                        OUT         PUINT32                                               f_pulChannelIndex, 
                        OUT         PUINT32                                               f_pulBufferIndex,
                        OUT         PBOOL                                           f_pfNotifyOnPlayoutStop,
                        OUT         PUINT32                                               f_pulUserEventId,
                        OUT         PBOOL                                           f_pfAllowStartIfActive )
{
      tPOCT6100_API_CHANNEL   pEchoChannel;
      UINT32                              ulEntryOpenCnt;

      /* Check for errors. */
      if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED;
      
      if ( f_pBufferPlayoutStart->ulChannelHndl == cOCT6100_INVALID_HANDLE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      if ( f_pBufferPlayoutStart->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && 
             f_pBufferPlayoutStart->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT )
            return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT;

      if ( f_pBufferPlayoutStart->fNotifyOnPlayoutStop != FALSE
            && f_pBufferPlayoutStart->fNotifyOnPlayoutStop != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOTIFY_ON_STOP;

      if ( f_pBufferPlayoutStart->fAllowStartWhileActive != FALSE
            && f_pBufferPlayoutStart->fAllowStartWhileActive != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ALLOW_ACTIVE;

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

      if ( (f_pBufferPlayoutStart->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      *f_pulChannelIndex = f_pBufferPlayoutStart->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK;
      if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex )

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

      /* Check for errors. */
      if ( pEchoChannel->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN;
      if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      /* The channel cannot be in POWER_DOWN or HT_FREEZE to start the playout. */
      if ( ( pEchoChannel->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN )
            || ( pEchoChannel->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_HT_FREEZE ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_ECHO_OP_MODE;
      
      /* The channel's NLP must be enabled for playout to occur. */
      if ( pEchoChannel->VqeConfig.fEnableNlp == FALSE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NLP_DISABLED;

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

      /*=====================================================================*/
      /* Check if the user activated the buffer playout events. */

      if ( f_pBufferPlayoutStart->fNotifyOnPlayoutStop == TRUE
            && f_pApiInstance->pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize == 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_DISABLED;

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

      /*=====================================================================*/
      /* Check if there is actually a buffer added in the list. */

      if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            if ( pEchoChannel->fRinBufAdded == FALSE )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_LIST_EMPTY;
      }
      else /* if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */
      {
            if ( pEchoChannel->fSoutBufAdded == FALSE )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_LIST_EMPTY;
      }

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

      /* Return the requested information. */
      *f_pfNotifyOnPlayoutStop = f_pBufferPlayoutStart->fNotifyOnPlayoutStop;
      *f_pulUserEventId = f_pBufferPlayoutStart->ulUserEventId;
      *f_pfAllowStartIfActive = f_pBufferPlayoutStart->fAllowStartWhileActive;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiWriteChanPlayoutStructs

Description:    Write the buffer playout event in the channel main structure.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutStart         Pointer to buffer playout start structure.
f_ulChannelIndex              Index of the channel within the API's channel list.
f_ulBufferIndex                     Index of the buffer within the API's buffer list.
f_fNotifyOnPlayoutStop        Flag for the notify on playout stop.
f_ulUserEventId                     User event id passed to the user when a playout event is generated.
f_fAllowStartIfActive         Add to currently playing list flag.
f_ulPlayoutStopEventType      Playout stop event type to be generated if required.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiWriteChanPlayoutStructs
UINT32 Oct6100ApiWriteChanPlayoutStructs(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_PLAYOUT_START            f_pBufferPlayoutStart,
                        IN          UINT32                                                f_ulChannelIndex, 
                        IN          UINT32                                                f_ulBufferIndex,
                        IN          BOOL                                            f_fNotifyOnPlayoutStop,
                        IN          UINT32                                                f_ulUserEventId,
                        IN          BOOL                                            f_fAllowStartIfActive,
                        IN          UINT32                                                f_ulPlayoutStopEventType )
{
      tPOCT6100_API_BUFFER                pBufferEntry;
      tPOCT6100_API_CHANNEL               pEchoChannel;
      tPOCT6100_SHARED_INFO               pSharedInfo;
      tOCT6100_READ_PARAMS                ReadParams;
      
      UINT32      ulResult;

      UINT32      ulWritePtr;
      UINT32      ulChipWritePtr;
      PUINT32     pulSkipPtr;
      UINT32      ulWritePtrBytesOfst;
      UINT32      ulSkipPtrBytesOfst;
      UINT32      ulWritePtrBitOfst;
      UINT32      ulSkipPtrBitOfst;
      UINT32      ulWritePtrFieldSize;
      UINT32      ulSkipPtrFieldSize;

      UINT32      ulIgnoreBytesOfst;
      UINT32      ulIgnoreBitOfst;
      UINT32      ulIgnoreFieldSize;
      
      UINT32      ulHardSkipBytesOfst;
      UINT32      ulHardSkipBitOfst;
      UINT32      ulHardSkipFieldSize;

      UINT32      ulReadPtrBytesOfst;
      UINT32      ulReadPtrBitOfst;
      UINT32      ulReadPtrFieldSize;

      UINT32      ulPlayoutBaseAddress;
      UINT32      ulAddress;
      UINT32      ulTempData;
      UINT32      ulMask;
      UINT32      ulReadData;
      UINT32      ulReadPtr;
      UINT32      ulLoopCnt = 0;

      UINT16      usReadData;

      BOOL  fBufferPlayoutStopDetected;
      BOOL  fWriteSkipPtr = FALSE;
      BOOL  fStillPlaying = TRUE;

      UINT32                  aulWaitTime[ 2 ];

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

      mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex );
      mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, f_ulBufferIndex );

      /* First off, check for buffer playout events, if requested for this channel/port. */
      /* At the same time, if requested, check that the playout has stopped for this channel/port. */
      if ( ( ( pEchoChannel->fRinBufPlaying == TRUE )
                  && ( ( pEchoChannel->fRinBufPlayoutNotifyOnStop == TRUE ) || ( f_fAllowStartIfActive == FALSE ) )
                  && ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) )
            || ( ( ( pEchoChannel->fSoutBufPlaying == TRUE ) || ( f_fAllowStartIfActive == FALSE ) )
                  && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == TRUE )
                  && ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) ) )
      {
            /* Buffer playout might still be going on for this channel/port. */
            ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, 
                                                                                                f_ulChannelIndex, 
                                                                                                f_pBufferPlayoutStart->ulPlayoutPort,
                                                                                                pEchoChannel->fRinBufPlayoutNotifyOnStop, 
                                                                                                &fBufferPlayoutStopDetected );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            /* Check if the user requested to only start if playout is over.  Return an error if */
            /* buffer playout is still going on on this channel/port. */
            if ( ( f_fAllowStartIfActive == FALSE ) && ( fBufferPlayoutStopDetected == FALSE ) )
            {
                  /* No go!  User should wait for the current list to stop, or call the */
                  /* Oct6100BufferPlayoutStop function. */
                  return cOCT6100_ERR_BUFFER_PLAYOUT_STILL_ACTIVE;
            }
      }

      /* Select the buffer of interest. */
      if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            ulWritePtr  = pEchoChannel->ulRinBufWritePtr;
            pulSkipPtr  = &pEchoChannel->ulRinBufSkipPtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4;
            ulSkipPtrBytesOfst  = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.usDwordOffset * 4;
            ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.usDwordOffset * 4;
            ulHardSkipBytesOfst     = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.usDwordOffset * 4;
            ulReadPtrBytesOfst      = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4;

            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset;
            ulSkipPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byBitOffset;
            ulIgnoreBitOfst         = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byBitOffset;
            ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byBitOffset;
            ulReadPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset;

            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize;
            ulSkipPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byFieldSize;
            ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byFieldSize;
            ulHardSkipFieldSize     = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byFieldSize;
            ulReadPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize;
      }
      else /* f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            ulWritePtr  = pEchoChannel->ulSoutBufWritePtr;
            pulSkipPtr  = &pEchoChannel->ulSoutBufSkipPtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4;
            ulSkipPtrBytesOfst  = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.usDwordOffset * 4;
            ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.usDwordOffset * 4;
            ulHardSkipBytesOfst     = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.usDwordOffset * 4;
            ulReadPtrBytesOfst      = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4;

            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset;
            ulSkipPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byBitOffset;
            ulIgnoreBitOfst         = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byBitOffset;
            ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byBitOffset;
            ulReadPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset;

            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize;
            ulSkipPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byFieldSize;
            ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byFieldSize;
            ulHardSkipFieldSize     = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byFieldSize;
            ulReadPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize;
      }
      


      /* Set the playout feature base address. */
      ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst;

      /* Check if we must wait for stop to complete before starting a new list. */
      if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE )
      {
            if ( ( ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinHardStop == TRUE ) )
                  || ( ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutHardStop == TRUE ) ) )
            {
                  /* Read the read pointer. */
                  ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

                  ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
                  ReadParams.pusReadData = &usReadData;
                  ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst;

                  /* Get the write pointer in the chip. */
                  ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulReadData, ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;

                  mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask );

                  /* Store the write pointer. */
                  ulChipWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst;

                  /* Optimize this access by only reading the word we are interested in. */
                  if ( ulReadPtrBitOfst < 16 )
                        ReadParams.ulReadAddress += 2;

                  while( fStillPlaying == TRUE )
                  {                       
                        /* Read the read pointer until equals to the write pointer. */
                        mOCT6100_DRIVER_READ_API( ReadParams, ulResult )
                        if ( ulResult != cOCT6100_ERR_OK )
                              return ulResult;

                        /* Move data at correct position according to what was read. */
                        if ( ulReadPtrBitOfst < 16 )
                              ulTempData = usReadData;
                        else
                              ulTempData = usReadData << 16;
                        
                        mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask );
                        
                        /* Store the read pointer. */
                        ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst;

                        /* Playout has finished when the read pointer reaches the write pointer. */
                        if ( ulReadPtr == ulChipWritePtr )
                              break;

                        ulLoopCnt++;
                        if( ulLoopCnt > cOCT6100_MAX_LOOP )
                        {
                              return cOCT6100_ERR_FATAL_E6;
                        }

                        aulWaitTime[ 0 ] = 100;
                        aulWaitTime[ 1 ] = 0;
                        ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime );
                        if ( ulResult != cOCT6100_ERR_OK )
                              return ulResult;              
                  }
            }
      }

      /* Check if must clear the skip bit. */
      if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE )
      {
            if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE )
                  && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) )
            {
                  /* Make sure the skip bit is cleared to start playout! */
                  ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
                  
                  mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask );

                  /* Cleared! */
                  ulTempData &= ( ~ulMask );

                  mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  ulTempData,
                                                                  ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;

                  /* Make sure the hard skip bit is cleared to start playout! */
                  ulAddress = ulPlayoutBaseAddress + ulHardSkipBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                                        pEchoChannel,
                                                                        ulAddress,
                                                                        &ulTempData,
                                                                        ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
                  
                  mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulHardSkipBitOfst, &ulMask );

                  /* Cleared! */
                  ulTempData &= ( ~ulMask );

                  mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  ulTempData,
                                                                  ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
            }
      }

      /* Write the skip and write pointer to activate buffer playout. */

      /* Update the skip pointer. */
      if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == FALSE )
            || ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == FALSE ) )
      {
            /* Old 31 events image. */
            if ( ( ( ulWritePtr - *pulSkipPtr ) & 0x7F ) > 63 )
            {
                  *pulSkipPtr = ( ulWritePtr - 63 ) & 0x7F;
                  fWriteSkipPtr = TRUE;
            }
      }
      else
      {
            /* No need to update the skip pointer, a bit needs to be set when skipping. */
            /* fWriteSkipPtr set to FALSE from variable declaration. */
      }

      if ( fWriteSkipPtr == TRUE )
      {
            /*=======================================================================*/
            /* Fetch and modify the skip pointer. */  

            ulAddress = ulPlayoutBaseAddress + ulSkipPtrBytesOfst;

            mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  &ulTempData,
                                                                  ulResult );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;
            
            mOCT6100_CREATE_FEATURE_MASK( ulSkipPtrFieldSize, ulSkipPtrBitOfst, &ulMask );
            
            ulTempData &= ( ~ulMask );
            ulTempData |= *pulSkipPtr << ulSkipPtrBitOfst;
            
            mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                            pEchoChannel,
                                                            ulAddress,
                                                            ulTempData,
                                                            ulResult );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

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


      /*=======================================================================*/
      /* Fetch and modify the write pointer. */ 

      ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst;

      mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                            pEchoChannel,
                                                            ulAddress,
                                                            &ulTempData,
                                                            ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask );
      
      ulTempData &= ( ~ulMask );
      ulTempData |= ulWritePtr << ulWritePtrBitOfst;
      
      mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                      pEchoChannel,
                                                      ulAddress,
                                                      ulTempData,
                                                      ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      /*=======================================================================*/
      

      /*=======================================================================*/
      /* Now update the state of the channel stating that the buffer playout is activated. */

      /* Select the buffer of interest.*/
      if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            /* Check if the global ports active stat must be incremented. */
            if ( pEchoChannel->fRinBufPlaying == FALSE )
            {
                  /* Increment the number of active buffer playout ports. */
                  pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts++;
            }

            pEchoChannel->fRinBufPlaying = TRUE;
            /* Keep the new notify on event flag. */
            pEchoChannel->fRinBufPlayoutNotifyOnStop = (UINT8)( f_fNotifyOnPlayoutStop & 0xFF );
            /* Keep the specified user event id. */
            pEchoChannel->ulRinUserBufPlayoutEventId = f_ulUserEventId;
            /* Keep type of event to be generated. */
            pEchoChannel->byRinPlayoutStopEventType = (UINT8)( f_ulPlayoutStopEventType & 0xFF );
            /* No hard stop for now. */
            pEchoChannel->fRinHardStop = FALSE;
            /* No buffer added in the rin list for now. */
            pEchoChannel->fRinBufAdded = FALSE;
            /* Buffer playout is active on this channel. */
            pEchoChannel->fBufPlayoutActive = TRUE;
      }
      else /* f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            /* Check if the global ports active stat must be incremented. */
            if ( pEchoChannel->fSoutBufPlaying == FALSE )
            {
                  /* Increment the number of active buffer playout ports. */
                  pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts++;
            }

            pEchoChannel->fSoutBufPlaying = TRUE;
            /* Keep the new notify on event flag. */
            pEchoChannel->fSoutBufPlayoutNotifyOnStop = (UINT8)( f_fNotifyOnPlayoutStop & 0xFF );
            /* Keep the specified user event id. */
            pEchoChannel->ulSoutUserBufPlayoutEventId = f_ulUserEventId;
            /* Keep type of event to be generated. */
            pEchoChannel->bySoutPlayoutStopEventType = (UINT8)( f_ulPlayoutStopEventType & 0xFF );
            /* No hard stop for now. */
            pEchoChannel->fSoutHardStop = FALSE;
            /* No buffer added in the sout list for now. */
            pEchoChannel->fSoutBufAdded = FALSE;
            /* Buffer playout is active on this channel. */
            pEchoChannel->fBufPlayoutActive = TRUE;
      }

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100BufferPlayoutStopSer

Description:    Stops buffer playout on 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_pBufferPlayoutStop    Pointer to buffer playout stop structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100BufferPlayoutStopSer
UINT32 Oct6100BufferPlayoutStopSer(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN OUT      tPOCT6100_BUFFER_PLAYOUT_STOP       f_pBufferPlayoutStop )
{
      UINT32      ulChannelIndex;
      UINT16      usEchoMemIndex;
      UINT32      ulResult;

      /* Check the user's configuration of the buffer for errors. */
      ulResult = Oct6100ApiAssertPlayoutStopParams( 
                                                                        f_pApiInstance, 
                                                                        f_pBufferPlayoutStop, 
                                                                        &ulChannelIndex, 
                                                                        &usEchoMemIndex );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      /* Write to  all resources needed to deactivate buffer playout. */
      ulResult = Oct6100ApiInvalidateChanPlayoutStructs( 
                                                                        f_pApiInstance, 
                                                                        f_pBufferPlayoutStop, 
                                                                        ulChannelIndex, 
                                                                        usEchoMemIndex 

                                                                        );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiAssertPlayoutStopParams

Description:      Check the validity of the channel and buffer requested.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutStop    Pointer to buffer playout stop structure.  
f_pulChannelIndex       Pointer to the channel index on which playout is to be stopped.
f_pusEchoMemIndex       Pointer to the echo mem index on which playout is to be stopped.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiAssertPlayoutStopParams
UINT32 Oct6100ApiAssertPlayoutStopParams(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_PLAYOUT_STOP       f_pBufferPlayoutStop,
                        OUT         PUINT32                                               f_pulChannelIndex,
                        OUT         PUINT16                                               f_pusEchoMemIndex )
{
      tPOCT6100_API_CHANNEL         pEchoChannel;
      UINT32      ulEntryOpenCnt;

      /* Check for errors. */
      if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 )
            return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED;
      
      if ( f_pBufferPlayoutStop->ulChannelHndl == cOCT6100_INVALID_HANDLE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      if ( f_pBufferPlayoutStop->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && 
             f_pBufferPlayoutStop->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT )
            return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT;

      if ( f_pBufferPlayoutStop->fStopCleanly != TRUE && f_pBufferPlayoutStop->fStopCleanly != FALSE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_STOP_CLEANLY;
      
      /*=====================================================================*/
      /* Check the channel handle. */

      if ( (f_pBufferPlayoutStop->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      *f_pulChannelIndex = f_pBufferPlayoutStop->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK;
      if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex )

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

      /* Check for errors. */
      if ( pEchoChannel->fReserved != TRUE )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN;
      if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt )
            return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID;

      /* Return echo memory index. */
      *f_pusEchoMemIndex = pEchoChannel->usEchoMemIndex;

      /* Check if buffer playout is active for the selected port. */
      if ( ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
            && ( pEchoChannel->fRinBufPlaying == FALSE )
            && ( pEchoChannel->fRinBufAdded == FALSE ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED;

      if ( ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT )
            && ( pEchoChannel->fSoutBufPlaying == FALSE )
             && ( pEchoChannel->fSoutBufAdded == FALSE ) )
            return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED;
      
      /*=====================================================================*/

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiInvalidateChanPlayoutStructs

Description:    Write the buffer playout event in the channel main structure.

-------------------------------------------------------------------------------
|     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_pBufferPlayoutStop          Pointer to buffer playout stop structure.  
f_ulChannelIndex              Index of the channel within the API's channel list.
f_usEchoMemIndex              Index of the echo channel in hardware memory.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiInvalidateChanPlayoutStructs
UINT32 Oct6100ApiInvalidateChanPlayoutStructs(
                        IN OUT      tPOCT6100_INSTANCE_API                    f_pApiInstance,
                        IN          tPOCT6100_BUFFER_PLAYOUT_STOP       f_pBufferPlayoutStop,
                        IN          UINT32                                                f_ulChannelIndex,
                        IN          UINT16                                                f_usEchoMemIndex

                        )
{
      tPOCT6100_API_CHANNEL   pEchoChannel;
      tPOCT6100_SHARED_INFO   pSharedInfo;
      tOCT6100_READ_PARAMS    ReadParams;
      tOCT6100_WRITE_PARAMS   WriteParams;

      UINT32      ulResult;

      UINT32      ulWritePtrBytesOfst;
      UINT32      ulWritePtrBitOfst;
      UINT32      ulWritePtrFieldSize;
      UINT32      ulSkipPtrBytesOfst;
      UINT32      ulSkipPtrBitOfst;
      UINT32      ulSkipPtrFieldSize;
      UINT32      ulIgnoreBytesOfst;
      UINT32      ulIgnoreBitOfst;
      UINT32      ulIgnoreFieldSize;
      UINT32      ulHardSkipBytesOfst;
      UINT32      ulHardSkipBitOfst;
      UINT32      ulHardSkipFieldSize;
      UINT32      ulReadPtrBytesOfst;
      UINT32      ulReadPtrBitOfst;
      UINT32      ulReadPtrFieldSize;

      UINT32      ulSkipPtr;
      UINT32      ulWritePtr;
      UINT32      ulReadPtr = 0;
      UINT32      ulCurrentPtr;

      UINT32      ulPlayoutBaseAddress;
      UINT32      ulAddress;
      UINT32      ulTempData;
      UINT32      ulMask;
      UINT32      ulReadData;

      UINT16      usReadData; 
      BOOL  fCheckStop = FALSE;

      UINT32      ulEventBuffer;

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

      WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

      WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId;

      ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

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

      mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex );

      /* Select the port of interest. */
      if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            ulWritePtr = pEchoChannel->ulRinBufWritePtr; 
            ulSkipPtr  = ulWritePtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4;
            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset;
            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize;

            ulSkipPtrBytesOfst  = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.usDwordOffset * 4;
            ulSkipPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byBitOffset;
            ulSkipPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byFieldSize;

            ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.usDwordOffset * 4;
            ulIgnoreBitOfst         = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byBitOffset;
            ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byFieldSize;

            ulHardSkipBytesOfst     = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.usDwordOffset * 4;
            ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byBitOffset;
            ulHardSkipFieldSize     = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byFieldSize;

            ulReadPtrBytesOfst      = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4;
            ulReadPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset;
            ulReadPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize;
      }
      else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            ulWritePtr = pEchoChannel->ulSoutBufWritePtr; 
            ulSkipPtr  = ulWritePtr;

            ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4;
            ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset;
            ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize;

            ulSkipPtrBytesOfst  = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.usDwordOffset * 4;
            ulSkipPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byBitOffset;
            ulSkipPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byFieldSize;

            ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.usDwordOffset * 4;
            ulIgnoreBitOfst         = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byBitOffset;
            ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byFieldSize;

            ulHardSkipBytesOfst     = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.usDwordOffset * 4;
            ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byBitOffset;
            ulHardSkipFieldSize     = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byFieldSize;

            ulReadPtrBytesOfst      = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4;
            ulReadPtrBitOfst  = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset;
            ulReadPtrFieldSize      = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize;
      }

      /* Set the playout feature base address. */
      ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst;

      /* Check if something is currently playing. */
      if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            if ( pEchoChannel->fRinBufPlaying == TRUE )
            {
                  /* Check if we are stopping it or if it stopped by itself. */
                  fCheckStop = TRUE;
            }
            else
            {
                  /* Not playing! */
                  if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL )
                        *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE;
            }
      }
      else /* if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */
      {
            if ( pEchoChannel->fSoutBufPlaying == TRUE )
            {
                  /* Check if we are stopping it or if it stopped by itself. */
                  fCheckStop = TRUE;
            }
            else
            {
                  /* Not playing! */
                  if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL )
                        *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE;
            }
      }

      if ( ( fCheckStop == TRUE ) || ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) )
      {
            /* Read the read pointer. */
            ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

            ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
            ReadParams.pusReadData = &usReadData;
            ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst;

            /* Optimize this access by only reading the word we are interested in. */
            if ( ulReadPtrBitOfst < 16 )
                  ReadParams.ulReadAddress += 2;

            /* Must read in memory directly since this value is changed by hardware */
            mOCT6100_DRIVER_READ_API( ReadParams, ulResult )
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;

            /* Move data at correct position according to what was read. */
            if ( ulReadPtrBitOfst < 16 )
                  ulTempData = usReadData;
            else
                  ulTempData = usReadData << 16;
            
            mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask );
            
            /* Store the read pointer. */
            ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst;

            /* Playout has finished when the read pointer reaches the write pointer. */
            if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL )
            {
                  if ( ulReadPtr != ulWritePtr )
                        *f_pBufferPlayoutStop->pfAlreadyStopped = FALSE;
                  else /* if ( ulReadPtr == ulWritePtr ) */
                        *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE;
            }
      }

      /* If the skip bits are located in the event itself, the playout is stopped by setting the */
      /* skip pointer to the hardware chip write pointer.  Read it directly from the NLP configuration. */
      if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE )
      {
            if ( ulReadPtr != ulWritePtr )
            {
                  /* Get the write pointer in the chip. */
                  ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulReadData, ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;

                  mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask );

                  /* Store the write pointer. */
                  ulWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst;
                  ulSkipPtr = ulWritePtr;
            }
      }

      /* Check if must clear repeat bit. */
      if ( ( ( pEchoChannel->fRinBufPlayoutRepeatUsed == TRUE ) && ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) )
            || ( ( pEchoChannel->fSoutBufPlayoutRepeatUsed == TRUE ) && ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) ) )
      {
            if ( ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE )
                  || ( ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE )
                        && ( ulWritePtr != ulReadPtr ) ) )
            {
                  if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
                  {
                        ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst;
                  }
                  else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
                  {
                        ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst;
                  }

                  /* Set the playout event base address. */
                  if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE )
                        && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) )
                  {
                        /* 127 or 31 events image. */
                        ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ( ( ulWritePtr - 1 ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 )));
                  }
                  else
                  {
                        /* Old 31 events image. */
                        ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ( ( ulWritePtr - 1 ) & 0x1F));
                  }

                  /* EVENT BASE + 4 */
                  /* Playout configuration. */
                  ulAddress += 4;

                  ReadParams.ulReadAddress = ulAddress;
                  mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;

                  /* Read-clear-write the new repeat bit. */
                  usReadData &= 0x7FFF;

                  WriteParams.ulWriteAddress = ulAddress;
                  WriteParams.usWriteData = usReadData;
                  mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
            }
      }

      /* Write the skip to the value of the write pointer to stop buffer playout. */

      /*=======================================================================*/
      /* First set the ignore skip clean bit if required. */      

      if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == FALSE )
            || ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == FALSE ) )
      {
            ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst;

            mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  &ulTempData,
                                                                  ulResult );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;
            
            mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask );
            
            ulTempData &= ( ~ulMask );

            /* Check if the skip need to be clean or not. */
            if ( f_pBufferPlayoutStop->fStopCleanly == FALSE )
                  ulTempData |= 0x1 << ulIgnoreBitOfst;
            
            mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                            pEchoChannel,
                                                            ulAddress,
                                                            ulTempData,
                                                            ulResult );
            if ( ulResult != cOCT6100_ERR_OK )
                  return ulResult;
      }

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

      
      /*=======================================================================*/
      /* Fetch and modify the write pointer. */ 

      ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst;

      mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask );
      
      ulTempData &= ( ~ulMask );
      ulTempData |= ulWritePtr << ulWritePtrBitOfst;
      
      mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                      pEchoChannel,
                                                      ulAddress,
                                                      ulTempData,
                                                      ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      /*=======================================================================*/

      
      /*=======================================================================*/
      /* Fetch and modify the skip pointer. */  

      ulAddress = ulPlayoutBaseAddress + ulSkipPtrBytesOfst;

      mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                            pEchoChannel,
                                                            ulAddress,
                                                            &ulTempData,
                                                            ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      mOCT6100_CREATE_FEATURE_MASK( ulSkipPtrFieldSize, ulSkipPtrBitOfst, &ulMask );
      
      ulTempData &= ( ~ulMask );
      ulTempData |= ulSkipPtr << ulSkipPtrBitOfst;
      
      mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                      pEchoChannel,
                                                      ulAddress,
                                                      ulTempData,
                                                      ulResult );
      if ( ulResult != cOCT6100_ERR_OK )
            return ulResult;
      
      /*=======================================================================*/
      

      /*=======================================================================*/
      /* If in the new buffer playout case, things are in a different order. */     

      if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE )
      {
            if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE )
                  && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) )
            {
                  ulAddress = ulPlayoutBaseAddress + ulHardSkipBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                                        pEchoChannel,
                                                                        ulAddress,
                                                                        &ulTempData,
                                                                        ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
                  
                  mOCT6100_CREATE_FEATURE_MASK( ulHardSkipFieldSize, ulHardSkipBitOfst, &ulMask );
                  
                  ulTempData &= ( ~ulMask );

                  /* Check if the skip need to be clean or not. */
                  if ( f_pBufferPlayoutStop->fStopCleanly == FALSE )
                        ulTempData |= 0x1 << ulHardSkipBitOfst;
                  
                  mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  ulTempData,
                                                                  ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;

                  /* Now is the appropriate time to skip! */
                  ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst;

                  mOCT6100_RETRIEVE_NLP_CONF_DWORD(   f_pApiInstance,
                                                                        pEchoChannel,
                                                                        ulAddress,
                                                                        &ulTempData,
                                                                        ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
                  
                  mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask );

                  ulTempData &= ( ~ulMask );

                  /* Set the skip bit. */
                  ulTempData |= 0x1 << ulIgnoreBitOfst;
                  
                  mOCT6100_SAVE_NLP_CONF_DWORD( f_pApiInstance,
                                                                  pEchoChannel,
                                                                  ulAddress,
                                                                  ulTempData,
                                                                  ulResult );
                  if ( ulResult != cOCT6100_ERR_OK )
                        return ulResult;
            }
      }

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


      /*=======================================================================*/
      /* The API must set the skip bit in all the events that are queued. */

      if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE )
      {
            if ( fCheckStop == TRUE )
            {
                  if ( ulReadPtr != ulWritePtr )
                  {
                        if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
                        {
                              ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst;
                        }
                        else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
                        {
                              ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst;
                        }

                        for ( ulCurrentPtr = ulReadPtr; ulCurrentPtr != ulWritePtr; )
                        {
                              /* Set the playout event base address. */
                              
                              /* 127 or 31 events image. */
                              ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + ( cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ulCurrentPtr );
                              ulCurrentPtr++;
                              ulCurrentPtr &= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 );

                              /* EVENT BASE + 0 playout configuration. */
                              WriteParams.ulWriteAddress = ulAddress;

                              /* Set skip bit + hard-skip bit. */
                              WriteParams.usWriteData = 0x8000;
                              if ( f_pBufferPlayoutStop->fStopCleanly == FALSE )
                                    WriteParams.usWriteData |= 0x4000;
                              mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult );
                              if ( ulResult != cOCT6100_ERR_OK )
                                    return ulResult;
                        }
                  }
            }
      }

      /*=======================================================================*/
      /* If stop immediatly, wait the stop before leaving the function. */

      if ( f_pBufferPlayoutStop->fStopCleanly == FALSE )
      {
            /* Remember that an "hard stop" was used for the next start. */
            if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
                  pEchoChannel->fRinHardStop = TRUE;
            else /* if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */
                  pEchoChannel->fSoutHardStop = TRUE;
      }

      /*=======================================================================*/
      /* Update the channel entry to set the playing flag to FALSE. */

      /* Select the port of interest. */
      if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT )
      {
            /* Check if the global ports active stat must be decremented. */
            if ( pEchoChannel->fRinBufPlaying == TRUE )
            {
                  /* Decrement the number of active buffer playout ports. */
                  pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--;
            }

            pEchoChannel->fRinBufPlaying = FALSE;

            /* Return user information. */
            if ( f_pBufferPlayoutStop->pfNotifyOnPlayoutStop != NULL )
                  *f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = pEchoChannel->fRinBufPlayoutNotifyOnStop;

            /* Make sure no new event is recorded for this channel/port. */
            pEchoChannel->fRinBufPlayoutNotifyOnStop = FALSE;
            if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE )
            {
                  pEchoChannel->ulRinBufSkipPtr = ulSkipPtr;
                  pEchoChannel->ulRinBufWritePtr = ulWritePtr;
            }
            else /* if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) */
                  pEchoChannel->ulRinBufSkipPtr = pEchoChannel->ulRinBufWritePtr;

            /* The repeat flag can now be used. */
            pEchoChannel->fRinBufPlayoutRepeatUsed = FALSE;

            /* For sure, all buffers have now been cleared on the Rin port. */
            pEchoChannel->fRinBufAdded = FALSE;

            /* Clear optimization flag if possible. */
            if ( ( pEchoChannel->fSoutBufPlaying == FALSE )
                  && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == FALSE ) )
            {
                  /* Buffer playout is no more active on this channel. */
                  pEchoChannel->fBufPlayoutActive = FALSE;
            }
      }
      else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */
      {
            /* Check if the global ports active stat must be decremented. */
            if ( pEchoChannel->fSoutBufPlaying == TRUE )
            {
                  /* Decrement the number of active buffer playout ports. */
                  pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--;
            }

            pEchoChannel->fSoutBufPlaying = FALSE;

            /* Return user information. */
            if ( f_pBufferPlayoutStop->pfNotifyOnPlayoutStop != NULL )
                  *f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = pEchoChannel->fSoutBufPlayoutNotifyOnStop;

            /* Make sure no new event is recorded for this channel/port. */
            pEchoChannel->fSoutBufPlayoutNotifyOnStop = FALSE;
            if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE )
            {
                  pEchoChannel->ulSoutBufSkipPtr = ulSkipPtr;
                  pEchoChannel->ulSoutBufWritePtr = ulWritePtr;
            }
            else /* if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) */
                  pEchoChannel->ulSoutBufSkipPtr = pEchoChannel->ulSoutBufWritePtr;

            /* The repeat flag can now be used. */
            pEchoChannel->fSoutBufPlayoutRepeatUsed = FALSE;

            /* For sure, all buffers have now been cleared on the Sout port. */
            pEchoChannel->fSoutBufAdded = FALSE;

            /* Clear optimization flag if possible. */
            if ( ( pEchoChannel->fRinBufPlaying == FALSE )
                  && ( pEchoChannel->fRinBufPlayoutNotifyOnStop == FALSE ) )
            {
                  /* Buffer playout is no more active on this channel. */
                  pEchoChannel->fBufPlayoutActive = FALSE;
            }
      }

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



      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiReserveBufPlayoutListEntry

Description:    Reserves a free entry in the Buffer playout 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_pulBufferIndex        List entry reserved.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiReserveBufPlayoutListEntry
UINT32 Oct6100ApiReserveBufPlayoutListEntry(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        OUT         PUINT32                                         f_pulBufferIndex )
{
      PVOID pBufPlayoutAlloc;
      UINT32      ulResult;

      mOCT6100_GET_BUFFER_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBufPlayoutAlloc )

      ulResult = OctapiLlmAllocAlloc( pBufPlayoutAlloc, f_pulBufferIndex );
      if ( ulResult != cOCT6100_ERR_OK )
      {
            if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT )
                  return cOCT6100_ERR_BUFFER_PLAYOUT_ALL_BUFFERS_OPEN;
            else
                  return cOCT6100_ERR_FATAL_40;
      }

      return cOCT6100_ERR_OK;
}
#endif


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

Function:         Oct6100ApiReleaseBufPlayoutListEntry

Description:    Release an entry from the Buffer playout 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_ulBufferIndex               List entry to be freed.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if !SKIP_Oct6100ApiReleaseBufPlayoutListEntry
UINT32 Oct6100ApiReleaseBufPlayoutListEntry(
                        IN OUT      tPOCT6100_INSTANCE_API              f_pApiInstance,
                        IN          UINT32                                          f_ulBufferIndex )
{
      PVOID pBufPlayoutAlloc;
      UINT32      ulResult;

      mOCT6100_GET_BUFFER_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBufPlayoutAlloc )

      ulResult = OctapiLlmAllocDealloc( pBufPlayoutAlloc, f_ulBufferIndex );
      if ( ulResult != cOCT6100_ERR_OK )
            return cOCT6100_ERR_FATAL_41;

      return cOCT6100_ERR_OK;
}
#endif

Generated by  Doxygen 1.6.0   Back to index