/****************************************************************************/
/*                                                                          */
/*  Name        audio_ffs.c                                                 */
/*                                                                          */
/*  Function    this file contains the  AUDIO ffs function:                 */
/*									                                        */
/*                                                                          */
/*  Version   0.1                                                           */
/*                                                                          */
/*  Date        Modification                                                */
/*  ------------------------------------                                    */
/*  18 May 2001  Create                                                     */
/*                                                                          */
/*  Author   Francois Mazard - Stephanie Gerthoux                           */
/*                                                                          */
/* (C) Copyright 2001 by Texas Instruments Incorporated, All Rights Reserved*/
/****************************************************************************/

#include "rv/rv_defined_swe.h"
#ifdef RVM_AUDIO_MAIN_SWE
  #ifndef _WINDOWS
    #include "config/swconfig.cfg"
    #include "config/sys.cfg"
    #include "config/chipset.cfg"
  #endif

  #include "l1_confg.h"
  #if (MELODY_E1) || (MELODY_E2) || (VOICE_MEMO)
    #include "rvf/rvf_api.h"
    #include "rv/rv_general.h"
    #include "rvm/rvm_gen.h"
    #include "audio/audio_api.h"
    #include "audio/audio_env_i.h"
    #include "audio/audio_ffs_i.h"
    #include "audio/audio_structs_i.h"
    #include "audio/audio_macro_i.h"
    #include "rvf/rvf_target.h"
    #include "audio/audio_const_i.h"
    #include "audio/audio_var_i.h"
    #include "audio/audio_error_hdlr_i.h"
    #include "audio/audio_messages_i.h"

    /* include the usefull L1 header */
    #define BOOL_FLAG
    #define CHAR_FLAG
    #include "l1_types.h"
    #include "l1audio_cust.h"
    #include "l1audio_const.h"
    #include "l1audio_msgty.h"
    #include "l1audio_signa.h"

    #include "ffs/ffs_api.h"


    /********************************************************************************/
    /*                                                                              */
    /*    Function Name:   audio_ffs_manager                                        */
    /*                                                                              */
    /*    Purpose:  This function is called to manage the FFS request from the      */
    /*              audio entity                                                    */
    /*                                                                              */
    /*    Input Parameters:                                                         */
    /*        message from the audio entity                                         */
    /*                                                                              */
    /*    Output Parameters:                                                        */
    /*        None.                                                                 */
    /*                                                                              */
    /*    Note:                                                                     */
    /*        None.                                                                 */
    /*                                                                              */
    /*    Revision History:                                                         */
    /*        None.                                                                 */
    /*                                                                              */
    /********************************************************************************/
    void audio_ffs_manager (T_RV_HDR *p_message)
    {
      UINT8 j, active_task, index_ffs, index_l1, *p_buffer, channel_id;
      T_AUDIO_FFS_SESSION *p_session;
      T_RV_HDR            *p_send_message;
      T_RVF_MB_STATUS     mb_status;
      BOOLEAN             loop_mode;
      #ifndef _WINDOWS
        UINT16              voice_memo_size, *p_scan;
      #else
        UINT16              i;
        UINT8               *p_mem;
      #endif
      UINT16              buffer_size;
      T_FFS_SIZE          size;
      T_RV_RET            status;

      switch (p_message->msg_id)
      {
        case AUDIO_FFS_FLASH_2_RAM_START_REQ:
        {
          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: flash to RAM session_id",
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->session_id, RV_TRACE_LEVEL_DEBUG_LOW);

          /* Find a free channel */
          channel_id = 0;
          while ( (p_audio_gbl_var->audio_ffs_session[channel_id].session_req.valid_channel) &&
                  (channel_id < AUDIO_FFS_MAX_CHANNEL) )
            channel_id++;

          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: open channel",
            channel_id, RV_TRACE_LEVEL_DEBUG_LOW);

          p_session =
            &(p_audio_gbl_var->audio_ffs_session[channel_id]);

          /* fill the request structure corresponding to the session id */
          p_session->session_req.audio_ffs_fd =
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->audio_ffs_fd;
          p_session->session_req.size =
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->initial_size;
          p_session->session_req.loop_mode =
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->loop;
          p_session->session_req.session_id =
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->session_id;

          /************************************************************/
          /* the FFS must download the 2 first buffers to the RAM     */
          /************************************************************/
          for (j=0; j<2; j++)
          {
            /* allocate the first buffer */
            p_session->session_info.buffer[j].size =
            p_session->session_req.size;

            mb_status = rvf_get_buf (p_audio_gbl_var->mb_audio_ffs,
                                     p_session->session_info.buffer[j].size,
                                     (T_RVF_BUFFER **) (&p_session->session_info.buffer[j].p_start_pointer));

            /* If insufficient resources, then report a memory error and abort.               */
            if (mb_status == RVF_RED)
            {
              audio_ffs_error_trace(AUDIO_ENTITY_NO_MEMORY);
            }

            AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: allocate buffer",
                j, RV_TRACE_LEVEL_DEBUG_LOW);

            /* intialize the stop pointer */
            p_session->session_info.buffer[j].p_stop_pointer =
              p_session->session_info.buffer[j].p_start_pointer +
              (p_session->session_info.buffer[j].size);

            /* Fill the buffer j while it isn't full in case of the loop back mode activated */
            loop_mode = TRUE;
            buffer_size = p_session->session_info.buffer[j].size;
            p_buffer = (UINT8 *)p_session->session_info.buffer[j].p_start_pointer;
            while ( (p_buffer < p_session->session_info.buffer[j].p_stop_pointer) &&
                    (loop_mode) )
            {
              loop_mode = p_session->session_req.loop_mode;

              #ifndef _WINDOWS
                size = ffs_read(p_session->session_req.audio_ffs_fd,
                                p_buffer,
                                buffer_size);
              #else
                size = buffer_size;
                p_mem = p_buffer;
                for (i=0; i<size; i++)
                {
                  *p_mem = (UINT8)i;
                  p_mem++;
                }
              #endif

              AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: ffs_read size",
                size, RV_TRACE_LEVEL_DEBUG_LOW);

              buffer_size -= size;
              p_buffer += size;

              if (buffer_size != 0)
              {
                #ifndef _WINDOWS
                  /* reset the FFS pointer */
                  ffs_seek(p_session->session_req.audio_ffs_fd,
                           0,
                            FFS_SEEK_SET);
                #endif
              }
            } /* while */
          } /* for (j=0; j<2; j++) */

          /* initialize the cust_get_pointer state machine */
          p_session->session_info.cust_get_pointer_state = AUDIO_CUST_GET_POINTER_INIT;

          /* inform the L1 to use the buffer 0 */
          p_session->session_info.index_l1 = 0;

          /* inform the FFS downloader to fill the buffer 0 when the L1 doesn't used */
          p_session->session_info.index_ffs = 0;

          p_session->session_req.session_mode =
            AUDIO_FFS_FLASH_2_RAM_SESSION;

          /* a new session is valid now */
          p_session->session_req.valid_channel = TRUE;

          /* Active the downloader if it is not already activated */
          active_task = 0;
          for (j=0; j<AUDIO_FFS_MAX_CHANNEL; j++)
          {
            if ( p_audio_gbl_var->audio_ffs_session[j].session_req.valid_channel )
            {
              active_task++;
            }
          }
          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: active session",
            active_task, RV_TRACE_LEVEL_DEBUG_LOW);
          if (active_task == 1)
          {
            AUDIO_SEND_TRACE("AUDIO FFS MANAGER: start FFS DOWNLOADER", RV_TRACE_LEVEL_DEBUG_LOW);

            /* Active asap the FFS downloader */
            rvf_start_timer(AUDIO_FFS_TIMER, AUDIO_FFS_ACTIVE_NOW, AUDIO_FFS_ONE_SHOT_TIMER);
          }

          /* Send the message to confirm that the first buffer is downloaded */
          /* allocate the message buffer */
          mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                                   sizeof (T_AUDIO_FFS_INIT),
                                   (T_RVF_BUFFER **) (&p_send_message));

          /* If insufficient resources, then report a memory error and abort.               */
          if (mb_status == RVF_RED)
          {
            audio_ffs_error_trace(AUDIO_ENTITY_NO_MEMORY);
          }

          /* fill the header of the message */
          ((T_AUDIO_FFS_INIT*)(p_send_message))->os_hdr.msg_id = AUDIO_FFS_INIT_DONE;

          /* fill the status parameters */
          ((T_AUDIO_FFS_INIT *)(p_send_message))->session_id =
            ((T_AUDIO_FFS_FLASH_2_RAM_START *)p_message)->session_id;
          ((T_AUDIO_FFS_INIT *)(p_send_message))->channel_id =
            channel_id;


          /* send the message to the AUDIO entity */
          rvf_send_msg (p_audio_gbl_var->addrId,
                        p_send_message);
          break;
        }
        case AUDIO_FFS_RAM_2_FLASH_START_REQ:
        {
          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: RAM to flash session_id",
            ((T_AUDIO_FFS_RAM_2_FLASH_START *)p_message)->session_id, RV_TRACE_LEVEL_DEBUG_LOW);

          /* Find a free channel */
          channel_id = 0;
          while ( (p_audio_gbl_var->audio_ffs_session[channel_id].session_req.valid_channel) &&
                  (channel_id < AUDIO_FFS_MAX_CHANNEL) )
            channel_id++;

          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: open channel",
            channel_id, RV_TRACE_LEVEL_DEBUG_LOW);

          p_session =
            &(p_audio_gbl_var->audio_ffs_session[channel_id]);

          /* fill the request structure corresponding to the session id */
          p_session->session_req.size =
            ((T_AUDIO_FFS_RAM_2_FLASH_START *)p_message)->initial_size;
          p_session->session_req.loop_mode = FALSE;
          p_session->session_req.audio_ffs_fd =
            ((T_AUDIO_FFS_RAM_2_FLASH_START *)p_message)->audio_ffs_fd;
          p_session->session_req.session_mode =
            AUDIO_FFS_RAM_2_FLASH_SESSION;
          p_session->session_req.session_id =
            ((T_AUDIO_FFS_RAM_2_FLASH_START *)p_message)->session_id;

          /********************* TO BE COMPLETED **********************/
          /* the FFS must allocate the first buffer to the RAM        */
          /************************************************************/
          for (j=0; j<2; j++)
          {
            mb_status = rvf_get_buf (p_audio_gbl_var->mb_audio_ffs,
                                     p_session->session_req.size,
                                    (T_RVF_BUFFER **) (&p_session->session_info.buffer[j].p_start_pointer));

            /* If insufficient resources, then report a memory error and abort.               */
            if (mb_status == RVF_RED)
            {
              audio_ffs_error_trace(AUDIO_ENTITY_NO_MEMORY);
            }

            AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: allocate buffer",
                j, RV_TRACE_LEVEL_DEBUG_LOW);

            /* Copy the initial size */
            p_session->session_info.buffer[j].size = p_session->session_req.size;
          }

          /* initialize the cust_get_pointer state machine */
          p_session->session_info.cust_get_pointer_state = AUDIO_CUST_GET_POINTER_INIT;

          /* inform the L1 to use the buffer 0 */
          p_session->session_info.index_l1 = 0;

          /* inform the FFS downloader to read the buffer 0 when the L1 doesn't used */
          p_session->session_info.index_ffs = 0;

          /* a new session is valid now */
          p_session->session_req.valid_channel = TRUE;

          /* Active the downloader if it is not already activated */
          active_task = 0;
          for (j=0; j<AUDIO_FFS_MAX_CHANNEL; j++)
          {
            if ( p_audio_gbl_var->audio_ffs_session[j].session_req.valid_channel)
            {
              active_task++;
            }
          }
          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: active session",
            active_task, RV_TRACE_LEVEL_DEBUG_LOW);

          if (active_task == 1)
          {
            AUDIO_SEND_TRACE("AUDIO FFS MANAGER: start FFS DOWNLOADER", RV_TRACE_LEVEL_DEBUG_LOW);

            /* Active asap the FFS downloader */
            rvf_start_timer(AUDIO_FFS_TIMER, AUDIO_FFS_ACTIVE_NOW, AUDIO_FFS_ONE_SHOT_TIMER);
          }
          /* Send the message to confirm that the first buffer is allocated */
          /* allocate the message buffer */
          mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                                   sizeof (T_AUDIO_FFS_INIT),
                                   (T_RVF_BUFFER **) (&p_send_message));

          /* If insufficient resources, then report a memory error and abort.               */
          if (mb_status == RVF_RED)
          {
            audio_ffs_error_trace(AUDIO_ENTITY_NO_MEMORY);
          }

          /* fill the header of the message */
          ((T_AUDIO_FFS_INIT*)(p_send_message))->os_hdr.msg_id = AUDIO_FFS_INIT_DONE;

          /* fill the status parameters */
          ((T_AUDIO_FFS_INIT *)(p_send_message))->session_id =
            ((T_AUDIO_FFS_RAM_2_FLASH_START *)p_message)->session_id;
          ((T_AUDIO_FFS_INIT *)(p_send_message))->channel_id =
            channel_id;

          /* send the message to the AUDIO entity */
          rvf_send_msg (p_audio_gbl_var->addrId,
                        p_send_message);

          break;
        }

        case AUDIO_FFS_STOP_REQ:
        {
          /* Find a channel corresponding to this session */
          channel_id = 0;
          while ( (p_audio_gbl_var->audio_ffs_session[channel_id].session_req.session_id
                    != ((T_AUDIO_FFS_STOP_REQ *)p_message)->session_id) &&
                  (channel_id < AUDIO_FFS_MAX_CHANNEL) )
            channel_id++;

          p_session = &(p_audio_gbl_var->audio_ffs_session[channel_id]);

          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: stop session_id",
            ((T_AUDIO_FFS_STOP_REQ *)p_message)->session_id, RV_TRACE_LEVEL_DEBUG_LOW);
          AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: close channel",
            channel_id, RV_TRACE_LEVEL_DEBUG_LOW);

          /* the task is stopped */
          p_session->session_req.valid_channel = FALSE;

          /* the stop process depends on the session_mode and sometimes the session_id */
          #if (VOICE_MEMO)
            if ( (p_session->session_req.session_mode == AUDIO_FFS_RAM_2_FLASH_SESSION) &&
                 (((T_AUDIO_FFS_STOP_REQ *)p_message)->session_id == AUDIO_FFS_SESSION_VM_RECORD) )
            {
              index_l1 = p_session->session_info.index_l1;
              index_ffs = p_session->session_info.index_ffs;

              if (index_ffs != index_l1)
              /* There's two buffers to save: one full (index_ffs) and one not full (index_l1) */
              {
                AUDIO_SEND_TRACE("AUDIO FFS MANAGER: end of VM record session with index_l1<>index_ffs", RV_TRACE_LEVEL_DEBUG_LOW);

                #ifndef _WINDOWS
                  /* save the full buffer */
                  if ((ffs_write (p_session->session_req.audio_ffs_fd,
                                  p_session->session_info.buffer[index_ffs].p_start_pointer,
                                  p_session->session_req.size)) < EFFS_OK)
                  {
                    audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_SAVED);
                  }

                  /* save a part of the buffer pointed by the L1 */
                  voice_memo_size = 2;
                  p_scan = (UINT16 *)(p_session->session_info.buffer[index_l1].p_start_pointer);
                  while ( (*p_scan++) != SC_VM_END_MASK )
                  {
                    voice_memo_size += 2;
                  }

                  if ((ffs_write  (p_session->session_req.audio_ffs_fd,
                                   p_session->session_info.buffer[index_l1].p_start_pointer,
                                   voice_memo_size)) < EFFS_OK)
                  {
                    audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_SAVED);
                  }
                #endif
              }
              else
              /* 1 buffer (not full) needs to be saved */
              {
                AUDIO_SEND_TRACE("AUDIO FFS MANAGER: end of VM record session with index_l1==index_ffs", RV_TRACE_LEVEL_DEBUG_LOW);
                #ifndef _WINDOWS
                  voice_memo_size = 2;
                  p_scan = (UINT16*)(p_session->session_info.buffer[index_l1].p_start_pointer);
                  while ( (*p_scan++) != SC_VM_END_MASK )
                  {
                    voice_memo_size += 2;
                  }

                  if ((ffs_write (p_session->session_req.audio_ffs_fd,
                                  p_session->session_info.buffer[index_l1].p_start_pointer,
                                  voice_memo_size)) < EFFS_OK)
                  {
                    audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_SAVED);
                  }
                #endif
              } /* index_ffs != index_l1 */
            }
          #endif /* VOICE_MEMO */
          /* deallocate the buffers */
          for (j=0; j<AUDIO_MAX_FFS_BUFFER_PER_SESSION; j++)
          {
            status = rvf_free_buf ( (T_RVF_BUFFER *)(p_session->session_info.buffer[j].p_start_pointer) );
            if (status != RVF_GREEN)
            {
              AUDIO_SEND_TRACE(" wrong buffer deallocated ",
                               RV_TRACE_LEVEL_ERROR);
            }
            AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: deallocate buffer",
                j, RV_TRACE_LEVEL_DEBUG_LOW);
          }

          /* Close the FFS file */
          #ifndef _WINDOWS
            if ( ffs_close(p_session->session_req.audio_ffs_fd) != EFFS_OK )
            {
              audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
            }
          #endif

          /* Send the message to confirm that the session is stopped */
          /* allocate the message buffer */
          mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                                   sizeof (T_AUDIO_FFS_STOP_CON),
                                   (T_RVF_BUFFER **)(&p_send_message));

          /* If insufficient resources, then report a memory error and abort.               */
          if (mb_status == RVF_RED)
          {
            audio_ffs_error_trace(AUDIO_ENTITY_NO_MEMORY);
          }

          /* fill the header of the message */
          ((T_AUDIO_FFS_STOP_CON*)(p_send_message))->os_hdr.msg_id = AUDIO_FFS_STOP_CON;

          /* fill the status parameters */
          ((T_AUDIO_FFS_STOP_CON*)(p_send_message))->session_id =
            ((T_AUDIO_FFS_STOP_REQ *)p_message)->session_id;

          /* send the message to the AUDIO entity */
          rvf_send_msg (p_audio_gbl_var->addrId,
                        p_send_message);
          break;
        }
      } /* switch (p_message) */
    }

    /********************************************************************************/
    /*                                                                              */
    /*    Function Name:   audio_ffs_downloader                                     */
    /*                                                                              */
    /*    Purpose:  This function is called to download the melody, voice memo data */
    /*              between the RAM and the FLASH.                                  */
    /*                                                                              */
    /*    Input Parameters:                                                         */
    /*        None.                                                                 */
    /*                                                                              */
    /*    Output Parameters:                                                        */
    /*        None.                                                                 */
    /*                                                                              */
    /*    Note:                                                                     */
    /*        None.                                                                 */
    /*                                                                              */
    /*    Revision History:                                                         */
    /*        None.                                                                 */
    /*                                                                              */
    /********************************************************************************/
    void audio_ffs_downloader(void)
    {
      UINT8               i, index_ffs, index_l1, *p_buffer;
      T_AUDIO_FFS_SESSION *p_session;
      UINT16              buffer_size;
      T_FFS_SIZE          size = 0;
      BOOLEAN             loop_mode, active_session;

      /* Scan all session in order to know which is valid */
      active_session = FALSE;
      for (i=0; i<AUDIO_FFS_MAX_CHANNEL; i++)
      {
       p_session = &(p_audio_gbl_var->audio_ffs_session[i]);
       if (p_session->session_req.valid_channel)
       {
          /* a session is valid */
          active_session = TRUE;

          index_l1 = p_session->session_info.index_l1;
          index_ffs = p_session->session_info.index_ffs;

          if (index_l1 != index_ffs)
          /* It's time to download a new buffer for the L1 */
          {
            AUDIO_SEND_TRACE_PARAM("AUDIO FFS DOWNLOADER: index_l1",
              index_l1, RV_TRACE_LEVEL_DEBUG_LOW);
            AUDIO_SEND_TRACE_PARAM("AUDIO FFS DOWNLOADER: index_ffs",
              index_ffs, RV_TRACE_LEVEL_DEBUG_LOW);

            switch (p_session->session_req.session_mode)
            {
              case AUDIO_FFS_FLASH_2_RAM_SESSION:
              {
                AUDIO_SEND_TRACE("AUDIO FFS DOWNLOADER: FLASH to RAM", RV_TRACE_LEVEL_DEBUG_LOW);

                /* Fill the buffer 0 while it isn't full in case of the loop back mode activated */
                loop_mode = TRUE;
                buffer_size = p_session->session_info.buffer[index_ffs].size;
                p_buffer = (UINT8 *)p_session->session_info.buffer[index_ffs].p_start_pointer;
                while ( (p_buffer < p_session->session_info.buffer[index_ffs].p_stop_pointer) &&
                        (loop_mode) )
                {
                  loop_mode = p_session->session_req.loop_mode;

                  #ifndef _WINDOWS
                    size = ffs_read(p_session->session_req.audio_ffs_fd,
                                    p_buffer,
                                    buffer_size);
                  #endif

                  AUDIO_SEND_TRACE_PARAM("AUDIO FFS MANAGER: ffs_read size",
                    size, RV_TRACE_LEVEL_DEBUG_LOW);

                  buffer_size -= size;
                  p_buffer += size;

                  if (buffer_size != 0)
                  {
                    #ifndef _WINDOWS
                      /* reset the FFS pointer */
                      ffs_seek(p_session->session_req.audio_ffs_fd,
                               0,
                               FFS_SEEK_SET);
                    #endif
                  }
                } /* while */
                break;
              }

              case AUDIO_FFS_RAM_2_FLASH_SESSION:
              {
                AUDIO_SEND_TRACE("AUDIO FFS DOWNLOADER: RAM to FLASH", RV_TRACE_LEVEL_DEBUG_LOW);

                /* save the full buffer */
                #ifndef _WINDOWS
                  if ((ffs_write  (p_session->session_req.audio_ffs_fd,
                                   p_session->session_info.buffer[index_ffs].p_start_pointer,
                                   p_session->session_req.size)) < EFFS_OK)
                  {
                    audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_SAVED);
                  }
                #endif
                break;
              }
            } /* switch (p_session->session_req.session_mode) */

            /* update the ffs buffer index */
            p_session->session_info.index_ffs++;
            if (p_session->session_info.index_ffs == AUDIO_MAX_FFS_BUFFER_PER_SESSION)
            {
              p_session->session_info.index_ffs = 0;
            }
          } /* (p_session->session_info.index_l1 != p_session->session_info.index_l1) */
        } /* valid session */
      } /* for (i=0; i<AUDIO_FFS_MAX_CHANNEL; i++) */

      /* Activate or not the Timer the next time */
      if (active_session)
      {
        rvf_start_timer(AUDIO_FFS_TIMER, AUDIO_FFS_TIME_OUT, AUDIO_FFS_ONE_SHOT_TIMER);
      }
      else
      {
        AUDIO_SEND_TRACE("AUDIO FFS DOWNLOADER: stop", RV_TRACE_LEVEL_DEBUG_LOW);
        /* Stop asap the FFS downloader */
        rvf_stop_timer(AUDIO_FFS_TIMER);
      }
    }
  #endif /* MELODY_E1 || MELODY_E2 || VOICE_MEMO */

#if (L1_VOICE_MEMO_AMR)
  T_AUDIO_RET audio_convert_to_mms(UINT8 *p_buffer, UINT16 *buffer_size, UINT8 *previous_type, UINT8 *size_left)
  {
    UINT8 rxtx_type, frame_header, data_size;
    UINT8 frame_type, quality;
    UINT8 *ptr_final, *ptr_mms;

    ptr_mms = p_buffer;
    ptr_final = ptr_mms + *buffer_size;

    /* sample is shared among the 2 buffers */
    if (*size_left > 0)
    {
      UINT8 i;

      switch (*previous_type)
      {
        case AUDIO_VM_AMR_RXTX_SID_FIRST:
          /* set data bits to 0 */
          for (i = 0; i < *size_left; i++)
            *(ptr_mms + i) = 0;
          /* set Mode Indication */
          *(ptr_mms + *size_left - 1) = AUDIO_MMS_MODE_INDICATION;
        break;
        case AUDIO_VM_AMR_RXTX_SID_UPDATE:
        //case AUDIO_VM_AMR_RXTX_SID_BAD:
          *(ptr_mms + *size_left - 1) |= AUDIO_MMS_STI_BIT | AUDIO_MMS_MODE_INDICATION;
        break;
      }
      ptr_mms += *size_left;
    }
    *size_left = 0;

    while (ptr_mms < ptr_final)
    {
      /* read header */
      frame_header = *ptr_mms;

      /* if end_mask, stop */
      if (frame_header == SC_VM_AMR_END_MASK)
      {
        *buffer_size = (ptr_mms - p_buffer);
        return AUDIO_OK;
      }

      /* reset header */
      *ptr_mms = 0;

      rxtx_type  = (frame_header & SC_RX_TX_TYPE_MASK);
      *previous_type = rxtx_type;
      switch (rxtx_type)
      {
        case AUDIO_VM_AMR_RXTX_SPEECH_GOOD:
        //case AUDIO_VM_AMR_RXTX_SPEECH_BAD:
        {
          /* FT + data_size */
          frame_type = frame_header & SC_CHAN_TYPE_MASK;
          switch (frame_type)
          {
            case AUDIO_VM_AMR_SPEECH_475:
              data_size = AUDIO_VM_AMR_SPEECH_475_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_515:
              data_size = AUDIO_VM_AMR_SPEECH_515_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_59:
              data_size = AUDIO_VM_AMR_SPEECH_590_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_67:
              data_size = AUDIO_VM_AMR_SPEECH_670_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_74:
              data_size = AUDIO_VM_AMR_SPEECH_740_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_795:
              data_size = AUDIO_VM_AMR_SPEECH_795_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_102:
              data_size = AUDIO_VM_AMR_SPEECH_102_DATA_SIZE;
            break;
            case AUDIO_VM_AMR_SPEECH_122:
              data_size = AUDIO_VM_AMR_SPEECH_122_DATA_SIZE;
            break;
          }
          /* Q */
          //if (rxtx_type == AUDIO_VM_AMR_RXTX_SPEECH_GOOD)
            quality = AUDIO_MMS_GOOD_QUALITY;
          //else
          //  quality = AUDIO_MMS_BAD_QUALITY;
        }
        break;
        case AUDIO_VM_AMR_RXTX_SID_FIRST:
        case AUDIO_VM_AMR_RXTX_SID_UPDATE:
        //case AUDIO_VM_AMR_RXTX_SID_BAD:
        {
          /* FT, data_size, Q */
          frame_type = AUDIO_MMS_SID_FRAME_TYPE;
          data_size = AUDIO_VM_AMR_SID_DATA_SIZE;
          //if ((rxtx_type == AUDIO_VM_AMR_RXTX_SID_FIRST)||
          //    (rxtx_type == AUDIO_VM_AMR_RXTX_SID_UPDATE))
          //{
            quality = AUDIO_MMS_GOOD_QUALITY;
          //}
          //else
          //  quality = AUDIO_MMS_BAD_QUALITY;

          /* data, STI, Mode indication */
          if (rxtx_type == AUDIO_VM_AMR_RXTX_SID_FIRST)
          {
            UINT8 data, i;

            /* number of bytes to set to 0 */
            data = ((ptr_final - ptr_mms) >= (data_size + 1)) ? (data_size) : (ptr_final - ptr_mms - 1);

            /* set data bits to 0 */
            for (i = 0; i < data; i++)
              *(ptr_mms + 1 + i) = 0;

            /* set Mode indication */
            if ((ptr_final - ptr_mms) >= (data_size + 1))
              *(ptr_mms + data_size) = AUDIO_MMS_MODE_INDICATION;

          }
          /* SID_UPDATE */
          else
          {
            /* set STI bit to 1 + Mode indication */
            if ((ptr_final - ptr_mms) >= (data_size + 1))
              *(ptr_mms + data_size) |= AUDIO_MMS_STI_BIT | AUDIO_MMS_MODE_INDICATION;
          }
        }
        break;
        case AUDIO_VM_AMR_RXTX_NO_DATA:
          frame_type = AUDIO_MMS_NO_DATA_FRAME_TYPE;
          data_size = AUDIO_VM_AMR_NO_DATA_DATA_SIZE;
          quality = AUDIO_MMS_GOOD_QUALITY;
        break;
        default:
        {
          AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: convert to MMS, header not recognized", frame_header, RV_TRACE_LEVEL_DEBUG_LOW);
          return AUDIO_ERROR;
        }
      }
      /* write header */
      *(ptr_mms)++ |= (frame_type << AUDIO_MMS_FRAME_TYPE_SHIFT) | (quality << AUDIO_MMS_QUALITY_SHIFT);

      /* write data, check we are not at the end of the buffer */
      if ((ptr_final - ptr_mms) < data_size)
      {
        *size_left = data_size - (ptr_final - ptr_mms);
        data_size = ptr_final - ptr_mms;
      }
      ptr_mms += data_size;
    }
    *buffer_size = (ptr_final - p_buffer);
    return AUDIO_OK;
  }

  T_AUDIO_RET audio_convert_from_mms(UINT8 *p_buffer, UINT16 buffer_size, UINT8 *previous_type, UINT8 *size_left)
  {
    UINT8 frame_header, data_size;
    UINT8 frame_type, quality;
    UINT8 *ptr_final, *ptr_mms;

    ptr_mms = p_buffer;
    ptr_final = ptr_mms + buffer_size;

    /* a sample is split between 2 RAM buffers */
    if (*size_left > 0)
    {
      /* if SID sample, remove STI and mode indication */
      if (*previous_type == AUDIO_MMS_SID_FRAME_TYPE)
      {
        *(ptr_mms + *size_left - 1) &= (~(AUDIO_MMS_STI_BIT | AUDIO_MMS_MODE_INDICATION));
      }
      ptr_mms += *size_left;
      *size_left = 0;
    }

    while (ptr_mms < ptr_final)
    {
      /* read header */
      frame_header = *ptr_mms;

      /* reset header */
      *ptr_mms = 0;

      /* FT and Q */
      frame_type = (frame_header & AUDIO_MMS_FRAME_TYPE_MASK) >> AUDIO_MMS_FRAME_TYPE_SHIFT;
      quality    = (frame_header & AUDIO_MMS_QUALITY_MASK) >> AUDIO_MMS_QUALITY_SHIFT;
      *previous_type = frame_type;

      /* Identify sample */
      if (frame_type < AUDIO_MMS_SID_FRAME_TYPE)
      {
        /* speech good or bad */
        *ptr_mms |= frame_type;
        if (quality == AUDIO_MMS_GOOD_QUALITY)
          *ptr_mms |= AUDIO_VM_AMR_RXTX_SPEECH_GOOD;
        else
          *ptr_mms |= AUDIO_VM_AMR_RXTX_SPEECH_BAD;

        switch (frame_type)
        {
          case AUDIO_VM_AMR_SPEECH_475:
            data_size = AUDIO_VM_AMR_SPEECH_475_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_515:
            data_size = AUDIO_VM_AMR_SPEECH_515_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_59:
            data_size = AUDIO_VM_AMR_SPEECH_590_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_67:
            data_size = AUDIO_VM_AMR_SPEECH_670_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_74:
            data_size = AUDIO_VM_AMR_SPEECH_740_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_795:
            data_size = AUDIO_VM_AMR_SPEECH_795_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_102:
            data_size = AUDIO_VM_AMR_SPEECH_102_DATA_SIZE;
          break;
          case AUDIO_VM_AMR_SPEECH_122:
            data_size = AUDIO_VM_AMR_SPEECH_122_DATA_SIZE;
          break;
        }
      }
      else if (frame_type == AUDIO_MMS_SID_FRAME_TYPE)
      {
        data_size = AUDIO_VM_AMR_SID_DATA_SIZE;
        /* SID_BAD */
        if (quality == AUDIO_MMS_BAD_QUALITY)
          *ptr_mms |= AUDIO_VM_AMR_RXTX_SID_BAD;
        /* SID_FIRST or SID_UPDATE */
        else
        {
          if (*previous_type == AUDIO_MMS_NO_DATA_FRAME_TYPE)
            *ptr_mms |= AUDIO_VM_AMR_RXTX_SID_UPDATE;
          else
            *ptr_mms |= AUDIO_VM_AMR_RXTX_SID_FIRST;
          /* try to remove STI + mode indication if sample not split between 2 buffers */
          if ((ptr_final - ptr_mms) >= (data_size + 1))
            *(ptr_mms + data_size) &= (~(AUDIO_MMS_STI_BIT | AUDIO_MMS_MODE_INDICATION));
        }
      }
      else if (frame_type == AUDIO_MMS_NO_DATA_FRAME_TYPE)
      {
        data_size = AUDIO_VM_AMR_NO_DATA_DATA_SIZE;
        *ptr_mms |= AUDIO_VM_AMR_RXTX_NO_DATA;
      }
      else
      {
        AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: convert from MMS, header not recognized", frame_header, RV_TRACE_LEVEL_DEBUG_LOW);
        return AUDIO_ERROR;
      }

      /* pass header */
      ptr_mms++;

      /* write data, check we are not at the end of the buffer */
      if ((ptr_final - ptr_mms) < data_size)
      {
        *size_left = data_size - (ptr_final - ptr_mms);
        data_size = ptr_final - ptr_mms;
      }
      ptr_mms += data_size;
    }
    return AUDIO_OK;
  }
#endif

#if (AUDIO_RAM_MANAGER)
  /* try to copy "size" bytes from audio_ram_fd to dest_buffer, returns bytes copied (0 to size) */
  INT16 ram_read(T_AUDIO_MEM_SESSION *p_session, UINT8 *dest_buffer, UINT16 size)
  {
    UINT16 i;

    /* check how many bytes there are in audio_ram_fd */
    if (size > p_session->session_req.audio_ram_size)
      size = p_session->session_req.audio_ram_size;
    /* copy byte by byte */
    for (i = 0; i < size; i++)
      *dest_buffer++ = *(p_session->session_req.audio_ram_fd)++;
    /* update audio_ram_fd size */
    p_session->session_req.audio_ram_size -= size;
    return size;
  }

  /* copy "size" bytes from src_buffer to audio_ram_fd, does not check size */
  INT16 ram_write(T_AUDIO_MEM_SESSION *p_session, UINT8 *src_buffer, UINT16 size)
  {
    UINT16 i;

    /* copy byte by byte */
    for (i = 0; i < size; i++)
      *(p_session->session_req.audio_ram_fd)++ = *src_buffer++;
    return size;
  }
#endif

#if (AUDIO_MEM_MANAGER)
  void audio_mem_send_status(T_AUDIO_RET status, UINT8 channel_id, UINT8 status_type,
                             T_RV_RETURN return_path)
  {
    /* status_type START or STOP, status AUDIO_OK or AUDIO_ERROR */
    T_AUDIO_MEM_STATUS *p_send_message;
    T_RVF_MB_STATUS mb_status = RVF_RED;

    while (mb_status == RVF_RED)
    {
      /* allocate the message buffer */
      mb_status = rvf_get_buf (p_audio_gbl_var->mb_external,
                               sizeof (T_AUDIO_MEM_STATUS),
                               (T_RVF_BUFFER **) (&p_send_message));

      /* If insufficient resources, then report a memory error and abort.               */
      /* and wait until more ressource is given */
      if (mb_status == RVF_RED)
      {
        audio_mem_error_trace(AUDIO_ENTITY_NO_MEMORY);
        rvf_delay(RVF_MS_TO_TICKS(1000));
      }
    }

    /*fill the header of the message */
    p_send_message->os_hdr.msg_id = AUDIO_MEM_STATUS_MSG;

    /* fill the status parameters */
    p_send_message->status      = status;
    p_send_message->channel_id  = channel_id;
    p_send_message->status_type = status_type;

    /* send message or call callback */
    if (return_path.callback_func == NULL)
      rvf_send_msg (return_path.addr_id, p_send_message);
    else
    {
      (*return_path.callback_func)((void *)(p_send_message));
       rvf_free_buf((T_RVF_BUFFER *)p_send_message);
    }
  }

  void audio_mem_send_record_status(UINT8 channel_id, UINT32 recorded_size, T_RV_RETURN return_path)
  {
    /* status_type START or STOP, status AUDIO_OK or AUDIO_ERROR */
    T_AUDIO_MEM_STATUS *p_send_message;
    T_RVF_MB_STATUS mb_status = RVF_RED;

    while (mb_status == RVF_RED)
    {
      /* allocate the message buffer */
      mb_status = rvf_get_buf (p_audio_gbl_var->mb_external,
                               sizeof (T_AUDIO_MEM_STATUS),
                               (T_RVF_BUFFER **) (&p_send_message));

      /* If insufficient resources, then report a memory error and abort.               */
      /* and wait until more ressource is given */
      if (mb_status == RVF_RED)
      {
        audio_mem_error_trace(AUDIO_ENTITY_NO_MEMORY);
        rvf_delay(RVF_MS_TO_TICKS(1000));
      }
    }

    /*fill the header of the message */
    p_send_message->os_hdr.msg_id = AUDIO_MEM_STATUS_MSG;

    /* fill the status parameters */
    p_send_message->status      = AUDIO_OK;
    p_send_message->channel_id  = channel_id;
    p_send_message->status_type = AUDIO_STOP_STATUS;
    p_send_message->recorded_size = recorded_size;

    /* send message or call callback */
    if (return_path.callback_func == NULL)
      rvf_send_msg (return_path.addr_id, p_send_message);
    else
    {
      (*return_path.callback_func)((void *)(p_send_message));
	  rvf_free_buf((T_RVF_BUFFER *)p_send_message);
    }
  }

  void audio_mem_manager (T_RV_HDR *p_message)
  {
    UINT8 channel_id, session_id, state;
    UINT8 mem_channel_id;
    T_RV_RETURN return_path;
    T_AUDIO_MEM_SESSION *p_session;

    /* get channel_id from messages */
    switch (p_message->msg_id)
    {
      case AUDIO_MEM_START_REQ:
        channel_id = ((T_AUDIO_MEM_START *)p_message)->channel_id;
        session_id = ((T_AUDIO_MEM_START *)p_message)->session_id;
      break;
      case AUDIO_MEM_STOP_REQ:
        channel_id = ((T_AUDIO_MEM_STOP *)p_message)->channel_id;
      break;
      case AUDIO_DRIVER_NOTIFICATION_MSG:
        channel_id = ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id;
      break;
      case AUDIO_DRIVER_LAST_NOTIFICATION_MSG:
        channel_id = ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id;
      break;
      case AUDIO_DRIVER_STATUS_MSG:
        channel_id = ((T_AUDIO_DRIVER_STATUS *)p_message)->channel_id;
      break;
    }

    /* Init mem_channel_id to browse all mem channels and find channel_id */
    /* state will stay IDLE if no mem channel is found */
    mem_channel_id = 0;
    state = AUDIO_MEM_IDLE;

    /* look for an ACTIVE session, which channel_id matches the one from the message */
    while ( (mem_channel_id < AUDIO_MEM_MAX_CHANNEL)&&
            ((p_audio_gbl_var->audio_mem_session[mem_channel_id].session_info.state == AUDIO_MEM_IDLE)||
             (p_audio_gbl_var->audio_mem_session[mem_channel_id].session_req.channel_id != channel_id)) )
    {
      mem_channel_id++;
    }

    /* if mem_channel_id < MAX_CHANNEL, we found an active channel so we can derive state */
    if (mem_channel_id < AUDIO_MEM_MAX_CHANNEL)
    {
      p_session = &(p_audio_gbl_var->audio_mem_session[mem_channel_id]);
      state = p_session->session_info.state;
    }

    switch (state)
    {
      case AUDIO_MEM_IDLE:
      {
        /* requester return_path (currently is Riviera Audio) */
        return_path.callback_func = NULL;
        return_path.addr_id       = p_audio_gbl_var->addrId;

        switch (p_message->msg_id)
        {
          case AUDIO_MEM_START_REQ:
          {
            /* find free MEM channel i.e. state = AUDIO_MEM_IDLE */
            mem_channel_id = 0;
            while ( (p_audio_gbl_var->audio_mem_session[mem_channel_id].session_info.state != AUDIO_MEM_IDLE) &&
                    (mem_channel_id < AUDIO_MEM_MAX_CHANNEL) )
              mem_channel_id++;

            if (mem_channel_id == AUDIO_MEM_MAX_CHANNEL)
            {
              AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: no memory channel available", RV_TRACE_LEVEL_DEBUG_LOW);
              audio_mem_send_status(AUDIO_ERROR, channel_id, AUDIO_START_STATUS, return_path);
              return;
            }

            /* get MEM session */
            p_session = &(p_audio_gbl_var->audio_mem_session[mem_channel_id]);

            /* fill parameters */
            p_session->session_req.channel_id = channel_id;
            p_session->session_req.session_id = session_id;
          #if (AUDIO_NEW_FFS_MANAGER)
            p_session->session_req.audio_ffs_fd =
              ((T_AUDIO_MEM_START *)p_message)->audio_ffs_fd;
          #endif
          #if (AUDIO_RAM_MANAGER)
            p_session->session_req.audio_ram_fd =
              ((T_AUDIO_MEM_START *)p_message)->audio_ram_fd;
            p_session->session_req.audio_ram_size =
              ((T_AUDIO_MEM_START *)p_message)->audio_ram_size;
          #endif
            p_session->session_req.size =
              ((T_AUDIO_MEM_START *)p_message)->size;// temporary RAM buffer size

            /* parameters for notification handling */
            p_session->session_info.size_left = 0;
            p_session->session_info.previous_type = AUDIO_VM_AMR_RXTX_SPEECH_GOOD;
            p_session->session_info.stop_req_allowed = TRUE;

            /* initialization phase for play sessions */
            switch (session_id)
            {
              case AUDIO_VM_AMR_PLAY_SESSION_ID:
              {
                UINT8 *play_buffer;// temporary RAM buffer to fill
                INT16 size_read;

                /* fill all buffers in advance */
                while (audio_driver_get_play_buffer(channel_id, &play_buffer) == AUDIO_OK)
                {
                #if (AUDIO_NEW_FFS_MANAGER)
                  /* write from FLASH to RAM buffer */
                  if (p_session->session_req.audio_ffs_fd != NULL)
                  {
                    /* copy from Flash "size" bytes into play_buffer */
                    size_read = ffs_read(p_session->session_req.audio_ffs_fd,
                                         play_buffer,
                                         p_session->session_req.size);

                    /* wrong read */
                    if (size_read < EFFS_OK)
                    {
                      if ( ffs_close(p_session->session_req.audio_ffs_fd) != EFFS_OK )
                        audio_mem_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
                      AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER INIT: FFS PLAY READ failed", RV_TRACE_LEVEL_DEBUG_LOW);
                      audio_mem_send_status(AUDIO_ERROR, channel_id, AUDIO_START_STATUS, return_path);
                      return;
                    }
                  }
                #endif
                #if (AUDIO_RAM_MANAGER)
                  /* write from RAM to RAM buffer */
                  if (p_session->session_req.audio_ram_fd != NULL)
                  {
                    /* copy from RAM "size" bytes into play_buffer */
                    size_read = ram_read(p_session, play_buffer, p_session->session_req.size);
                  }
                #endif

                  /* convert to MMS */
                  if (audio_convert_from_mms(play_buffer, size_read,
                                         &(p_session->session_info.previous_type),
                                         &(p_session->session_info.size_left)) != AUDIO_OK)
                  {
                    AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER INIT: wrong MMS format", RV_TRACE_LEVEL_DEBUG_LOW);
                    size_read = 0;// will fill buffer with END_MASK and stop task
                  }

                  /* last buffer already, put END_MASK */
                  if ( ((UINT16)size_read) < p_session->session_req.size )
                  {
                    UINT16 i;

                    if (p_session->session_info.size_left != 0)
                      AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY DOWNLOADER: MMS PLAY file incomplete",
                        p_session->session_info.size_left, RV_TRACE_LEVEL_DEBUG_LOW);
                    for (i = size_read; i < p_session->session_req.size; i++)
                      *(play_buffer + i) = SC_VM_AMR_END_MASK;
                  }

                  AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY DOWNLOADER: size read", size_read, RV_TRACE_LEVEL_DEBUG_LOW);

                  audio_driver_play_buffer(channel_id, play_buffer);
                }

              }// case AUDIO_VM_AMR_PLAY_SESSION_ID
              break;
            }// switch (session_id)

            audio_driver_start_session(channel_id, return_path);

            p_session->session_info.state = AUDIO_MEM_WAIT_NOTIFICATION_OR_STOP;
          }
          break; //case AUDIO_MEM_START_REQ:
          case AUDIO_MEM_STOP_REQ:
            audio_mem_error_trace(AUDIO_ERROR_STOP_EVENT);
          break;
        }
      } // case AUDIO_MEM_IDLE:
      break;
      case AUDIO_MEM_WAIT_NOTIFICATION_OR_STOP:
      {
        /* requester return_path (currently is Riviera Audio) */
        return_path.callback_func = NULL;
        return_path.addr_id       = p_audio_gbl_var->addrId;

        switch (p_message->msg_id)
        {
          case AUDIO_DRIVER_NOTIFICATION_MSG:
          {
            switch (p_session->session_req.session_id)
            {
              case AUDIO_VM_AMR_RECORD_SESSION_ID:
              {
                UINT16 record_buffer_size;

                /* default is session_req.size but can be less if we find END_MASK */
                record_buffer_size = p_session->session_req.size;

                /* convert to MMS, update record_buffer_size if END_MASK is found */
                audio_convert_to_mms((UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                                     &record_buffer_size,
                                     &(p_session->session_info.previous_type),
                                     &(p_session->session_info.size_left));

              #if (AUDIO_NEW_FFS_MANAGER)
                if (p_session->session_req.audio_ffs_fd != NULL)
                {
                  if ((ffs_write (p_session->session_req.audio_ffs_fd,
                                  (UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                                  record_buffer_size)) < EFFS_OK)
                  {
                    AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: FFS RECORD WRITE FAILED", RV_TRACE_LEVEL_DEBUG_LOW);
                  }
                }
              #endif
              #if (AUDIO_RAM_MANAGER)
                if (p_session->session_req.audio_ram_fd != NULL)
                {
                  ram_write (p_session,
                             (UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                             record_buffer_size);
                }
              #endif

                AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: RAM to MEMORY", record_buffer_size, RV_TRACE_LEVEL_DEBUG_LOW);//DEBUG
              }
              break;
              case AUDIO_VM_AMR_PLAY_SESSION_ID:
              {
                UINT8 *play_buffer;
                INT16  size_read;

                /* try to get a buffer */
                if (audio_driver_get_play_buffer(channel_id, &play_buffer) == AUDIO_OK)
                {
                #if (AUDIO_NEW_FFS_MANAGER)
                  if (p_session->session_req.audio_ffs_fd != NULL)
                  {
                    size_read = ffs_read(p_session->session_req.audio_ffs_fd,
                                         play_buffer,
                                         p_session->session_req.size);
                    /* wrong read */
                    if (size_read < EFFS_OK)
                    {
                      AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: FFS PLAY READ FAILED", RV_TRACE_LEVEL_DEBUG_LOW);
                      size_read = 0;// will put END_MASK in whole buffer so stops play
                    }
                  }
                #endif
                #if (AUDIO_RAM_MANAGER)
                  if (p_session->session_req.audio_ram_fd != NULL)
                  {
                    size_read = ram_read(p_session, play_buffer, p_session->session_req.size);
                  }
                #endif

                  if (audio_convert_from_mms(play_buffer, size_read,
                                         &(p_session->session_info.previous_type),
                                         &(p_session->session_info.size_left)) != AUDIO_OK)
                  {
                    AUDIO_SEND_TRACE("AUDIO MEMORY DOWNLOADER: wrong MMS format", RV_TRACE_LEVEL_DEBUG_LOW);
                    size_read = 0;// will fill buffer with END_MASK
                  }

                  /* last buffer, put END_MASK */
                  if (  ((UINT16)size_read) < p_session->session_req.size )
                  {
                    UINT16 i;

                    if (p_session->session_info.size_left != 0)
                      AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: MMS PLAY file incomplete",
                        p_session->session_info.size_left, RV_TRACE_LEVEL_DEBUG_LOW);
                    for (i = size_read; i < p_session->session_req.size; i++)
                      *(play_buffer + i) = SC_VM_AMR_END_MASK;
                  }

                  audio_driver_play_buffer(channel_id, play_buffer);

                  if (size_read > 0)
                  {
                    AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: MEMORY to RAM", size_read, RV_TRACE_LEVEL_DEBUG_LOW);//DEBUG
                  }
                  else
                  {
                    AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: buffer not used", RV_TRACE_LEVEL_DEBUG_LOW);//DEBUG
                  }
                } // if (audio_driver_get_play_buffer(channel_id, &p_buffer) == AUDIO_OK)
                else
                  AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: no buffer available", RV_TRACE_LEVEL_DEBUG_LOW);//DEBUG
              }
              break;
            }
          }
          break;
          case AUDIO_DRIVER_LAST_NOTIFICATION_MSG:
          {
            UINT16 record_buffer_size;

            record_buffer_size = p_session->session_req.size;

            audio_convert_to_mms((UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                                 &record_buffer_size,
                                 &(p_session->session_info.previous_type),
                                 &(p_session->session_info.size_left));

          #if (AUDIO_NEW_FFS_MANAGER)
            if (p_session->session_req.audio_ffs_fd != NULL)
            {
              if ((ffs_write  (p_session->session_req.audio_ffs_fd,
                               (UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                               record_buffer_size)) < EFFS_OK)
              {
                AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: FFS RECORD WRITE FAILED", RV_TRACE_LEVEL_DEBUG_LOW);
              }
            }
          #endif
          #if (AUDIO_RAM_MANAGER)
            if (p_session->session_req.audio_ram_fd != NULL)
            {
              if ((ram_write  (p_session,
                               (UINT8 *)((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer,
                               record_buffer_size)) < 0)
              {
                AUDIO_SEND_TRACE("AUDIO MEMORY MANAGER: RAM RECORD WRITE FAILED", RV_TRACE_LEVEL_DEBUG_LOW);
              }
            }
          #endif

            /* recorded_size */
            AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: last RAM to MEMORY", record_buffer_size, RV_TRACE_LEVEL_DEBUG_LOW);
            AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: size recorded",
              ((T_AUDIO_DRIVER_LAST_NOTIFICATION *)p_message)->recorded_size, RV_TRACE_LEVEL_DEBUG_LOW);
            p_session->session_info.recorded_size = ((T_AUDIO_DRIVER_LAST_NOTIFICATION *)p_message)->recorded_size;

            /* stop must no longer be accepted as it is an automatic stop */
            p_session->session_info.stop_req_allowed = FALSE;

            /* MEM return_path */
            return_path.callback_func    = NULL;
            return_path.addr_id          = p_audio_gbl_var->addrId;

            audio_driver_free_session(channel_id, return_path);
          }
          break;
          case AUDIO_DRIVER_STATUS_MSG:
          {
            /* STOP OK for play */
            /* FREE OK for record */
            if ( ( (((T_AUDIO_DRIVER_STATUS *)p_message)->status_type == AUDIO_STOP_STATUS) &&
                    (((T_AUDIO_DRIVER_STATUS *)p_message)->status == AUDIO_OK)) ||
                 ( (((T_AUDIO_DRIVER_STATUS *)p_message)->status_type == AUDIO_FREE_STATUS) &&
                    (((T_AUDIO_DRIVER_STATUS *)p_message)->status == AUDIO_OK)) )
            {
            #if (AUDIO_NEW_FFS_MANAGER)
              if (p_session->session_req.audio_ffs_fd != NULL)
              {
                if ( ffs_close(p_session->session_req.audio_ffs_fd) != EFFS_OK )
                {
                  audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
                }
                AUDIO_SEND_TRACE_PARAM("AUDIO MEMORY MANAGER: close FFS file for mem channel:", mem_channel_id, RV_TRACE_LEVEL_DEBUG_LOW);
              }
            #endif

              if (((T_AUDIO_DRIVER_STATUS *)p_message)->status_type == AUDIO_FREE_STATUS)
                audio_mem_send_record_status(channel_id, p_session->session_info.recorded_size, return_path);
              else
                audio_mem_send_status(AUDIO_OK, channel_id, AUDIO_STOP_STATUS, return_path);

              p_session->session_info.state = AUDIO_MEM_IDLE;
            }
          } //case AUDIO_DRIVER_STATUS_MSG:
          break;
          case AUDIO_MEM_STOP_REQ:
          {
            /* check stop req is allowed i.e. no previous stop req, nor automatic stop */
            if (p_session->session_info.stop_req_allowed == TRUE)
            {
              p_session->session_info.stop_req_allowed = FALSE;

              audio_driver_stop_session(channel_id);
            }
            else
            {
              audio_mem_error_trace(AUDIO_ERROR_STOP_EVENT);
              //audio_mem_send_status(AUDIO_ERROR, channel_id, AUDIO_STOP_STATUS, return_path);
            }
          }
          break;
          case AUDIO_MEM_START_REQ:
            audio_mem_error_trace(AUDIO_ERROR_START_EVENT);
            //audio_mem_send_status(AUDIO_ERROR, channel_id, AUDIO_START_STATUS, return_path);
          break;
        }//switch (p_message->msg_id)
      } //case AUDIO_MEM_WAIT_NOTIFICATION_OR_STOP:
      break;
    } // switch(state)
  }

  UINT8 audio_mem_message_switch(T_RV_HDR *p_message)
  {
    UINT8 channel_id;
    UINT8 mem_channel_id = 0;

    /* MEM START and STOP */
    if ((p_message->msg_id == AUDIO_MEM_START_REQ)||
        (p_message->msg_id == AUDIO_MEM_STOP_REQ))
      return 1;

    /* For other messages, we must check channel_id is really handled by MEM
      and not by other managers such as streaming or UART */
    if (p_message->msg_id == AUDIO_DRIVER_STATUS_MSG)
      channel_id = ((T_AUDIO_DRIVER_STATUS *)p_message)->channel_id;

    if (p_message->msg_id == AUDIO_DRIVER_NOTIFICATION_MSG)
      channel_id = ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id;

    if (p_message->msg_id == AUDIO_DRIVER_LAST_NOTIFICATION_MSG)
      channel_id = ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id;

    /* find active MEM session handling channel_id */
    while ( (mem_channel_id < AUDIO_MEM_MAX_CHANNEL) &&
            ((p_audio_gbl_var->audio_mem_session[mem_channel_id].session_info.state == AUDIO_MEM_IDLE)||
             (p_audio_gbl_var->audio_mem_session[mem_channel_id].session_req.channel_id != channel_id)))
    {
      mem_channel_id++;
    }

    if (mem_channel_id == AUDIO_MEM_MAX_CHANNEL)
      return 0;
    else
      return 1;
  }
#endif // AUDIO_MEM_MANAGER

#endif /* RVM_AUDIO_MAIN_SWE */

