view src/cs/services/audio/audio_driver.c @ 287:3dee79757ae4

UI fw: load handheld audio mode on boot We have now reached the point where use of audio mode config files should be considered mandatory. In ACI usage we can tell users that they need to perform an AT@AUL of some appropriate audio mode, but in UI-enabled fw we really need to have the firmware load audio modes on its own, so that correct audio config gets established when the handset or development board runs on its own, without a connected host computer. Once have FC Venus with both main and headset audio channels and headset plug insertion detection, our fw will need to automatically load the handheld mode or the headset mode depending on the plug insertion state. For now we load only the handheld mode, which has been tuned for FC-HDS4 on FC Luna.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 13 Nov 2021 03:20:57 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/****************************************************************************/
/*                                                                          */
/*  File Name:  audio_driver.c                                              */
/*                                                                          */
/*  Purpose:  This file contains all the functions used to manage the       */
/*            driver.                                                       */
/*                                                                          */
/*  Version   0.1                                                           */
/*                                                                          */
/*  Date        Modification                                                */
/*  ------------------------------------                                    */
/*  09 December 2002  Create                                                */
/*                                                                          */
/*  Author   Frederic Turgis                                                */
/*                                                                          */
/* (C) Copyright 2002 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"
  #include "rvf/rvf_api.h"
  #include "rv/rv_general.h"
  #include "rvm/rvm_gen.h"
  #include "audio/audio_features_i.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"
  
  #ifndef _WINDOWS
    // include the usefull L1 header
    #define BOOL_FLAG
    #define CHAR_FLAG
    #include "l1_types.h"
    #include "cust_os.h"
    #include "l1audio_cust.h"
    #include "l1audio_msgty.h"
    #include "l1audio_signa.h"
    #include "l1_signa.h"
  #else
    // include the usefull L1 header
    #define BOOL_FLAG
    #define CHAR_FLAG
    #include "l1_types.h"
    #include "l1audio_const.h"
    #include "l1audio_cust.h"
    #include "l1audio_defty.h"
    #include "l1audio_msgty.h"
    #include "l1audio_signa.h"
    #include "l1_const.h"
    #include "l1_defty.h"
    #include "l1_msgty.h"
    #include "l1_signa.h"
    #include "l1_varex.h"
	#include "audio/tests/audio_test.h"
  #endif

#if (L1_AUDIO_DRIVER)
  #if (L1_VOICE_MEMO_AMR)
    extern T_AUDIO_RET audio_driver_vm_amr_play_manager (T_RV_HDR *p_message, T_AUDIO_DRIVER_SESSION *p_session);
    extern T_AUDIO_RET audio_driver_vm_amr_record_manager (T_RV_HDR *p_message, T_AUDIO_DRIVER_SESSION *p_session);
    extern T_AUDIO_RET audio_driver_midi_manager (T_RV_HDR *p_message, T_AUDIO_DRIVER_SESSION *p_session);
  #endif

  UINT8 audio_driver_message_switch(T_RV_HDR *p_message);
  void audio_driver_send_status (T_AUDIO_RET status,
                                 UINT8 status_type,
                                 UINT8 channel_id,
                                 T_RV_RETURN return_path);
  void audio_driver_init_send_status (T_AUDIO_RET status,
                                      UINT8 session_id,
                                      UINT8 channel_id,
                                      T_RV_RETURN return_path);
  void audio_driver_manager(T_RV_HDR *p_message);
  T_AUDIO_RET audio_driver_get_play_buffer(UINT8 channel_id, UINT8 **pp_buffer);
  T_AUDIO_RET audio_driver_play_buffer(UINT8 channel_id, UINT8 *p_buffer);

  UINT8 audio_driver_message_switch(T_RV_HDR *p_message)
  {
    switch (p_message->msg_id)
    {
      case AUDIO_DRIVER_START_SESSION:
      case AUDIO_DRIVER_STOP_SESSION:
      case AUDIO_DRIVER_FREE_SESSION:
        return(AUDIO_DRIVER_SWITCH);
      break;
    #if (L1_VOICE_MEMO_AMR)
      case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
      case MMI_VM_AMR_RECORD_START_CON:
      case MMI_VM_AMR_RECORD_STOP_CON:
        return(AUDIO_DRIVER_VM_AMR_RECORD_SESSION_SWITCH);
      break;
      case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
      case MMI_VM_AMR_PLAY_START_CON:
      case MMI_VM_AMR_PLAY_STOP_CON:
        return(AUDIO_DRIVER_VM_AMR_PLAY_SESSION_SWITCH);
      break;
    #endif
    #if (L1_MIDI == 1)
      case AUDIO_DRIVER_INIT_MIDI_SESSION:
      case MMI_MIDI_START_CON:
      case MMI_MIDI_STOP_CON:
        return(AUDIO_DRIVER_MIDI_SESSION_SWITCH);
      break;
    #endif
      default:
        return(AUDIO_DRIVER_NONE);
      break;
    } // switch
  }

  void audio_driver_send_status (T_AUDIO_RET status,
                                 UINT8       status_type,
                                 UINT8       channel_id,
                                 T_RV_RETURN return_path)
  {
    T_AUDIO_DRIVER_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_DRIVER_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_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
        rvf_delay(RVF_MS_TO_TICKS(1000));
      }
    }

    // fill the header of the message + parameters
    p_send_message->os_hdr.msg_id = AUDIO_DRIVER_STATUS_MSG;
    p_send_message->status      = status;
    p_send_message->status_type = status_type;
    p_send_message->channel_id  = channel_id;

    // 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_driver_init_send_status (T_AUDIO_RET status,
                                      UINT8       session_id,
                                      UINT8       channel_id,
                                      T_RV_RETURN return_path)
  {
    T_AUDIO_DRIVER_INIT_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_DRIVER_INIT_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_driver_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_DRIVER_INIT_STATUS_MSG;

    // fill the status parameters
    p_send_message->status      = status;
    p_send_message->session_id  = session_id;
    p_send_message->channel_id  = channel_id;

    // 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_driver_manager(T_RV_HDR *p_message)
  {
    T_AUDIO_DRIVER_SESSION *p_session;
    T_AUDIO_DRIVER_PARAMETER *driver_parameter;
    T_RV_RETURN return_path;
    T_RVF_MB_STATUS mb_status;
    UINT8 session_id, channel_id, state, j;

    // initialize return_path to default values
    return_path.callback_func=NULL;
    return_path.addr_id=0;

    // find state + extract information:channel_id or session_id + driver_parameter
    switch (p_message->msg_id)
    {
      // start/stop session messages have channel_id so we know the driver_session
      case AUDIO_DRIVER_START_SESSION:
      case AUDIO_DRIVER_STOP_SESSION:
      case AUDIO_DRIVER_FREE_SESSION:
        channel_id = ((T_AUDIO_DRIVER_HANDLE_SESSION *)p_message)->channel_id;
        p_session  = &(p_audio_gbl_var->audio_driver_session[channel_id]);
        state      = p_session->session_info.state;
        if (p_message->msg_id != AUDIO_DRIVER_STOP_SESSION)
          return_path = ((T_AUDIO_DRIVER_HANDLE_SESSION *)p_message)->return_path;
        else
          return_path = p_session->session_req.return_path;
      break;
      // messages which contain only session_id, must look for it in ACTIVE driver_session
      default:
      {
        switch (p_message->msg_id)
        {
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
            session_id       = AUDIO_VM_AMR_RECORD_SESSION_ID;
            driver_parameter = &(((T_AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION *)p_message)->driver_parameter);
            return_path      = ((T_AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION *)p_message)->return_path;
          break;
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
            session_id       = AUDIO_VM_AMR_PLAY_SESSION_ID;
            driver_parameter = & (((T_AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION *)p_message)->driver_parameter);
            return_path      = ((T_AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION *)p_message)->return_path;
          break;
          case MMI_VM_AMR_RECORD_START_CON:
          case MMI_VM_AMR_RECORD_STOP_CON:
            session_id = AUDIO_VM_AMR_RECORD_SESSION_ID;
          break;
          case MMI_VM_AMR_PLAY_START_CON:
          case MMI_VM_AMR_PLAY_STOP_CON:
            session_id = AUDIO_VM_AMR_PLAY_SESSION_ID;
          break;
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
            session_id       = AUDIO_MIDI_SESSION_ID;
            driver_parameter = &(((T_AUDIO_DRIVER_INIT_MIDI_SESSION *)p_message)->driver_parameter);
            return_path      = ((T_AUDIO_DRIVER_INIT_MIDI_SESSION *)p_message)->return_path;
          break;
          case MMI_MIDI_START_CON:
          case MMI_MIDI_STOP_CON:
            session_id = AUDIO_MIDI_SESSION_ID;
          break;
        #endif
        }

        // initialize channel_id to browse all driver channels
        channel_id = 0;
        state = AUDIO_DRIVER_CHANNEL_WAIT_INIT;

        // look for an active session, which session_id matches the one from the message
        while ( (channel_id < AUDIO_DRIVER_MAX_CHANNEL)&&
                ((p_audio_gbl_var->audio_driver_session[channel_id].session_info.state == AUDIO_DRIVER_CHANNEL_WAIT_INIT)||
                (p_audio_gbl_var->audio_driver_session[channel_id].session_req.session_id != session_id)) )
        {
          channel_id++;
        }
        // if channel_id < MAX_CHANNEL, we found an active channel so we can derive channel_id + state
        if (channel_id < AUDIO_DRIVER_MAX_CHANNEL)
        {
          p_session = &(p_audio_gbl_var->audio_driver_session[channel_id]);
          state = p_session->session_info.state;
          return_path = p_session->session_req.return_path;
        }
      }
      break; // default
    }

    switch (state)
    {
      case AUDIO_DRIVER_CHANNEL_WAIT_INIT:
      {
        switch (p_message->msg_id)
        {
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
          {
            T_AUDIO_RET result;

            // Find a free channel
            channel_id = 0;
            while ( (p_audio_gbl_var->audio_driver_session[channel_id].session_info.state != AUDIO_DRIVER_CHANNEL_WAIT_INIT) &&
                    (channel_id < AUDIO_DRIVER_MAX_CHANNEL) )
              channel_id++;

            if (channel_id == AUDIO_DRIVER_MAX_CHANNEL)
            {
              AUDIO_SEND_TRACE("no driver channel available", RV_TRACE_LEVEL_DEBUG_LOW);
              audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
              return;
            }

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

            // get session descriptor and fill REQ parameters
            p_session = &(p_audio_gbl_var->audio_driver_session[channel_id]);
            p_session->session_req.session_id     = session_id;
            p_session->session_req.size           = driver_parameter->buffer_size << 1;// we request 16-bit words buffers
            p_session->session_req.nb_buffer      = driver_parameter->nb_buffer;
            // fill return_path parameters, may be used if next message is STOP_SESSION
            p_session->session_req.return_path.callback_func = return_path.callback_func;
            p_session->session_req.return_path.addr_id = return_path.addr_id;

            /************************************************************/
            /* the driver must allocate the RAM buffers pointer         */
            /************************************************************/
            mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                                     sizeof(T_AUDIO_DRIVER_BUFFER_INFO)*p_session->session_req.nb_buffer,
                                     (T_RVF_BUFFER **) (&p_session->session_info.buffer));

            // If insufficient resources, then report a memory error and abort.
            if (mb_status == RVF_RED)
            {
              audio_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
              audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
              return;
            }

            /************************************************************/
            /* the driver must allocate the RAM buffers                 */
            /************************************************************/
            for (j = 0; j < p_session->session_req.nb_buffer; 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)
              {
                UINT8 i;
                // free already allocated buffers + buffer pointer
                if (j > 0)
                {
                  for (i = j - 1; i >= 0; i--)
                    rvf_free_buf((T_RVF_BUFFER *)p_session->session_info.buffer[i].p_start_pointer);
                }
                rvf_free_buf((T_RVF_BUFFER *)p_session->session_info.buffer);
                audio_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
                audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
                return;
              }

              // initialize parameters
              p_session->session_info.buffer[j].size = p_session->session_req.size;

              AUDIO_SEND_TRACE_PARAM("AUDIO DRIVER: allocate buffer",
                p_session->session_info.buffer[j].p_start_pointer, RV_TRACE_LEVEL_DEBUG_LOW);
            }

            // info parameters (state must be changed before driver specific functions call
            p_session->session_info.index_l1     = 0;
            p_session->session_info.index_appli  = 0;
            p_session->session_info.stop_request = 0;

            // conversion of parameters + prepare l1 start message
            switch(p_message->msg_id)
            {
            #if (L1_VOICE_MEMO_AMR)
              case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
                result=audio_driver_vm_amr_record_manager(p_message,p_session);
              break;
              case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
                result=audio_driver_vm_amr_play_manager(p_message,p_session);
              break;
            #endif
            #if (L1_MIDI == 1)
              case AUDIO_DRIVER_INIT_MIDI_SESSION:
                result=audio_driver_midi_manager(p_message,p_session);
              break;
            #endif
            }

            // check L1 msg allocation was successfull
            if (result != AUDIO_OK)
            {
              AUDIO_SEND_TRACE("AUDIO DRIVER MANAGER: L1 msg allocation failed", RV_TRACE_LEVEL_DEBUG_LOW);
              audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
              return;
            }

            // state (must be changed after driver specific functions calls)
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_START;

            audio_driver_init_send_status(AUDIO_OK, session_id, channel_id, return_path);
          } //case AUDIO_DRIVER_INIT_..._SESSION:
          break;
          case AUDIO_DRIVER_START_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_START_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
          break;
          case AUDIO_DRIVER_STOP_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_STOP_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
          break;
          case AUDIO_DRIVER_FREE_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_FREE_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_FREE_STATUS, channel_id, return_path);
          break;
        } // switch (p_message->msg_id)
      } //case AUDIO_DRIVER_CHANNEL_WAIT_INIT:
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_START:
      {
        switch (p_message->msg_id)
        {
          case AUDIO_DRIVER_START_SESSION:
          {
            T_AUDIO_RET result;

            // fill notification parameters
            p_session->session_req.return_path.callback_func = return_path.callback_func;
            p_session->session_req.return_path.addr_id = return_path.addr_id;

            // send l1 message
            switch(p_session->session_req.session_id)
            {
            #if (L1_VOICE_MEMO_AMR)
              case AUDIO_VM_AMR_RECORD_SESSION_ID:
                result=audio_driver_vm_amr_record_manager(p_message,p_session);
              break;
              case AUDIO_VM_AMR_PLAY_SESSION_ID:
                result=audio_driver_vm_amr_play_manager(p_message,p_session);
              break;
            #endif
            #if (L1_MIDI == 1)
              case AUDIO_MIDI_SESSION_ID:
                result=audio_driver_midi_manager(p_message,p_session);
              break;
            #endif
            }

            if (result != AUDIO_OK)
            {
              audio_driver_error_trace(AUDIO_ERROR_L1_START_EVENT);
              audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
              return;
            }

            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_START_CON;
          }
          break;
          case AUDIO_DRIVER_STOP_SESSION:
          {
            // deallocate buffers
            for(j=0; j<p_session->session_req.nb_buffer; j++)
            {
              mb_status=rvf_free_buf((T_RVF_BUFFER *)(p_session->session_info.buffer[j].p_start_pointer));

              AUDIO_SEND_TRACE_PARAM("AUDIO DRIVER MANAGER: deallocate buffer",
                j, RV_TRACE_LEVEL_DEBUG_LOW);

              if (mb_status != RVF_GREEN)
                AUDIO_SEND_TRACE_PARAM("can't deallocate buffer", j, RV_TRACE_LEVEL_ERROR);
            }

            // Deallocate buffers pointer
            rvf_free_buf((T_RVF_BUFFER *)p_session->session_info.buffer);

            // deallocate l1 message
            audio_deallocate_l1_message(p_session->session_req.p_l1_send_message);

            // send status OK
            audio_driver_send_status(AUDIO_OK,AUDIO_STOP_STATUS,channel_id,return_path);

            // change state
            p_session->session_info.state=AUDIO_DRIVER_CHANNEL_WAIT_INIT;
          }
          break;
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
            audio_driver_error_trace(AUDIO_ERROR_INIT_EVENT);
            audio_driver_init_send_status(AUDIO_ERROR, session_id, 0, return_path);
          break;
          case AUDIO_DRIVER_FREE_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_FREE_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_FREE_STATUS, channel_id, return_path);
          break;
        } // switch
      } //case AUDIO_DRIVER_CHANNEL_WAIT_START:
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_START_CON:
      {
        switch (p_message->msg_id)
        {
        #if (L1_VOICE_MEMO_AMR)
          case MMI_VM_AMR_RECORD_START_CON:
          case MMI_VM_AMR_PLAY_START_CON:
        #endif
        #if (L1_MIDI == 1)
          case MMI_MIDI_START_CON:
        #endif
            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_STOP;
          break;
          case AUDIO_DRIVER_STOP_SESSION:
            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_START_CON_TO_STOP;
          break;
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
            audio_driver_error_trace(AUDIO_ERROR_INIT_EVENT);
            audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
          break;
          case AUDIO_DRIVER_START_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_START_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
          break;
          case AUDIO_DRIVER_FREE_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_FREE_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_FREE_STATUS, channel_id, return_path);
          break;
        } // switch
      } //case AUDIO_DRIVER_CHANNEL_WAIT_START_CON:
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_STOP:
      {
        switch (p_message->msg_id)
        {
          case AUDIO_DRIVER_STOP_SESSION:
          {
            // 1st stop request
            if (p_session->session_info.stop_request == 0)
            {
              T_AUDIO_RET result;

              // send l1 message STOP_REQ
              switch(p_session->session_req.session_id)
              {
              #if (L1_VOICE_MEMO_AMR)
                case AUDIO_VM_AMR_RECORD_SESSION_ID:
                  result=audio_driver_vm_amr_record_manager(p_message,p_session);
                break;
                case AUDIO_VM_AMR_PLAY_SESSION_ID:
                  result=audio_driver_vm_amr_play_manager(p_message,p_session);
                break;
              #endif
              #if (L1_MIDI == 1)
                case AUDIO_MIDI_SESSION_ID:
                  result=audio_driver_midi_manager(p_message,p_session);
                break;
              #endif
              }

              // allocate or send L1 msg went wrong
              if (result != AUDIO_OK)
              {
                audio_driver_error_trace(AUDIO_ERROR_L1_STOP_EVENT);
                audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
                return;
              }

              // STOP has been requested, no longer accept it
              p_session->session_info.stop_request = 1;
            }
            else
            {
              audio_driver_error_trace(AUDIO_ERROR_STOP_EVENT);
              audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
            }
          }
          break;
        #if (L1_VOICE_MEMO_AMR)
          case MMI_VM_AMR_RECORD_STOP_CON:
          {
            // send last notification
            T_AUDIO_DRIVER_LAST_NOTIFICATION *p_status_message;

            // Allocate the Riviera buffer
            mb_status = RVF_RED;
            while (mb_status == RVF_RED)
            {
              mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                                       sizeof (T_AUDIO_DRIVER_LAST_NOTIFICATION),
                                       (T_RVF_BUFFER **) (&p_status_message));
              // If insufficient resources, then report a memory error and abort.
              if (mb_status == RVF_RED)
              {
                // the memory is insufficient to continue the non regression test
                audio_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
                rvf_delay(RVF_MS_TO_TICKS(1000));
              }
            }

            // Fill the message ID
            p_status_message->header.msg_id = AUDIO_DRIVER_LAST_NOTIFICATION_MSG;

            // fill parameters
            p_status_message->channel_id = channel_id;
            p_status_message->recorded_size = ((T_MMI_VM_AMR_RECORD_CON *)p_message)->recorded_size - SC_VM_AMR_END_MASK_SIZE;
            p_status_message->p_buffer   =
              (UINT16 *)p_session->session_info.buffer[p_session->session_info.index_l1].p_start_pointer;

            if (return_path.callback_func == NULL)
              rvf_send_msg (return_path.addr_id, p_status_message);
            else
            {
              // call the callback function
              (*(return_path.callback_func))((void *)(p_status_message));
              rvf_free_buf((T_RVF_BUFFER *)p_status_message);
            }

            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_FREE;
          }
          break;
        #endif // #if (L1_VOICE_MEMO_AMR)
        #if (L1_VOICE_MEMO_AMR)
          case MMI_VM_AMR_PLAY_STOP_CON:
        #endif
        #if (L1_MIDI == 1)
          case MMI_MIDI_STOP_CON:
        #endif
          {
            // deallocate buffers
            for (j = 0; j < p_session->session_req.nb_buffer; j++)
            {
              mb_status = rvf_free_buf ((T_RVF_BUFFER *) (p_session->session_info.buffer[j].p_start_pointer));

              AUDIO_SEND_TRACE_PARAM("AUDIO DRIVER MANAGER: deallocate buffer", j, RV_TRACE_LEVEL_DEBUG_LOW);

              if (mb_status != RVF_GREEN)
                AUDIO_SEND_TRACE_PARAM("can't deallocate buffer", j, RV_TRACE_LEVEL_ERROR);
            }
            // Deallocate buffers pointer
            rvf_free_buf((T_RVF_BUFFER *)p_session->session_info.buffer);

            audio_driver_send_status (AUDIO_OK, AUDIO_STOP_STATUS, channel_id,
                                      return_path);
            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_INIT;
          }
          break;
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
            audio_driver_error_trace(AUDIO_ERROR_INIT_EVENT);
            audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
          break;
          case AUDIO_DRIVER_START_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_START_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
          break;
          case AUDIO_DRIVER_FREE_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_FREE_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_FREE_STATUS, channel_id, return_path);
          break;
        } //switch
      } //case AUDIO_DRIVER_CHANNEL_WAIT_STOP:
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_START_CON_TO_STOP:
      {
        T_AUDIO_RET result = AUDIO_OK;
        switch (p_message->msg_id)
        {
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
            audio_driver_error_trace(AUDIO_ERROR_INIT_EVENT);
            audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
            return;
          break;
          case AUDIO_DRIVER_START_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_START_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
            return;
          break;
          case AUDIO_DRIVER_STOP_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_STOP_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
            return;
          break;
          case AUDIO_DRIVER_FREE_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_FREE_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_FREE_STATUS, channel_id, return_path);
            return;
          break;
        #if (L1_VOICE_MEMO_AMR)
          case MMI_VM_AMR_RECORD_START_CON:
            // send L1 stop msg
            result=audio_driver_vm_amr_record_manager(p_message, p_session);
          break;
          case MMI_VM_AMR_PLAY_START_CON:
            // send L1 stop msg
            result=audio_driver_vm_amr_play_manager(p_message, p_session);
          break;
        #endif
        #if (L1_MIDI == 1)
          case MMI_MIDI_START_CON:
            // send L1 stop msg
            result=audio_driver_midi_manager(p_message,p_session);
          break;
        #endif
        }

        if (result != AUDIO_OK)
        {
          audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
          return;
        }
        else
        {
          // next state should be WAIT_STOP_CON, which is WAIT_STOP + stop_request == 1
          p_session->session_info.stop_request = 1;
          // change state
          p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_STOP;
        }
      }
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_FREE:
      {
        switch (p_message->msg_id)
        {
          case AUDIO_DRIVER_FREE_SESSION:
          {
            // deallocate buffers
            for (j = 0; j < p_session->session_req.nb_buffer; j++)
            {
              mb_status = rvf_free_buf ((T_RVF_BUFFER *) (p_session->session_info.buffer[j].p_start_pointer));

              AUDIO_SEND_TRACE_PARAM("AUDIO DRIVER MANAGER: deallocate buffer", j, RV_TRACE_LEVEL_DEBUG_LOW);

              if (mb_status != RVF_GREEN)
                AUDIO_SEND_TRACE_PARAM("can't deallocate buffer", j, RV_TRACE_LEVEL_ERROR);
            }
            // Deallocate buffers pointer
            rvf_free_buf((T_RVF_BUFFER *)p_session->session_info.buffer);

            audio_driver_send_status (AUDIO_OK, AUDIO_FREE_STATUS, channel_id,
                                      return_path);

            // change state
            p_session->session_info.state = AUDIO_DRIVER_CHANNEL_WAIT_INIT;
          }
          break;
        #if (L1_VOICE_MEMO_AMR)
          case AUDIO_DRIVER_INIT_VM_AMR_RECORD_SESSION:
          case AUDIO_DRIVER_INIT_VM_AMR_PLAY_SESSION:
        #endif
        #if (L1_MIDI == 1)
          case AUDIO_DRIVER_INIT_MIDI_SESSION:
        #endif
            audio_driver_error_trace(AUDIO_ERROR_INIT_EVENT);
            audio_driver_init_send_status(AUDIO_ERROR, session_id, channel_id, return_path);
          break;
          case AUDIO_DRIVER_START_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_START_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_START_STATUS, channel_id, return_path);
          break;
          case AUDIO_DRIVER_STOP_SESSION:
            audio_driver_error_trace(AUDIO_ERROR_STOP_EVENT);
            audio_driver_send_status(AUDIO_ERROR, AUDIO_STOP_STATUS, channel_id, return_path);
          break;
        } // switch
      }
      break;
    }
  }
#endif // (L1_AUDIO_DRIVER)

#endif // #ifdef RVM_AUDIO_MAIN_SWE