/*===========================================================================
                    IMPORTANT NOTICE

        THIS FILE IS NOT TO BE DISTRIBUTED IN SOURCE

FILE:  bridle_MediaCMX.c

SERVICES:  BRIDLE IMedia Services based on CMX.

GENERAL DESCRIPTION:
	BREW Kernel entry point for media services based on CMX.

        Copyright © 2003 QUALCOMM Incorporated.
               All Rights Reserved.
            QUALCOMM Proprietary/GTDR
===========================================================================*/

#include "OEMFeatures.h"

#if defined(FEATURE_BREW_MULTIMEDIA)

#include "msm/bridle_MediaCMX.h"
#include "BRIDLEInit_OEM.h"
#include "AEEStdLib.h"

#define BRIDLE_MEDIACMX_MAX_HANDLES  64

#define FARF_BRIDLE_MEDIACMX  1
#define FARF(x, p)  if (1 == FARF_##x) DBGPRINTF p
/*==================================================================
         TYPEDEFS
==================================================================*/
#if !defined(FEATURE_BREW_CMX_V3)
/* Structures for QCP recording configuration parameters */
typedef struct {
  cmx_qcp_format_type   format;       /* QCP recording mode            */
  uint32                report_ms;    /* Time callback interval in ms  */
  uint32                auto_stop_ms; /* Silence time to end recording */  
} cmx_qcp_rec_para_type;
#endif // !defined(FEATURE_BREW_CMX_V3)


/*==================================================================
         STATIC DATA
==================================================================*/
#if __ARMCC_VERSION >= 120000
#pragma arm section zidata = "bridle_svc_rw_usr_ro"
#endif
uint32 BRIDLE_SUBSYS_NO(MediaCMX);
#if __ARMCC_VERSION >= 120000
#pragma arm section zidata
#endif

static AEEInstance   gpInstances[BRIDLE_MEDIACMX_MAX_HANDLES]; // compile time limit to number of simultaneous user mode file handles
AEEInstanceList      gMediaCMXInstanceList = { gpInstances, sizeof(gpInstances)/sizeof(gpInstances[0]), 0 };

static void BridleCMX_CheckCallback(uint32 swi, uint16 nParmID, CMXInfo * pci);
static void BridleCMX_CheckMediaData(uint32 swi, CMXInfo * pci);

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

      UNPACKBRIDLE_OEMMedia FUNCTIONS

===============================================================================*/
DECLARE_STATIC_UNPACKBRIDLE_OEMMEDIA_FUNCTIONS()

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

      OEMMedia INTERFACE FUNCTIONS

===============================================================================*/
DECLARE_STATIC_OEMMEDIA_FUNCTIONS()

/*==================================================================
   
     BRIDLE FUNCTION REGISTRATION
   
==================================================================*/
BRIDLE_DECLARE_SUBSYS_HANDLER_TABLE(MediaCMX);

BRIDLE_DECLARE_GENERIC_SUBSYS_SWIHANDLER(MediaCMX)

int bridle_MediaCMX_RegisterSubSystem(void *po)
{
   OEMMM_DEFINE_BRIDLE_INIT_SYBSYS_HANDLER_TABLE(MediaCMX);

   return BRIDLE_REGISTER_SUBSYS(MediaCMX);
}

/*==================================================================
   
     MediaCMX UNPACKBRIDLE IMPLEMENTATION
   
==================================================================*/
/*==================================================================

==================================================================*/
static uint32 unpackbridle_OEMMedia_New(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{  
   OEMINSTANCE    m;
   uint32         h;
   int            nErr;
   AEECLSID       cls = (AEECLSID)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE *  pi = (OEMINSTANCE *)UNPACKBRIDLE_PARAM_2;

   if (!cls || !pi)
      return EBADPARM;

   BRIDLE_CHECK_WRITEACCESS(swi, pi, sizeof(OEMINSTANCE));

   nErr = OEMMedia_New(cls, &m);
   if (nErr)
      return nErr;

   if (!AEEHandle_To(&gMediaCMXInstanceList, m, &h))
   {
      OEMMedia_Delete(m);
      return EFAILED;
   }

   *pi = (OEMINSTANCE)h;
   return SUCCESS;
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_Delete(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{  
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);

   OEMMedia_Delete(m);
   
   (void)AEEHandle_Clear(&gMediaCMXInstanceList, h);

   return 0;
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_Start(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);
   
   return (uint32)OEMMedia_Start(m);
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_Stop(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);
   
   return (uint32)OEMMedia_Stop(m);
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_PauseResume(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;
   boolean     bPause = (boolean)UNPACKBRIDLE_PARAM_2;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);
   
   return (uint32)OEMMedia_PauseResume(m, bPause);
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_Seek(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{
   uint32         h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE    m = (OEMINSTANCE)h;
   AEEMediaSeek   eSeek = (AEEMediaSeek)UNPACKBRIDLE_PARAM_2;
   int32          lTimeMS = (int32)UNPACKBRIDLE_PARAM_3;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);
   
   return (uint32)OEMMedia_Seek(m, eSeek, lTimeMS);
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_SetParm(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4) 
{
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;
   int16       nParmID = (int16)UNPACKBRIDLE_PARAM_2;
   int32       p1 = (int32)UNPACKBRIDLE_PARAM_3;
   int32       p2 = (int32)UNPACKBRIDLE_PARAM_4;
   int32       p3 = (int32)UNPACKBRIDLE_PARAM_5;
   boolean     bLocal = (boolean)UNPACKBRIDLE_PARAM_6;

   // Some nParmID values do not require object instance.
   if (h)
      BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);

   // Validate the parameters defined in bridle_MediaCMX.h
   switch (nParmID)
   {
      case OEMCMX_ID_TYPE:
      {
         CMXInfo *   psi = (CMXInfo *)p1;

         if (psi)
         { 
            if (OEMCMX_TYPE_QCP_RECORD == psi->nType)
               BRIDLE_CHECK_READACCESS_NZ(swi, p2, sizeof(cmx_qcp_rec_para_type));
#if defined(FEATURE_CMX_RAW_PLAYBACK)
            else if (OEMCMX_TYPE_AUDFMT_PLAY_CODEC == psi->nType)
               BRIDLE_CHECK_READACCESS_NZ(swi, p2, sizeof(cmx_codec_spec_type));
#endif // defined(FEATURE_CMX_RAW_PLAYBACK)

            BridleCMX_CheckCallback(swi, nParmID, psi);
            BridleCMX_CheckMediaData(swi, psi);
         }

         break;
      }

      case OEMCMX_ID_STATUS_CB:
         BridleCMX_CheckCallback(swi, nParmID, (CMXInfo *)p1);
         break;

      case OEMCMX_ID_TOTALTIME:
         BridleCMX_CheckCallback(swi, nParmID, (CMXInfo *)p1);
         BridleCMX_CheckMediaData(swi, (CMXInfo *)p1);
         break;

      case OEMCMX_ID_VOLUME:  // Fall thru...
      case OEMCMX_ID_PAN:     // Fall thru...
      case OEMCMX_ID_TEMPO:   // Fall thru...
      case OEMCMX_ID_TUNE:
         break;

      case OEMCMX_ID_MIDI_DEVICE:
         BridleCMX_CheckCallback(swi, nParmID, (CMXInfo *)p3);
         break;

      case OEMCMX_ID_CHANNEL:
         break;

      case OEMCMX_ID_DATA_RESPONSE:
         BRIDLE_CHECK_READACCESS_NZ(swi, (uint32)p1, sizeof(CMXDataRequest));
         if (p2 && p3)
            BRIDLE_CHECK_READACCESS_NZ(swi, (uint32)p2, (uint32)p3);
         break;

      default:
        break;
   }

   return OEMMedia_SetParm(m, nParmID, p1, p2, p3, bLocal);
}

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

==================================================================*/
static uint32 unpackbridle_OEMMedia_GetParm(uint32 swi, uint32 a1, uint32 a2, uint32 a3, uint32 a4) 
{
   uint32      h = (uint32)UNPACKBRIDLE_PARAM_1;
   OEMINSTANCE m = (OEMINSTANCE)h;
   int16       nParmID = (int16)UNPACKBRIDLE_PARAM_2;
   int32  *    pP1 = (int32 *)UNPACKBRIDLE_PARAM_3;
   int32  *    pP2 = (int32 *)UNPACKBRIDLE_PARAM_4;
   int32  *    pP3 = (int32 *)UNPACKBRIDLE_PARAM_5;

   BRIDLE_CHECK_HANDLE(swi, m, &gMediaCMXInstanceList);

   return OEMMedia_GetParm(m, nParmID, pP1, pP2, pP3);
}

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

==================================================================*/
static void BridleCMX_CheckCallback(uint32 swi, uint16 nParmID, CMXInfo * pci)
{
   uint32   dwFn = 0;

   if (!pci)
      return;

   BRIDLE_CHECK_READACCESS(swi, pci, sizeof(CMXInfo));

   if (OEMCMX_ID_TYPE == nParmID)
   {
      switch (pci->nType)
      {
         case OEMCMX_TYPE_AUDFMT_PLAY:
            dwFn = (uint32)CMediaMMLayer_PlayCB;
            break;

         case OEMCMX_TYPE_AUDFMT_RINGER:
            dwFn = (uint32)CMediaMMLayer_RingerCB;
            break;

#if defined(FEATURE_QCP) || defined(FEATURE_PCM_REC)
         case OEMCMX_TYPE_QCP_RECORD:
            dwFn = (uint32)CMediaMMLayer_RecordCB;
            break;
#endif // defined(FEATURE_QCP) || defined(FEATURE_PCM_REC)

#if defined(FEATURE_MIDI_OUT)
         case OEMCMX_TYPE_MIDI_OUT_MSG:
            dwFn = (uint32)CMediaMMLayer_MIDIOutMsgCB;
            break;

#if defined(FEATURE_MIDI_OUT_QCP)
         case OEMCMX_TYPE_MIDI_OUT_QCP:
            dwFn = (uint32)CMediaMMLayer_MIDIOutQCPPlayCB;
            break;
#endif // defined(FEATURE_MIDI_OUT_QCP)
#endif // defined(FEATURE_MIDI_OUT)

         case OEMCMX_TYPE_AUDFMT_PLAY_CODEC:
            dwFn = (uint32)CMediaMMLayer_RingerCB;
            break;

         default:
            break;
      }
   }
   else if (OEMCMX_ID_STATUS_CB == nParmID)
   {
      switch (pci->nType)
      {
         case OEMCMX_TYPE_AUDFMT_PLAY:
         case OEMCMX_TYPE_AUDFMT_RINGER:
         case OEMCMX_TYPE_QCP_RECORD:
            dwFn = (uint32)CMediaMMLayer_StatusCB;
            break;

         case OEMCMX_TYPE_MIDI_OUT_MSG:
            break;

#if defined(FEATURE_MIDI_OUT) && defined(FEATURE_MIDI_OUT_QCP)
         case OEMCMX_TYPE_MIDI_OUT_QCP:
            dwFn = (uint32)CMediaMMLayer_MIDIOutQCPStatusCB;
            break;
#endif

         default:
            break;
      }
   }
   else if (OEMCMX_ID_TOTALTIME == nParmID)
   {
      if (OEMCMX_TYPE_AUDFMT_PLAY == pci->nType)
         dwFn = (uint32)CMediaMMLayer_TimeCB;
   }
#if defined(FEATURE_MIDI_OUT)
   else if (OEMCMX_ID_MIDI_DEVICE == nParmID)
      dwFn = (uint32)CMIDIOut_MIDIDeviceCB;
#endif // defined(FEATURE_MIDI_OUT)

   if (dwFn)
      BRIDLE_CHECK_VALUE(swi, pci->dwCB, dwFn);
}

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

==================================================================*/
static void BridleCMX_CheckMediaData(uint32 swi, CMXInfo * pci)
{
   if (!pci || !pci->ph)
      return;

   BRIDLE_CHECK_READACCESS(swi, pci->ph, sizeof(cmx_handle_type));

   if (pci->ph->source_type == CMX_SOURCE_EFS)
      BRIDLE_CHECK_READACCESS_NZ(swi, pci->ph->efs.filename, sizeof(pci->ph->efs.filename)); // redundant
   else if (pci->ph->source_type == CMX_SOURCE_MEM)
      BRIDLE_CHECK_READACCESS_NZ(swi, pci->ph->mem.buf, pci->ph->mem.len);
   else if (pci->ph->source_type == CMX_SOURCE_CLIENT)
      BRIDLE_CHECK_VALUE(swi, (uint32)pci->ph->client.data_req_ptr, (uint32)CMediaMMLayer_CMXDataRequestCB);
}

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

      MediaCMX INTERFACE IMPLEMENTATION

===============================================================================*/
typedef struct OEMMedia
{
   AEECLSID       m_clsSelf;

   CMXInfo        m_ciStart;
   CMXInfo        m_ciStatus;

   // Play/Ringer
   int16          m_eType; // CMX_AUDFMT_START_XXX

   // QCPRecord
   uint32         m_dwPauseMS;     // Pause between ringers
   cmx_qcp_rec_para_type * m_pQCPRecParm;
   flg            m_bReverse:1;  // Record locally (ReverseLink)
#if defined(FEATURE_CMX_RAW_PLAYBACK)
   cmx_codec_spec_type *   m_pCodecSpec;
#endif

   // MIDIOutQCP
   uint16         m_wVolume;
   uint16         m_wPan;
   uint32         m_dwChannel;
   
#ifdef FEATURE_MULTISEQUENCER
   // Multisequencer
   cmx_audfmt_multi_param_type * m_pMultiParam;
   void *                        m_pSequence;
   cmx_audfmt_seq_param_type *   m_pSeqParam;
   
#endif  //FEATURE_MULTISEQUENCER

#ifdef FEATURE_PCM_REC
   // PCM Record
   cmx_pcm_rec_para_type * m_pPCMRecParm;
#endif //FEATURE_PCM_REC

} OEMMedia;

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

==================================================================*/
static int OEMMedia_New(AEECLSID cls, OEMINSTANCE * ph) 
{ 
   OEMMedia *  pme;

   if (!ph)
      return EBADPARM;

   pme = (OEMMedia *)MALLOC(sizeof(OEMMedia));
   if (!pme)
      return ENOMEMORY;
   
   *ph = (OEMINSTANCE)pme;
   pme->m_clsSelf = cls;

   return SUCCESS; 
}

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

==================================================================*/
static void OEMMedia_Delete(OEMINSTANCE h)
{ 
   FREE((OEMMedia *)h);
}

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

==================================================================*/
static int  OEMMedia_Start(OEMINSTANCE h)
{
   OEMMedia *  pme = (OEMMedia *)h;
   void *      pUser = (void *)pme->m_ciStatus.dwUserData;

   if (!pme->m_ciStart.ph)
      return EBADPARM;

   switch (pme->m_ciStart.nType)
   {
      case OEMCMX_TYPE_AUDFMT_PLAY:
         cmx_audfmt_play(pme->m_ciStart.ph, CMX_AF_CALLBACK_VALUE, (cmx_audfmt_start_enum_type)pme->m_eType, 
                         (cmx_audfmt_play_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                         pUser);
         break;

      case OEMCMX_TYPE_AUDFMT_RINGER:
         cmx_audfmt_ringer(pme->m_ciStart.ph, (uint16)pme->m_dwPauseMS, (cmx_audfmt_start_enum_type)pme->m_eType,
                           (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                           pUser);
         break;

#if defined(FEATURE_QCP)
      case OEMCMX_TYPE_QCP_RECORD:
         if (pme->m_bReverse)
         {
#if defined(FEATURE_BREW_CMX_V3)
            cmx_qcp_record_reverse(pme->m_ciStart.ph, pme->m_pQCPRecParm,
                                   (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                                   pUser);
#else
            cmx_qcp_record_reverse(pme->m_ciStart.ph, pme->m_pQCPRecParm->format, pme->m_pQCPRecParm->report_ms,
                                   (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                                   pUser);
#endif // defined(FEATURE_BREW_CMX_V3)
         }
         else
         {
#if defined(FEATURE_BREW_CMX_V3)
            cmx_qcp_record_forward(pme->m_ciStart.ph, pme->m_pQCPRecParm,
                                   (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                                   pUser);
#else
            cmx_qcp_record_forward(pme->m_ciStart.ph, pme->m_pQCPRecParm->format, pme->m_pQCPRecParm->report_ms,
                                   (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                                   pUser);
#endif // defined(FEATURE_BREW_CMX_V3)
         }
         break;
#endif // defined(FEATURE_QCP)

#if defined(FEATURE_MIDI_OUT)
      case OEMCMX_TYPE_MIDI_OUT_MSG:
         cmx_midi_out_msg(pme->m_ciStart.ph,
                          (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                          pUser);
         break;

#if defined(FEATURE_MIDI_OUT_QCP)
      case OEMCMX_TYPE_MIDI_OUT_QCP:
         cmx_midi_out_qcp(pme->m_ciStart.ph, pme->m_wVolume, (sint15)(pme->m_wPan - 64), 
                          (cmx_midi_out_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                          pUser);
         break;
#endif // defined(FEATURE_MIDI_OUT_QCP)
#endif // defined(FEATURE_MIDI_OUT)

#if defined(FEATURE_CMX_RAW_PLAYBACK)
      case OEMCMX_TYPE_AUDFMT_PLAY_CODEC:
         cmx_audfmt_play_codec(pme->m_ciStart.ph, pme->m_pCodecSpec, 
                               (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                               pUser);
                        
         break;
#endif //defined(FEATURE_CMX_RAW_PLAYBACK)

#ifdef FEATURE_MULTISEQUENCER
      case OEMCMX_TYPE_AUDFMT_PLAY_MULTI:
         cmx_audfmt_play_multi(pme->m_ciStart.ph, pme->m_pMultiParam, 
                               (cmx_audfmt_play_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                               pUser);
         break;
#endif //FEATURE MULTISEQUENCER

#if defined(FEATURE_PCM_REC)
      case OEMCMX_TYPE_PCM_RECORD:
            cmx_pcm_record(pme->m_ciStart.ph, pme->m_pPCMRecParm,
                           (cmx_cb_func_ptr_type)pme->m_ciStart.dwCB, 
                            pUser);
         break;
#endif // defined(FEATURE_PCM_REC)

      default:
         return EFAILED;
   }

   return SUCCESS; 
}

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

==================================================================*/
static int OEMMedia_Stop(OEMINSTANCE h)
{
   OEMMedia *           pme = (OEMMedia *)h;
   cmx_cb_func_ptr_type pfn = (cmx_cb_func_ptr_type)pme->m_ciStatus.dwCB;
   void *               pUser = (void *)pme->m_ciStatus.dwUserData;


   switch (pme->m_ciStart.nType)
   {
      case OEMCMX_TYPE_AUDFMT_PLAY: // Fall thru...
      case OEMCMX_TYPE_AUDFMT_RINGER: // Fall thru...
      case OEMCMX_TYPE_AUDFMT_PLAY_CODEC:
         cmx_audfmt_stop(pfn, pUser);
         break;

      case OEMCMX_TYPE_QCP_RECORD:
         cmx_qcp_record_stop(pfn, pUser);
         break;

      case OEMCMX_TYPE_MIDI_OUT_MSG:
         // No effect.
         break;

#if defined(FEATURE_MIDI_OUT_QCP)
      case OEMCMX_TYPE_MIDI_OUT_QCP:
         cmx_midi_out_qcp_stop((void *)pme->m_dwChannel, pfn, pUser);
         break;
#endif // defined(FEATURE_MIDI_OUT_QCP)

#ifdef FEATURE_MULTISEQUENCER
      case OEMCMX_TYPE_AUDFMT_PLAY_MULTI:
         cmx_audfmt_sequence_cmd(pme->m_pSequence, pme->m_pSeqParam, 
                                 pfn, pUser);
         break;
#endif // FEATURE_MULTISEQUENCER

#ifdef FEATURE_PCM_REC
      case OEMCMX_TYPE_PCM_RECORD:
         cmx_pcm_record_stop(pme->m_pPCMRecParm->link, pfn, pUser);
         break;
#endif // FEATURE_PCM_REC

      default:
         return EFAILED;
   }

   return SUCCESS;
}

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

==================================================================*/
static int OEMMedia_PauseResume(OEMINSTANCE h, boolean bPause)
{
   OEMMedia *           pme = (OEMMedia *)h;
   cmx_cb_func_ptr_type pfn = (cmx_cb_func_ptr_type)pme->m_ciStatus.dwCB;
   void *               pUser = (void *)pme->m_ciStatus.dwUserData;

   switch (pme->m_ciStart.nType)
   {
      case OEMCMX_TYPE_AUDFMT_PLAY: // Fall thru...
      case OEMCMX_TYPE_AUDFMT_RINGER:
         if (bPause)
            cmx_audfmt_pause(pfn, pUser);
         else
            cmx_audfmt_resume(pfn, pUser);
         break;

      case OEMCMX_TYPE_QCP_RECORD:
         if (bPause)
            cmx_qcp_record_pause(pfn, pUser);
         else
            cmx_qcp_record_resume(pfn, pUser);
         break;

      case OEMCMX_TYPE_MIDI_OUT_MSG:
         // No effect.
         break;

#if defined(FEATURE_MIDI_OUT_QCP)
      case OEMCMX_TYPE_MIDI_OUT_QCP:
         if (bPause)
            cmx_midi_out_qcp_pause(pfn, pUser);
         else
            cmx_midi_out_qcp_resume(pfn, pUser);
         break;
#endif // defined(FEATURE_MIDI_OUT_QCP)

#ifdef FEATURE_MULTISEQUENCER
      case OEMCMX_TYPE_AUDFMT_PLAY_MULTI:
         cmx_audfmt_sequence_cmd(pme->m_pSequence, pme->m_pSeqParam, 
                                 pfn, pUser);
         break;
#endif // FEATURE_MULTISEQUENCER

#ifdef FEATURE_PCM_REC
      case OEMCMX_TYPE_PCM_RECORD:
         if (bPause)
            cmx_pcm_record_pause(pme->m_pPCMRecParm->link, pfn, pUser);
         else
            cmx_pcm_record_resume(pme->m_pPCMRecParm->link, pfn, pUser);
         break;
#endif // FEATURE_PCM_REC

      default:
         return EFAILED;
   }

   return SUCCESS;
}

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

==================================================================*/
static int OEMMedia_Seek(OEMINSTANCE h, AEEMediaSeek eSeek, int32 lTimeMS)
{
   OEMMedia *           pme = (OEMMedia *)h;
   cmx_cb_func_ptr_type pfn = (cmx_cb_func_ptr_type)pme->m_ciStatus.dwCB;
   void *               pUser = (void *)pme->m_ciStatus.dwUserData;

   if (eSeek != MM_SEEK_CURRENT)
      return EUNSUPPORTED;

   switch (pme->m_ciStart.nType)
   {
      case OEMCMX_TYPE_AUDFMT_PLAY: // Fall thru...
      case OEMCMX_TYPE_AUDFMT_RINGER:
         if (lTimeMS < 0)
            cmx_audfmt_rewind(-1*lTimeMS, pfn, pUser);
         else
            cmx_audfmt_fforward(lTimeMS, pfn, pUser);
         break;

#ifdef FEATURE_MULTISEQUENCER
      case OEMCMX_TYPE_AUDFMT_PLAY_MULTI:
         cmx_audfmt_sequence_cmd(pme->m_pSequence, pme->m_pSeqParam, 
                                 pfn, pUser);
         break;
#endif // FEATURE_MULTISEQUENCER

      default:
         return EFAILED;
   }

   return SUCCESS;
}

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

==================================================================*/
static int OEMMedia_SetParm(OEMINSTANCE h, int16 nParmID, int32 p1, int32 p2, int32 p3, boolean bLocal)
{ 
   OEMMedia *           pme = (OEMMedia *)h;
   cmx_cb_func_ptr_type pfn;
   void *               pUser;
   int                  nErr = SUCCESS;

   // Process MIDI_DEVICE open/close which may not require object instance.
#if defined(FEATURE_MIDI_OUT)
   if (OEMCMX_ID_MIDI_DEVICE == nParmID)
   {
      boolean     bOpen = (boolean)p1;
      int         eADEC = (int)p2;
      CMXInfo *   pci = (CMXInfo *)p3;

      if (bLocal)
         return SUCCESS;

      pfn = pci ? (cmx_cb_func_ptr_type)pci->dwCB : NULL;
      pUser = pci ? (void *)pci->dwUserData : NULL;

      if (bOpen)
#if defined(FEATURE_BREW_CMX_V3)
         cmx_midi_out_open_adec_format((cmx_adec_mode_enum_type)eADEC, pfn, pUser);
#else
         cmx_midi_out_open(pfn, pUser);
#endif // defined(FEATURE_BREW_CMX_V3)
      else
         cmx_midi_out_close(pfn, pUser);

      return SUCCESS;
   }
#endif // defined(FEATURE_MIDI_OUT_QCP)

   if (!pme)
      return SUCCESS;

   pfn = (cmx_cb_func_ptr_type)pme->m_ciStatus.dwCB;
   pUser = (void *)pme->m_ciStatus.dwUserData;

   switch (nParmID)
   {
      case OEMCMX_ID_TYPE:
         if (!bLocal)
            break;

         if (p1)
            MEMCPY(&pme->m_ciStart, (CMXInfo *)p1, sizeof(CMXInfo));

         if (OEMCMX_TYPE_AUDFMT_PLAY == pme->m_ciStart.nType)
               pme->m_eType = (int16)p2;
         else if (OEMCMX_TYPE_AUDFMT_RINGER == pme->m_ciStart.nType)
         {
            pme->m_eType = (int16)p2;
            pme->m_dwPauseMS = (uint32)p3;
         }
         else if (OEMCMX_TYPE_QCP_RECORD == pme->m_ciStart.nType)
         {
            pme->m_pQCPRecParm = (cmx_qcp_rec_para_type *)p2;
            pme->m_bReverse = (boolean)p3;
         }
#if defined(FEATURE_CMX_RAW_PLAYBACK)
         else if (OEMCMX_TYPE_AUDFMT_PLAY_CODEC == pme->m_ciStart.nType)
            pme->m_pCodecSpec = (cmx_codec_spec_type *)p2;
#endif // FEATURE_CMX_RAW_PLAYBACK
#ifdef FEATURE_MULTISEQUENCER
         else if (OEMCMX_TYPE_AUDFMT_PLAY_MULTI == pme->m_ciStart.nType)
         {
            pme->m_pMultiParam = (cmx_audfmt_multi_param_type *)p2;
         }
#endif // FEATURE_MULTISEQUENCER         

#ifdef FEATURE_PCM_REC
         else if (OEMCMX_TYPE_PCM_RECORD == pme->m_ciStart.nType)
         {
            pme->m_pPCMRecParm = (cmx_pcm_rec_para_type *)p2;
         }
#endif // FEATURE_PCM_REC

         else
            nErr = EBADPARM;
         break;

      case OEMCMX_ID_STATUS_CB:
         if (!bLocal)
            break;
         if (p1)
            MEMCPY(&pme->m_ciStatus, (CMXInfo *)p1, sizeof(CMXInfo));
         break;


      case OEMCMX_ID_TOTALTIME:
      {
         CMXInfo *   pci = (CMXInfo *)p1;

         if (bLocal)
            break;

         if (pci && OEMCMX_TYPE_AUDFMT_PLAY == pci->nType)
         {
            cmx_audfmt_get_time(pci->ph, 
                                (cmx_audfmt_time_cb_func_ptr_type)pci->dwCB, 
                                (void *)pci->dwUserData);
         }
         else
            nErr = EBADPARM;
         break;
      }

      case OEMCMX_ID_VOLUME:
         pme->m_wVolume = (uint16)p1;
         if (bLocal)
            break;

#if defined(FEATURE_MIDI_OUT_QCP)
         if (OEMCMX_TYPE_MIDI_OUT_QCP == pme->m_ciStart.nType)
            cmx_midi_out_qcp_volume((void *)pme->m_dwChannel, pme->m_wVolume, pfn, pUser);
         else
#endif // defined(FEATURE_MIDI_OUT_QCP)
            nErr = EUNSUPPORTED;
         break;
         
      case OEMCMX_ID_PAN:
         pme->m_wPan = (uint16)p1;
         if (bLocal)
            break;

         if (OEMCMX_TYPE_AUDFMT_PLAY == pme->m_ciStart.nType || OEMCMX_TYPE_AUDFMT_RINGER == pme->m_ciStart.nType)
            cmx_audfmt_pan((uint32)pme->m_wPan, pfn, pUser);
#if defined(FEATURE_MIDI_OUT_QCP)
         else if (OEMCMX_TYPE_MIDI_OUT_QCP == pme->m_ciStart.nType)
            cmx_midi_out_qcp_pan((void *)pme->m_dwChannel, (sint15)pme->m_wPan, pfn, pUser);
#endif // defined(FEATURE_MIDI_OUT_QCP)
         else
            nErr = EUNSUPPORTED;
         break;

      case OEMCMX_ID_TEMPO:
         if (bLocal)
            break;

         if (OEMCMX_TYPE_AUDFMT_PLAY == pme->m_ciStart.nType || OEMCMX_TYPE_AUDFMT_RINGER == pme->m_ciStart.nType)
            cmx_audfmt_tempo((uint32)p1, pfn, pUser);
         else
            nErr = EUNSUPPORTED;
         break;

      case OEMCMX_ID_TUNE:
         if (bLocal)
            break;

         if (OEMCMX_TYPE_AUDFMT_PLAY == pme->m_ciStart.nType || OEMCMX_TYPE_AUDFMT_RINGER == pme->m_ciStart.nType)
            cmx_audfmt_tune((uint32)p1, pfn, pUser);
         else
            nErr = EUNSUPPORTED;
         break;

      case OEMCMX_ID_CHANNEL:
         if (!bLocal)
            break;

         pme->m_dwChannel = (uint32)p1;
         break;

      case OEMCMX_ID_DATA_RESPONSE:
         if (bLocal)
            break;
         else
         {
            CMXDataRequest *  pReq = (CMXDataRequest *)p1;
            uint8 *           pBuffer = (uint8 *)p2;
            uint32            dwBufSize = (uint32)p3;

            pReq->pfnDataReq(CMX_SUCCESS, pBuffer, dwBufSize, pReq->pServerUserData);
         }
         
         break;

#ifdef FEATURE_MULTISEQUENCER
      case OEMCMX_ID_SEQUENCE:
         pme->m_pSequence = (void*)p1;
         pme->m_pSeqParam = (cmx_audfmt_seq_param_type *)p2;
         if (bLocal)
            break;
           
         cmx_audfmt_sequence_cmd(pme->m_pSequence, pme->m_pSeqParam, 
                                 pfn, pUser);
         break;
#endif // FEATURE_MULTISEQUENCER

#ifdef FEATURE_PCM_REC
      case OEMCMX_ID_LINK:
         pme->m_pPCMRecParm->link = (cmx_pcm_rec_link_type)p1;
#endif // FEATURE_PCM_REC

      default:
         nErr = EFAILED;
   }
   
   return SUCCESS;
}

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

==================================================================*/
static int  OEMMedia_GetParm(OEMINSTANCE h, int16 nParmID, int32 * pP1, int32 * pP2, int32 * pP3)
{
   return EUNSUPPORTED; 
}

#endif // defined(FEATURE_BREW_MULTIMEDIA)
