view src/cs/services/audio/audio_ffs.c @ 275:79cfefc1e2b4

audio mode load: gracefully handle mode files of wrong AEC version Unfortunately our change of enabling L1_NEW_AEC (which is necessary in order to bring our Calypso ARM fw into match with the underlying DSP reality) brings along a change in the audio mode file binary format and file size - all those new tunable AEC parameters do need to be stored somewhere, after all. But we already have existing mode files in the old format, and setting AEC config to garbage when loading old audio modes (which is what would happen without the present change) is not an appealing proposition. The solution implemented in the present change is as follows: the audio mode loading code checks the file size, and if it differs from the active version of T_AUDIO_MODE, the T_AUDIO_AEC_CFG structure is cleared - set to the default (disabled AEC) for the compiled type of AEC. We got lucky in that this varying T_AUDIO_AEC_CFG structure sits at the end of T_AUDIO_MODE!
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 30 Jul 2021 02:55:48 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/****************************************************************************/
/*                                                                          */
/*  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 */