Fixed problem of input task being stuck when input stream stops:
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / framework / audioStreamInpProcNewIO.c
index f46ffd1b074c6178ed6969d44d416acce986a41e..4d95b8b4bd579144d7b9c4d114d1a59a57157707 100644 (file)
@@ -42,7 +42,10 @@ All rights reserved.
 #include "procsdk_audio_typ.h"
 #include "audioStreamInpProc.h"
 #include "audioStreamProc_common.h"
+#include "aspMsg_common.h"
+#include "aspMsg_master.h"
 #include "asperr.h"
+#include "common.h"
 
 #include "audk2g.h"
 #include "audk2g_audio.h"
@@ -53,6 +56,7 @@ All rights reserved.
 #include "ioData.h"
 
 
+#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
 
 #define SYNC_PC_MASK         0x1F
 #define SYNC_SUBTYPE_MASK    0x700
@@ -63,6 +67,7 @@ All rights reserved.
 
 #define IEC_HEADER_LENGTH    4
 
+#define INPUT_SWITCH_HANGOVER 8
 
 //table needed until PAF_SOURCE is reordered to match IEC numbering
 const SmUns IECpafSource[23] =
@@ -109,7 +114,7 @@ extern XDAS_Int32 D10_RxControl(const void *pD10RxParams,
  */
 int asipPrepareProcessing();
 int asipIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo);
-void asipProcInit(PAF_AST_IoInp  *pInp);
+void asipProcInit(PAF_AST_IoInp  *pInp, asipDecProc_t *pDec);
 void asipIoPhyPrime(PAF_AST_IoInp *pInpIo);
 void asipPhyTransferPend(void);
 void asipPhyTransferComplete(PAF_AST_IoInp * pInpIo);
@@ -119,7 +124,9 @@ Int asipUpdateInputStatus(const void *pRxParams, PAF_InpBufStatus *pStatus,
                           PAF_InpBufConfig *pInpBuf);
 
 //Int asipDecideSource(const PAF_ASIT_Params *pP, PAF_AST_Config *pAstCfg, asipDecProc_t *pDec);
-Int asipProcessing(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp);
+Int asipProcessing(const PAF_ASIT_Params *pP,
+                   const PAF_ASIT_Patchs *pQ,
+                   PAF_ASIT_Config *pAsitCfg);
 void asipErrorHandling(PAF_AST_Config *pAstCfg, int asipErrno);
 
 /*
@@ -127,13 +134,15 @@ void asipErrorHandling(PAF_AST_Config *pAstCfg, int asipErrno);
  */
 extern Semaphore_Handle asipSemRx;
 extern PAF_ASIT_Config gPAF_ASIT_config;
+extern const MdUns iecFrameLength[23];
+extern Ptr hMcaspRxChan;
+
 
 enum
 {
     ASIP_SOURCE_DETECTION,
-    ASIP_DECODE_BITSTREAM,
+    ASIP_DECODE,
     ASIP_SWITCH_TO_PCM,
-    ASIP_DECODE_PCM
 };
 
 enum
@@ -142,6 +151,8 @@ enum
     ASIP_INPUT_PROCESSING
 };
 
+
+
 #define ASIP_DEBUG
 
 #ifdef ASIP_DEBUG
@@ -179,6 +190,8 @@ Int asipErrno;
 Int inputReadyForProcessing;
 #endif
 
+    Int firstTimeInit = TRUE;
+
     Log_info0("Enter taskAsipFxn()");
 
     taskAsipFxnInit(pP, pQ);  // initialization of input task
@@ -188,7 +201,6 @@ Int inputReadyForProcessing;
     //
     pAsitCfg = &gPAF_ASIT_config;       // initialize pointer to task configuration
     pAstCfg  = pAsitCfg->pAstCfg;       // pointer to AST common (shared) configuration
-    pInp     = pAsitCfg->pIoInp;        // pointer to input I/O components
 
     /* Set Audio Stream Number (1, 2, etc.) */
     as = pAstCfg->as;
@@ -196,10 +208,8 @@ Int inputReadyForProcessing;
     //
     // Determine decoder and stream indices associated with the master input
     //
-    zMI = pP->zone.master;
-
-    pInp[zMI].numPrimeXfers = NUM_PRIME_XFERS;
-    //asipInitDebug(&pInp[zMI]);
+    zMI  = pP->zone.master;
+    pInp = &pAsitCfg->pIoInp[zMI];        // pointer to input I/O components
 
     for (z=STREAM1; z < STREAMN; z++)
     {
@@ -208,130 +218,12 @@ Int inputReadyForProcessing;
 
     TRACE_TERSE0("TaskAsip: Entering Main Loop.");
 
-#if 0
-    // Wait until input device is ready - change this to event based scheduling
-    asipErrno = 0;
-    while (!inputReadyForProcessing)
-    {
-        // Indicate decoder no decoding yet
-        pP->fxns->sourceDecode(pP, pQ, pAsitCfg, PAF_SOURCE_NONE);
-
-        Task_sleep(5);  // 5 system tick, or 5 msec. Should remove this later when implementing event based scheduling.
-
-        inputReadyForProcessing = asipPrepareProcessing(pP, pQ, pAsitCfg, &asipErrno);
-
-        if(asipErrno) {
-            asipErrorHandling(pAstCfg, asipErrno);
-        }
-    }
-
-    // .....................................................................
-    // At this point we have an enabled input and want to decode something.
-    // If no decoder selected then do nothing. Need to reset the sourceProgram, since
-    // when no decoder is selected there are no calls to IB
-    asipErrno = asipIoCompsInit(&pAstCfg->xInp[zMI], &pInp[zMI]);
-    if(asipErrno) {
-        printf("ASIP IO components init error!\n");
-        exit(0);
-    }
-
-    asipProcInit(&pInp[zMI]);
-
-    // start I/O physical layer by priming McASP LLD for input
-    asipIoPhyPrime(&pInp[zMI]);
-
-    //
-    // Main processing loop
-    //
-    asipErrno = 0;
-    for (;;)
-    {
-        // Pending on I/O PHY transfer
-        asipPhyTransferPend();
-
-        // Marks I/O PHY transfer and I/O BUFF write complete
-        asipPhyTransferComplete(&pInp[zMI]);
-
-        // Main function to process input data
-        asipErrno = asipProcessing(pAstCfg, &pInp[zMI]);
-
-        // Start next transfer
-        asipPhyTransferStart(&pInp[zMI]);
-
-        if(asipErrno) {
-            asipErrorHandling(pAstCfg, asipErrno);
-        }
-    }
-#endif
-
-#if 0
-    //
-    // Main processing loop
-    //
-    asipLoopCount1 = 0;
-    asipLoopCount2 = 0;
-    asipErrno = 0;
-    inputReadyForProcessing = FALSE;
-    for (;;)
-    {
-        asipLoopCount1++;
-
-        if(asipErrno) {
-            asipErrorHandling(pAstCfg, asipErrno);
-
-            inputReadyForProcessing = FALSE;
-        }
-
-        // Wait until input device is ready - change this to event based scheduling
-        if(!inputReadyForProcessing) {
-            // Indicate decoder no decoding yet
-            pP->fxns->sourceDecode(pP, pQ, pAsitCfg, PAF_SOURCE_NONE);
-
-            // 5 system tick, or 5 msec. Should remove this later when implementing
-            // event based scheduling.
-            Task_sleep(5);
-
-            inputReadyForProcessing = asipPrepareProcessing(pP, pQ, pAsitCfg, &asipErrno);
-
-            if (inputReadyForProcessing) {
-                // Input is ready for processing, so we initialize the I/O components
-                asipIoCompsInit(&pAstCfg->xInp[zMI], &pInp[zMI]);
-
-                // Initialize ASIP processing
-                asipProcInit(&pInp[zMI]);
-
-                // Start I/O physical layer by priming McASP LLD for input
-                asipIoPhyPrime(&pInp[zMI]);
-            }
-            else {
-                // Input is not ready, so go back to the beginning of the loop
-                continue;
-            }
-        }  /* if(!inputReadyForProcessing) */
-
-        // Pending on I/O PHY transfer
-        asipPhyTransferPend();
-
-        // Marks I/O PHY transfer and I/O BUFF write complete
-        asipPhyTransferComplete(&pInp[zMI]);
-
-        // Main function to process input data
-        asipErrno = asipProcessing(pAstCfg, &pInp[zMI]);
-
-        // Start next transfer
-        asipPhyTransferStart(&pInp[zMI]);
-
-        asipLoopCount2++;
-    }  // for (;;)
-#endif
-
     //
     // Main processing loop
     //
     asipLoopCount1 = 0;
     asipLoopCount2 = 0;
     asipErrno = 0;
-    inputReadyForProcessing = FALSE;
     pInp->asipState = ASIP_INPUT_PREPARATION;
 
     for (;;)
@@ -349,16 +241,22 @@ Int inputReadyForProcessing;
             Task_sleep(5);
 
             inputReadyForProcessing = asipPrepareProcessing(pP, pQ, pAsitCfg, &asipErrno);
-
             if (inputReadyForProcessing) {
-                // Input is ready for processing, so we initialize the I/O components
-                asipIoCompsInit(&pAstCfg->xInp[zMI], &pInp[zMI]);
+                // Input is ready for processing, so we initialize the I/O components.
+                // Note that the I/O components init. and I/O PHY prime are performed only at the
+                // first time. This should be changed later - init. and prime should be done whenever
+                // input interface has changed.
+                if(firstTimeInit) {
+                    asipIoCompsInit(&pAstCfg->xInp[zMI], pInp);
 
-                // Initialize ASIP processing
-                asipProcInit(&pInp[zMI]);
+                    // Start I/O physical layer by priming McASP LLD for input
+                    asipIoPhyPrime(pInp);
+
+                    firstTimeInit = FALSE;
+                }
 
-                // Start I/O physical layer by priming McASP LLD for input
-                asipIoPhyPrime(&pInp[zMI]);
+                // Initialize ASIP processing
+                asipProcInit(pInp, &pAsitCfg->inpDec);
 
                 pInp->asipState = ASIP_INPUT_PROCESSING;
             }
@@ -369,13 +267,13 @@ Int inputReadyForProcessing;
             asipPhyTransferPend();
 
             // Marks I/O PHY transfer and I/O BUFF write complete
-            asipPhyTransferComplete(&pInp[zMI]);
+            asipPhyTransferComplete(pInp);
 
             // Main function to process input data
-            asipErrno = asipProcessing(pAstCfg, &pInp[zMI]);
+            asipErrno = asipProcessing(pP, pQ, pAsitCfg);
 
             // Start next transfer
-            asipPhyTransferStart(&pInp[zMI]);
+            asipPhyTransferStart(pInp);
 
             if(asipErrno) {
                 asipErrorHandling(pAstCfg, asipErrno);
@@ -392,10 +290,6 @@ Int inputReadyForProcessing;
 
 }  /* taskAsipFxn */
 
-extern const MdUns iecFrameLength[23];
-extern Ptr hMcaspRxChan;
-#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
-
 
 /*===========================================================================
  * ASIP processing preparation
@@ -512,7 +406,7 @@ int asipIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo)
 
     ioPhyParams.ioBuffHandle    = pInpIo->hIoBuff;
     ioPhyParams.xferFrameSize   = INPUT_FRAME_SIZE_DEF;
-    ioPhyParams.mcaspChanHandle = hMcaspRxChan;
+    ioPhyParams.mcaspChanHandle = pInpIo->hMcaspChan;
     ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_WRITE;
     if(ioPhyInit(pInpIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) {
         return (-1);   // to remove magic number
@@ -531,9 +425,10 @@ int asipIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo)
         return (-1);   // to remove magic number
     }
 
+    pInpIo->numPrimeXfers  = NUM_PRIME_XFERS;
     pInpIo->phyXferSize    = ioPhyParams.xferFrameSize;
-    pInpIo->switchHangOver = 0;
-    pInpIo->syncState      = IODATA_SYNC_NONE;
+    //pInpIo->switchHangOver = 0;
+    pInpIo->preSyncState   = IODATA_SYNC_NONE;
 
     return 0;
 } /* asipIoCompsInit */
@@ -541,11 +436,13 @@ int asipIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo)
 /*======================================================================================
  *  This function initializes ASIP processing
  *====================================================================================*/
-void asipProcInit(PAF_AST_IoInp  *pInp)
+void asipProcInit(PAF_AST_IoInp  *pInp, asipDecProc_t *pDec)
 {
     pInp->swapData = SWAP_INPUT_DATA;
     pInp->asipProcState = ASIP_SOURCE_DETECTION;
-    pInp->switchHangOver = 0;
+    //pInp->switchHangOver = 0;
+
+    pDec->initDone = FALSE;
 }
 
 /*======================================================================================
@@ -599,11 +496,11 @@ void asipMcaspCallback(void* arg, MCASP_Packet *mcasp_packet)
 /*======================================================================================
  *  This function checks if McASP Rx for input overruns
  *====================================================================================*/
-int asipCheckMcaspRxOverrun(void)
+int asipCheckMcaspRxOverrun(Ptr mcaspChanHandle)
 {
     Mcasp_errCbStatus mcaspErrStat;
 
-    mcaspControlChan(hMcaspRxChan, Mcasp_IOCTL_CHAN_QUERY_ERROR_STATS, &mcaspErrStat);
+    mcaspControlChan(mcaspChanHandle, Mcasp_IOCTL_CHAN_QUERY_ERROR_STATS, &mcaspErrStat);
 
     return (mcaspErrStat.isRcvOvrRunOrTxUndRunErr);
 }
@@ -622,7 +519,7 @@ void asipMcaspRxRestart(void)
  *====================================================================================*/
 void asipPhyTransferStart(PAF_AST_IoInp *pInpIo)
 {
-    if(asipCheckMcaspRxOverrun()) {
+    if(asipCheckMcaspRxOverrun(pInpIo->hMcaspChan)) {
 #ifdef ASIP_DEBUG
         pInpIo->numInputOverrun++;
 #endif
@@ -671,19 +568,23 @@ Int asipSelectDevices(const PAF_ASIT_Patchs *pQ, PAF_AST_IoInp *pInp)
 #endif
         if(status != Audk2g_EOK) {
             Log_info0("audk2g_AudioSelectClkSrc Failed!\n");
+            return ASIP_ERR_D10_CFG;
         }
         audk2g_delay(50000); // Without delay between these 2 calls system aborts.
 
         /* Initialize McASP module */
         status = mcaspAudioConfig(); //defined in newio\fw\mcasp_cfg.c
         if(status != Audk2g_EOK) {
-            TRACE_TERSE0("McASP Configuration Failed!\n");
+            Log_info0("McASP Configuration Failed!\n");
+            return ASIP_ERR_MCASP_CFG;
         }
 
+        pInp->hMcaspChan = hMcaspRxChan;
         d10Initialized = 1;
     }
 
     /////////////// TODO: HW interface selection and initialization //////////////
+    ////// to add what PAF_ASIT_selectDevices() does /////////
 #ifdef IO_HW_INTERFACE
     pInp->pRxParams = pQ->devinp->x[IO_HW_INTERFACE];
 #else
@@ -717,8 +618,9 @@ Int asipUpdateInputStatus(const void *pRxParams, PAF_InpBufStatus *pStatus,
     asipErrno = D10_RxControl(pRxParams,
                           (Uns)PAF_SIO_CONTROL_GET_INPUT_STATUS,
                           (Arg) &inputStatus);
-    if (asipErrno)
+    if (asipErrno) {
         return asipErrno;
+    }
     pStatus->sampleRateData = inputStatus.sampleRateData;
     pStatus->sampleRateMeasured = inputStatus.sampleRateMeasured;
     pStatus->nonaudio = inputStatus.nonaudio;
@@ -775,58 +677,314 @@ Int asipUpdateInputStatus(const void *pRxParams, PAF_InpBufStatus *pStatus,
     return 0;
 }
 
+/*==============================================================================
+ * After SYNC is found, i.e. either bitstream preamble is detected or it times
+ * out to PCM, update input buffer config and I/o components accordingly.
+ ==============================================================================*/
+Int asipUpdateIoComps(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp,
+                      ioDataAutoDetStat_t *autoDetStatus)
+{
+    Int sourceConfig;
+    Int zMD, deliverZeros;
+    int frameLength;
+    PAF_InpBufConfig *pBufConfig;
+    Audk2g_STATUS mcaspStatus;
+    ioPhyCtl_t  ioPhyCtl;
+
+    zMD = pAstCfg->masterDec;
+    pBufConfig = &pAstCfg->xInp[zMD].inpBufConfig;
+
+    // Get the configured source
+    sourceConfig = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceSelect),
+                                          GATEMP_INDEX_DEC);
+
+    if(autoDetStatus->syncState == IODATA_SYNC_PCM) {
+        // Bitstream preamble is not found and it times out -> assume this is PCM
+        deliverZeros = autoDetStatus->deliverZeros;
+        if (sourceConfig == PAF_SOURCE_PCM || sourceConfig == PAF_SOURCE_DSD1 ||
+            sourceConfig == PAF_SOURCE_DSD2 || sourceConfig == PAF_SOURCE_DSD3) {
+            // set to one -- ensures that PCM decode calls made before data is
+            // available will result in zero output.
+            // (mostly needed for PA15 since, currently, all other frameworks
+            // require a frame of data before the first decode call.
+            deliverZeros = TRUE;  // override deliverZeros returned by ioDataControl
+        }
+
+        // update input buffer config structure
+        pBufConfig->deliverZeros  = deliverZeros;
+        pBufConfig->sizeofElement = WORD_SIZE_PCM;
+        pBufConfig->frameLength   = pBufConfig->lengthofData = INPUT_FRAME_LENGTH;
+
+        // reconfigure McASP LLD to transfer 32-bit unpacked data
+        //mcaspStatus = mcaspRecfgWordWidth(pInp->hMcaspChan, Mcasp_WordLength_32);
+        //if(mcaspStatus != Audk2g_EOK) {
+        //    return ASIP_ERR_MCASP_CFG;
+        //}
+
+        // Change I/O PHY transfer size to PCM frame size
+        pInp->phyXferSize = (INPUT_FRAME_LENGTH)*(WORD_SIZE_PCM);
+
+        // Adjust I/O BUFF delay and read pointer - to make sure read pointers always point to
+        // PCM data from 1st I2S (out of 4 for HDMI 4xI2S)
+        // Adjust delay and don't mark input buffer as read complete
+        ioBuffAdjustDelay(pInp->hIoBuff, pInp->phyXferSize);
+
+        // Stop swapping data
+        pInp->swapData = FALSE;
+
+    } /* IODATA_SYNC_PCM */
+
+    if(autoDetStatus->syncState == IODATA_SYNC_BITSTREAM) {
+        // Change I/O PHY transfer size to be the same as the bitstream frame size
+        uint_least16_t pc = autoDetStatus->bitStreamInfo & SYNC_PC_MASK; //0x001F
+        frameLength = iecFrameLength[pc];
+
+        // update input buffer config structure
+        pBufConfig->sizeofElement = WORD_SIZE_BITSTREAM;
+        pBufConfig->frameLength   = frameLength;
+        pBufConfig->lengthofData  = frameLength - IEC_HEADER_LENGTH;
+
+/*
+        if (pc == 0x11 && DTSHDSubType == 3 && (PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD] <=48000.0))
+            pDevExt->sourceProgram = PAF_SOURCE_DXP;    // LBR is 23
+*/
+
+/*        if (pc == 1)
+            pDevExt->elementSize = 4288;
+        else if (pc == 0x11) {
+            pDevExt->frameLength = (pDevExt->pIECFrameLength[pc] << DTSHDSubType);
+            pDevExt->lengthofData = pDevExt->frameLength;
+        }
+*/
+
+        // Change I/O PHY transfer size to bitstream frame size
+        pInp->phyXferSize = frameLength*WORD_SIZE_BITSTREAM;
+    }
+
+    pBufConfig->stride = INPUT_STRIDE;   // common for PCM and bitstream
+
+    //JXTODO: decide what to do with hRxSio
+    pAstCfg->xInp[zMD].hRxSio = pInp->hIoData; //temporary - does ARM use hRxSio or just check if it is not NULL?
+    pAstCfg->xInp[zMD].pInpBuf = &(pAstCfg->xInp[zMD].inpBufConfig);
+
+    // Update I/O PHY transfer size accordingly
+    ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
+    ioPhyCtl.params.xferFrameSize = pInp->phyXferSize;
+    ioPhyControl(pInp->hIoPhy, &ioPhyCtl);
+
+    return ASIP_NO_ERR;
+} /* asipUpdateIoComps */
+
+void asipUpdateInpBufConfig(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp)
+{
+    PAF_InpBufConfig *pBufConfig;
+    ioDataCtl_t ioDataCtl;
+
+    /* Get information for reading input data */
+    ioDataCtl.code = IODATA_CTL_GET_INPBUFFINFO;
+    ioDataControl(pInp->hIoData, &ioDataCtl);
+
+    if(ioDataCtl.param.dataReadInfo.frameSize != pInp->phyXferSize) {
+        // Fatal error!
+        TRACE_VERBOSE0("TaskAsip: error in updating I/O");
+        SW_BREAKPOINT;
+    }
+
+    pBufConfig = &(pAstCfg->xInp[pAstCfg->masterDec].inpBufConfig);
+
+    //JXTODO: do we need to gate here? - No, since ARM won't read until it receives message
+    //key = GateMP_enter(gateHandle);
+
+    pBufConfig->base.pVoid   = ioDataCtl.param.dataReadInfo.buffBase;
+    pBufConfig->sizeofBuffer = ioDataCtl.param.dataReadInfo.buffSize;
+    pBufConfig->pntr.pSmInt  = ioDataCtl.param.dataReadInfo.startAddress;
+
+    // Leave the gate
+    //GateMP_leave(gateHandle, key);
+}
+
+/*==============================================================================
+ * Decide source after SYNC is found, i.e. either bitstream preamble is detected
+ * or it times out to PCM.
+ ==============================================================================*/
+Int asipDecideSource(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp,
+                     ioDataAutoDetStat_t *autoDetStatus)
+{
+    Int sourceConfig, sourceSelect, sourceProgram;
+    Int zMD;
+    char asipMsgBuf[ASP_MSG_BUF_LEN];
+
+    // Get the configured source
+    zMD = pAstCfg->masterDec;
+    sourceConfig = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceSelect), GATEMP_INDEX_DEC);
+
+    if(autoDetStatus->syncState == IODATA_SYNC_PCM) {
+        if (sourceConfig == PAF_SOURCE_DSD1 || sourceConfig == PAF_SOURCE_DSD2 ||
+            sourceConfig == PAF_SOURCE_DSD3) {
+            sourceProgram = sourceConfig;
+        }
+        else {
+            sourceProgram = PAF_SOURCE_PCM;
+        }
+    }
+
+    if(autoDetStatus->syncState == IODATA_SYNC_BITSTREAM) {
+        uint_least16_t pc = autoDetStatus->bitStreamInfo & SYNC_PC_MASK; //0x001F
+        sourceProgram = IECpafSource[pc];
+    }
+
+    // write the decided source program to memory
+    sharedMemWriteInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceProgram), sourceProgram, GATEMP_INDEX_DEC);
+
+    // now that we have some input classification, and possibly an outstanding
+    // input frame, we determine whether or not to call decodeProcessing and with
+    // what decAlg.
+    sourceSelect = PAF_SOURCE_NONE;
+
+    switch (sourceConfig)
+    {
+        // If autodetecting, decoding everything, and input is something
+        // (i.e. bitstream or PCM) then decode.
+        case PAF_SOURCE_AUTO:
+            if (sourceProgram >= PAF_SOURCE_PCM)  {
+                sourceSelect = sourceProgram; // use whatever from autodet
+            }
+            break;
+
+        // If autodetecting, decoding only PCM, and input is PCM then decode.
+        case PAF_SOURCE_PCMAUTO:
+            if (sourceProgram == PAF_SOURCE_PCM) {
+                sourceSelect = sourceProgram;  // only expect autodet to give PAF_SOURCE_PCM, otherwise set to NONE
+            }
+            break;
+
+        // If autodetecting, decoding only bitstreams, and input is a bitstream then decode.
+        case PAF_SOURCE_BITSTREAM:
+            if (sourceProgram >= PAF_SOURCE_AC3) {
+                sourceSelect = sourceProgram;
+            }
+            break;
+
+        // If autodetecting, decoding only DTS, and input is DTS then decode.
+        case PAF_SOURCE_DTSALL:
+            switch (sourceProgram)
+            {
+                case PAF_SOURCE_DTS11:
+                case PAF_SOURCE_DTS12:
+                case PAF_SOURCE_DTS13:
+                case PAF_SOURCE_DTS14:
+                case PAF_SOURCE_DTS16:
+                case PAF_SOURCE_DTSHD:
+                    sourceSelect = sourceProgram;
+                    break;
+            }
+            break;
+
+        // All others, e.g., force modes, fall through to here.
+        // If user made specific selection then program must match select.
+        // (NB: this compare relies on ordering of PAF_SOURCE)
+        default:
+            sourceSelect = sourceConfig;
+            if ((sourceSelect >= PAF_SOURCE_PCM) && (sourceSelect <= PAF_SOURCE_N)) {
+                if (sourceProgram != sourceSelect) {
+                    sourceSelect = PAF_SOURCE_NONE;
+                }
+            }
+            break;
+    }
+
+    // if we didn't find any matches then skip
+    if (sourceSelect == PAF_SOURCE_NONE) {
+        TRACE_VERBOSE0("TaskAsip: no matching source type, continue");
+        return ASIP_ERR_NO_MATCHING_SOURCE;
+    }
+
+#ifndef PCM_LOOPBACK_TEST
+    // send source select message to slave
+    *(Int32 *)&asipMsgBuf[0] = sourceSelect;
+    if(AspMsgSend(ASP_SLAVE_DEC_SOURCE_SELECT, ASP_MASTER_DEC_SOURCE_SELECT_DONE,
+                  asipMsgBuf, NULL) != ASP_MSG_NO_ERR) {
+        TRACE_VERBOSE0("TaskAsip: error in sending SOURCE_SELECT message");
+        SW_BREAKPOINT;
+    }
+#endif
+
+    pInp->sourceSelect  = sourceSelect;
+    pInp->sourceProgram = sourceProgram;
+
+    return ASIP_NO_ERR;
+} /* asipDecideSource */
+
+
+Int asipBypassIoData(PAF_AST_IoInp *pInp)
+{
+    // When switching to PCM, McASP RFMT register will be modified,
+    // which will cause all 0's in one McASP LLD transfer. This will
+    // be detected as loss of SYNC by auto detection. To prevent that,
+    // skip I/O DATA process for hangover period so that this all 0's
+    // frame will not be seen by auto-detection. Also, playing out PCM
+    // needs to be skipped as well, to prevent from playing out garbage
+    // (16-bit packed data).
+    void *buff1, *buff2;
+    size_t size1, size2;
+
+    // Get read pointers (or sub-buffers) of the input buffer
+    if (ioBuffGetReadPtrs(pInp->hIoBuff, pInp->phyXferSize,
+                          &buff1, &size1, &buff2, &size2)
+        == IOBUFF_ERR_UNDERFLOW) {
+        //printf("Input buffer underflows during switch hangover!\n");
+        return ASIP_ERR_SWITCH_TO_PCM;
+    }
+
+    ioBuffReadComplete(pInp->hIoBuff, buff1, size1);
+
+    if(buff2 != NULL) {
+        ioBuffReadComplete(pInp->hIoBuff, buff2, size2);
+    }
+
+    return ASIP_NO_ERR;
+}
 
 /*=============================================================================
  *  Main function of ASIP processing
  *============================================================================*/
-#define INPUT_SWITCH_HANGOVER 8
+Int asipProcessing(const PAF_ASIT_Params *pP,
+                   const PAF_ASIT_Patchs *pQ,
+                   PAF_ASIT_Config *pAsitCfg)
 
-Int asipProcessing(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp)
 {
-    int autoDetstatus, syncState;
+    PAF_AST_Config  *pAstCfg;
+    int ioDataStatus, asipStatus, zMI;
+    ioDataAutoDetStat_t autoDetStatus;
     Audk2g_STATUS mcaspStatus;
-
     ioDataCtl_t ioDataCtl;
     ioPhyCtl_t  ioPhyCtl;
+    PAF_AST_IoInp *pInp;            /* Input I/O components */
 
-    if(pInp->asipProcState == ASIP_SWITCH_TO_PCM) {
-        // When switching to PCM, McASP RFMT register will be modified,
-        // which will cause all 0's in one McASP LLD transfer. This will
-        // be detected as loss of SYNC by auto detection. To prevent that,
-        // skip I/O DATA process for hangover period so that this all 0's
-        // frame will not be seen by auto-detection. Also, playing out PCM
-        // needs to be skipped as well, to prevent from playing out garbage
-        // (16-bit packed data).
-        void *buff1, *buff2;
-        size_t size1, size2;
-
-        // Get read pointers (or sub-buffers) of the input buffer
-        if (ioBuffGetReadPtrs(pInp->hIoBuff, pInp->phyXferSize,
-                              &buff1, &size1, &buff2, &size2)
-            == IOBUFF_ERR_UNDERFLOW) {
-            //printf("Input buffer underflows during switch hangover!\n");
-            return ASIP_ERR_SWITCH_TO_PCM;
-        }
-
-        ioBuffReadComplete(pInp->hIoBuff, buff1, size1);
+    pAstCfg = pAsitCfg->pAstCfg;
+    zMI  = pAstCfg->masterDec;
+    pInp = &pAsitCfg->pIoInp[zMI]; // pointer to input I/O components
 
-        if(buff2 != NULL) {
-            ioBuffReadComplete(pInp->hIoBuff, buff2, size2);
+    if(pInp->asipProcState == ASIP_SWITCH_TO_PCM) {
+        // Bypass I/O data processing due to McASP LLD work around
+        // (refer to comments inside the function)
+        asipStatus = asipBypassIoData(pInp);
+        if(asipStatus != ASIP_NO_ERR) {
+            return asipStatus;
         }
     }
     else {
         // Perform auto-detection when not switching
-        autoDetstatus = ioDataProcess(pInp->hIoData);
-        if(autoDetstatus == IODATA_ERR_IOBUF_UNDERFLOW) {
+        ioDataStatus = ioDataProcess(pInp->hIoData);
+        if(ioDataStatus == IODATA_ERR_IOBUF_UNDERFLOW) {
             // Input buffer underflows - no action is needed
-            //printf("Input buffer underflows.\n");
             pInp->numUnderflow += 1;
 
             // Return since there is no enough data to process
             return ASIP_NO_ERR;
         }
-        else if(autoDetstatus != IODATA_NO_ERR) {
-            // Something run happens: print error log and return
+        else if(ioDataStatus != IODATA_NO_ERR) {
+            // Something is wrong: print error log and return
             //printf("IODATA processing error!\n");
             return ASIP_ERR_AUTO_DETECION;
         }
@@ -835,7 +993,7 @@ Int asipProcessing(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp)
             ioDataCtl.code = IODATA_CTL_GET_AUTODET_STATUS;
             ioDataControl(pInp->hIoData, &ioDataCtl);
 
-            syncState = ioDataCtl.param.autoDetStats.syncState;
+            autoDetStatus = ioDataCtl.param.autoDetStats;
         }
     }
 
@@ -845,55 +1003,47 @@ Int asipProcessing(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp)
         // zero out the output buffer
         rxDecodePlayZero(pInp);
 
-        ioDataReadComplete(pInp->hIoData);
-
-        if(syncState == IODATA_SYNC_BITSTREAM || syncState == IODATA_SYNC_PCM) {
-            // Decide input source after SYNC is found, i.e. either
-            // bitstream preamble is detected or it times out to PCM.
-            //sourceSelect = asipDecideSource(pP, pAstCfg, &decProc);
-
-        }
+        if(   autoDetStatus.syncState == IODATA_SYNC_BITSTREAM
+           || autoDetStatus.syncState == IODATA_SYNC_PCM) {
+            // Update I/O components and input buffer config
+            asipUpdateIoComps(pAstCfg, pInp, &autoDetStatus);
 
-        if(syncState == IODATA_SYNC_BITSTREAM) {
-            // Change I/O PHY transfer size to be the same as the bitstream frame size
-            int frameSize;
-            uint_least16_t pc = ioDataCtl.param.autoDetStats.bitStreamInfo & SYNC_PC_MASK; //0x001F
-            frameSize = iecFrameLength[pc] * WORD_SIZE_BITSTREAM;
-
-            ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
-            ioPhyCtl.params.xferFrameSize = frameSize;
-            ioPhyControl(pInp->hIoPhy, &ioPhyCtl);
-            pInp->phyXferSize = ioPhyCtl.params.xferFrameSize;
-
-            pInp->asipProcState = ASIP_DECODE_BITSTREAM;
-            pInp->numFrameReceived = 1;
-        }
-        else if(syncState == IODATA_SYNC_PCM) {
-            // reconfigure McASP LLD to transfer 32-bit unpacked data
-            mcaspStatus = mcaspRecfgWordWidth(hMcaspRxChan, Mcasp_WordLength_32);
-            if(mcaspStatus != Audk2g_EOK) {
-                return ASIP_ERR_MCASP_CFG;
+            // Decide input source and inform decoder
+            asipStatus = asipDecideSource(pAstCfg, pInp, &autoDetStatus);
+            if(asipStatus != ASIP_NO_ERR) {
+                return asipStatus;
             }
+            else {
+                // set to unknown so that we can ensure, for IOS purposes, that sourceDecode = NONE
+                // iff we are in this top level state machine and specifically not in decodeProcessing
+#ifndef PCM_LOOPBACK_TEST
+                pP->fxns->sourceDecode(pP, pQ, pAsitCfg, PAF_SOURCE_UNKNOWN);
+#endif
 
-            // Change I/O PHY transfer size to PCM frame size
-            ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
-            ioPhyCtl.params.xferFrameSize = INPUT_FRAME_SIZE_PCM;
-            ioPhyControl(pInp->hIoPhy, &ioPhyCtl);
-            pInp->phyXferSize = ioPhyCtl.params.xferFrameSize;
-
-            // Adjust I/O BUFF delay and read pointer - to make sure read pointers always point to
-            // PCM data from 1st I2S (out of 4 for HDMI 4xI2S)
-            // Adjust delay and don't mark input buffer as read complete
-            ioBuffAdjustDelay(pInp->hIoBuff, pInp->phyXferSize);
-
-            // Stop swapping data
-            pInp->swapData = FALSE;
-
-            // Go to transition state to switch to PCM
-            pInp->asipProcState = ASIP_SWITCH_TO_PCM;
-            pInp->switchHangOver = INPUT_SWITCH_HANGOVER;
+                if(autoDetStatus.syncState == IODATA_SYNC_BITSTREAM) {
+                    // Input is bit stream: go to decoding
+                    pInp->asipProcState = ASIP_DECODE;
+                    //pInp->numFrameReceived = 1;
+                }
+                else  {
+                    // Input is PCM: stop swapping data
+                    pInp->swapData = FALSE;
+
+                    // Reconfigure McASP LLD to transfer 32-bit unpacked data
+                    mcaspStatus = mcaspRecfgWordWidth(pInp->hMcaspChan, Mcasp_WordLength_32);
+                    if(mcaspStatus != Audk2g_EOK) {
+                        return ASIP_ERR_MCASP_CFG;
+                    }
+
+                    // Go to transition state to switch to PCM
+                    pInp->asipProcState = ASIP_SWITCH_TO_PCM;
+                    pInp->switchHangOver = INPUT_SWITCH_HANGOVER;
+                    //pInp->numPcmFrameReceived = 0;
+                }
+            }
 
-            pInp->numPcmFrameReceived = 0;
+            pInp->numFrameReceived = 0;
+            pInp->preSyncState = autoDetStatus.syncState;
         }
         else {
             // Source is still unknown - take no action
@@ -901,71 +1051,77 @@ Int asipProcessing(PAF_AST_Config *pAstCfg, PAF_AST_IoInp  *pInp)
         }
         break;
 
-    case ASIP_DECODE_BITSTREAM:
-        if (syncState == IODATA_SYNC_NONE) {
-            // Change I/O PHY transfer size to default
-            ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
-            ioPhyCtl.params.xferFrameSize = INPUT_FRAME_SIZE_DEF;
-            ioPhyControl(pInp->hIoPhy, &ioPhyCtl);
-            pInp->phyXferSize  = ioPhyCtl.params.xferFrameSize;
-
-            pInp->numFrameReceived = 0;
-            pInp->asipProcState  = ASIP_SOURCE_DETECTION;
-        }
-        else {
-            pInp->numFrameReceived += 1;
-
-            rxDecodeBitStream(pInp);
-
-            ioDataReadComplete(pInp->hIoData);
-        }
-        break;
-
     case ASIP_SWITCH_TO_PCM:
         // zero out the output buffer
         rxDecodePlayZero(pInp);
 
         pInp->switchHangOver--;
         if(pInp->switchHangOver == 0) {
-            pInp->asipProcState = ASIP_DECODE_PCM;
-            // send message to decoder
+            pInp->asipProcState = ASIP_DECODE;
         }
         break;
 
-    case ASIP_DECODE_PCM:
-        if (syncState == IODATA_SYNC_NONE) {
-            // reconfigure McASP LLD to receive 16-bit packed bits
-            mcaspStatus = mcaspRecfgWordWidth(hMcaspRxChan, Mcasp_WordLength_16);
-            if(mcaspStatus != Audk2g_EOK) {
-                return ASIP_ERR_MCASP_CFG;
-            }
-
-            // Change I/O PHY transfer size to default
+    case ASIP_DECODE:
+        if(autoDetStatus.syncState == IODATA_SYNC_NONE) {
+            // SYNC lost: change I/O PHY transfer size to default for auto-detection
             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
             ioPhyCtl.params.xferFrameSize = INPUT_FRAME_SIZE_DEF;
             ioPhyControl(pInp->hIoPhy, &ioPhyCtl);
             pInp->phyXferSize  = ioPhyCtl.params.xferFrameSize;
 
-            // Start swapping data
-            pInp->swapData = TRUE;
-            pInp->numPcmFrameReceived = 0;
+            if(pInp->preSyncState == IODATA_SYNC_PCM) {
+                // If it was PCM, reconfigure McASP LLD to receive 16-bit packed bits
+                mcaspStatus = mcaspRecfgWordWidth(pInp->hMcaspChan, Mcasp_WordLength_16);
+                if(mcaspStatus != Audk2g_EOK) {
+                    return ASIP_ERR_MCASP_CFG;
+                }
+
+                // Start swapping data
+                pInp->swapData = TRUE;
+            }
 
-            pInp->asipProcState = ASIP_SOURCE_DETECTION;
+            // Inform decoder to complete decoding previous frame
+            pInp->sourceSelect = PAF_SOURCE_NONE;
+
+            pInp->numFrameReceived = 0;
+            pInp->asipProcState  = ASIP_SOURCE_DETECTION;
         }
         else {
-            pInp->numPcmFrameReceived += 1;
-
-            rxDecodePcm(pInp);
+            pInp->numFrameReceived += 1;    // for debugging
 
-            ioDataReadComplete(pInp->hIoData);
+            // Communicate input stream information to decoder through input buffer configuration
+            asipUpdateInpBufConfig(pAstCfg, pInp);
         }
 
+#ifndef PCM_LOOPBACK_TEST
+        asipStatus = asipDecodeProcessing(pP, pQ, pAsitCfg, pInp->sourceSelect);
+        if(asipStatus != ASIP_NO_ERR) {
+
+            // FL: send dec exit message to slave
+            if( AspMsgSend(ASP_SLAVE_DEC_EXIT, ASP_MASTER_DEC_EXIT_DONE, NULL, NULL)
+                != ASP_MSG_NO_ERR)
+            {
+                TRACE_VERBOSE0("TaskAsip: error in sending DEC_EXIT message");
+                SW_BREAKPOINT;
+            }
+
+            return asipStatus;
+        }
+#else
+        if(autoDetStatus.syncState == IODATA_SYNC_PCM) {
+            rxDecodePcm(pInp);     // for PCM loopback testing
+        }
+#endif
         break;
 
     default:
         break;
     }
 
+    if(pInp->asipProcState != ASIP_SWITCH_TO_PCM) {
+        ioDataReadComplete(pInp->hIoData);
+    }
+
     return 0;
 } /* asipProcessing */