]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - pasdk/test_dsp/framework/audioStreamOutIo.c
PASDK-577:Add experimental code for setting CLKXDIV in setCheckRateX
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / framework / audioStreamOutIo.c
2 /*
3 Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
4 All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35 /*
36  *  ======== audioStreamOutIo.c ========
37  */
39 #include <string.h> // for memset
40 #include <xdc/runtime/Log.h>
41 #include <xdc/runtime/System.h>
42 #include <xdc/std.h>
44 #include "mcasp_cfg.h"
45 #include "ioConfig.h"    //TODO: remove this header
46 #include "ioBuff.h"
47 #include "ioPhy.h"
48 #include "ioData.h"
50 #include "pafsio_ialg.h"
51 #include "stdasp.h"
52 #include "asperr.h"
54 #include "audioStreamProc_common.h"
55 #include "audioStreamOutProc.h"
56 #include "audioStreamOutIo.h"
58 #define DEC_OUTNUMBUF_MAP(X) \
59       pP->poutNumBufMap[z]->map[(X) >= pP->poutNumBufMap[z]->length ? 0 : (X)]
61 //#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
63 extern Ptr hMcaspTxChan;
64 extern Int d10Initialized;
67 // Select Output devices
68 Int asopSelectDevices(
69     const PAF_SIO_Params *pOutCfg, 
70     PAF_AST_IoOut *pOut
71 )
72 {
73     mcaspLLDconfig *pReqLldCfg;
74     Ptr mcaspChanHandle;
75     Aud_STATUS status;
76     UInt postedEvents;    
78     if ((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) 
79     {
80         return ASOP_IO_ERR_IO_UNINIT;
81     }
83     // Deactivate currently active Output device
84     if (pOut->hMcaspChan != NULL)
85     {
86         // check McASP LLD control API
87         mcaspControlChan(pOut->hMcaspChan, MCASP_CHAN_RESET, NULL);
88         // Delete McASP LLD channel
89         status = mcaspDeleteChan(pOut->hMcaspChan);
90         if (status != Aud_EOK)
91         {
92             Log_info0("asopSelectDevices(): McASP channel deletion failed!\n");
93             return ASOP_IO_ERR_MCASP_CFG;
94         }
95         
96         // Clear (drop) already posted Output data events
97         postedEvents = Event_getPostedEvents(gAsotEvtHandle);
98         while ((postedEvents & Evt_Id_AsotTxMcaspEdma) != 0)
99         {
100             Event_pend(gAsotEvtHandle, Event_Id_NONE, Evt_Id_AsotTxMcaspEdma, 0);
101             postedEvents = Event_getPostedEvents(gAsotEvtHandle);
102         }        
103         
104         pOut->hMcaspChan = NULL;            // reset active McASP LLD handle
105         pOut->pLldCfg->hMcaspChan = NULL;   // reset McASP LLD handle for active McASP LLD configuration
106         pOut->pLldCfg = NULL;               // reset pointer to active McASP LLD configuration
107     }
109     // Activate requested device
110     if (pOutCfg != NULL)
111     {
112         //
113         // Device other than OutNone selected
114         //
115         
116         pReqLldCfg = (mcaspLLDconfig *)pOutCfg->sio.pConfig;
117         if (pReqLldCfg->hMcaspChan == NULL) 
118         {
119             // Create McASP LLD channel
120             mcaspChanHandle = NULL;
121             status = mcasplldChanCreate(pReqLldCfg, &mcaspChanHandle);
122             if (status != Aud_EOK) {
123                 Log_info0("asopSelectDevices(): McASP channel creation failed!\n");
124                 return ASOP_IO_ERR_MCASP_CFG;
125             }
127             pReqLldCfg->hMcaspChan = mcaspChanHandle;   // set McASP LLD handle for requested McASP LLD configuration
128             pOut->pLldCfg = pReqLldCfg;                 // set pointer to active McASP LLD configuration
129             pOut->hMcaspChan = pReqLldCfg->hMcaspChan;  // set active McASP LLD handle
130             
131             // configure stride according to selected McASP LLD configuration
132             pOut->stride = pReqLldCfg->mcaspChanParams->noOfSerRequested * 
133                 pReqLldCfg->mcaspChanParams->noOfChannels;
134                 
135             pOut->rateX = 1.; // intialize rateX
136         }
137         else
138         {
139             return ASOP_IO_ERR_INV_STATE;
140         }
141     }
142     else
143     {
144         //
145         // OutNone device selected
146         //
147         
148         pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
149         pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
150     }
152     return ASOP_IO_SOK;
155 // Check if Output device SIO selection changed
156 Int checkOutDevSioSelUpdate(
157     const PAF_ASOT_Params *pP, 
158     PAF_ASOT_Config *pAsotCfg,
159     Int z, 
160     Bool *pOutDevSelUpdate
163     PAF_AST_Config *pAstCfg;
164     
165     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
167     if ((z < OUTPUT1) || (z >= OUTPUTN))
168     {
169         *pOutDevSelUpdate = FALSE;
170         return ASOP_IO_ERR_INV_PARAMS;
171     }
172     
173     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
175     return ASOP_IO_SOK;
178 // Check if any Output device SIO selection changed
179 Int checkAnyOutDevSioSelUpdate(
180     const PAF_ASOT_Params *pP, 
181     PAF_ASOT_Config *pAsotCfg,
182     Bool *pOutDevSelUpdate
185     PAF_AST_Config *pAstCfg;
186     Int outDevSelUpdate;
187     Int z;
188     
189     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
191     outDevSelUpdate = FALSE;
192     for (z=OUTPUT1; z < OUTPUTN; z++) 
193     {
194         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
195         {
196             outDevSelUpdate = TRUE;
197             break;
198         }
199     }
200     
201     *pOutDevSelUpdate = outDevSelUpdate;
203     return ASOP_IO_SOK;
206 // -----------------------------------------------------------------------------
207 // ASOT Decoding Function Helper - SIO Driver Change
208 //
209 //   Name:      PAF_ASOT_setCheckRateX
210 //   Purpose:   Decoding Function for reinitiating output.
211 //   From:      AST Parameter Function -> decodeInfo1
212 //              AST Parameter Function -> decodeInfo2
213 //   Uses:      See code.
214 //   States:    x
215 //   Return:    Error number in standard form (0 on success).
216 //   Trace:     None.
217 //
219 /* 0: set, 1: check, unused for now. --Kurt */
220 Int asopSetCheckRateX(
221     const PAF_ASOT_Params *pP, 
222     const PAF_ASOT_Patchs *pQ, 
223     PAF_ASOT_Config *pAsotCfg, 
224     Int check
227     PAF_AST_Config *pAstCfg;
228     PAF_AST_IoOut  *pOut;
229     float rateX;
230     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
231     Int z;                              /* output counter */
232     Int zx;                             /* output re-counter */
233     Int getVal;
234     int inputRate, inputCount, outputRate, outputCount;
235     Int zMD;
236     Int zMI;
237     Int zMS;
238     Int zE, zX;
240     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
241     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
242     
243     zMD = pAstCfg->masterDec;
244     zMS = pAstCfg->masterStr;
245     zMI = pP->zone.master;
247     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
248     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
249     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
250         inputRate, PAF_SAMPLERATEHZ_INV);
252     for (z=OUTPUT1; z < OUTPUTN; z++) 
253     {
254         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
255         {
256             // determine associated encoder
257             zE = z;
258             for (zX = ENCODE1; zX < ENCODEN; zX++) 
259             {
260                 if (pP->outputsFromEncodes[zX] == z) 
261                 {
262                     zE = zX;
263                     break;
264                 }
265             }
267             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
268             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
269             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
270                 outputRate, PAF_SAMPLERATEHZ_STD);
271             if ((rateI > 0) && (rateO > 0))
272             {
273                 rateX = rateO /* std */ * rateI /* inv */;
274             }
275             else if (inputCount != 0)
276             {
277                 rateX = (float)outputCount / inputCount;
278             }
279             else
280             {
281                 return ASPERR_INFO_RATERATIO;
282             }
284 #if 0 // FL, New IO: add similar thing to be figured out     
285             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
286             if (getVal == DOBERR_RATECHANGE) 
287             {
288                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
289                 {
290                     if (pAstCfg->xOut[zx].hTxSio)
291                     {
292                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
293                     }
294                 }
296                 // this forces an exit from the calling state machine which will
297                 // eventually call startOutput which calls setCheckRateX for all outputs
298                 // and so it is ok, in the presence of a rate change on any output, to
299                 // exit this loop /function early.
300                 return ASPERR_INFO_RATECHANGE;
301             }
302             else if (getVal != SYS_OK)
303             {
304                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
305             }
306 #endif // FL, New IO
307             if (pOut->rateX != rateX)
308             {
309                 UInt32 regVal;
310                 
311                 //
312                 // "Proof on concept" code for McASP LLD API to change bit clock divider.
313                 //
315                 // Initialize divider value.
316                 // This works for AHCLKX input from HDMI & sample rate = 44.1,48,88.2,96,192 kHz.
317                 divider = 2;
318                 
319                 // Update divider based on calculated rateX
320                 divider /= rateX;
322                 // Experimental code: directly write CLKXDIV
323                 regVal = *(volatile UInt32 *)0x23400B0;
324                 regVal &= ~0x1F; // mask off CLKXDIV bits
325                 //regVal |= 7; // set CLKXDIV for 48 kHz
326                 //regVal |= 3; // set CLKXDIV for 96 kHz
327                 //regVal |= 1; // set CLKXDIV for 192 kHz
328                 regVal |= (divider-1); // set CLKXDIV
329                 *(volatile UInt32 *)0x23400B0 = regVal;
330                 
331                 pOut->rateX = rateX;
332             }
333         }
334     }
336     return ASOP_IO_SOK;
337 } //asopSetCheckRateX
339 // -----------------------------------------------------------------------------
340 // ASOT Decoding Function Helper - SIO Driver Start
341 //
342 //   Name:      PAF_ASOT_startOutput
343 //   Purpose:   Decoding Function for initiating output.
344 //   From:      AST Parameter Function -> decodeInfo1
345 //   Uses:      See code.
346 //   States:    x
347 //   Return:    Error number in standard or SIO form (0 on success).
348 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
349 //              * State information as per parent.
350 //              * SIO control errors.
351 //
352 Int asopStartOutput(
353     const PAF_ASOT_Params *pP,
354     const PAF_ASOT_Patchs *pQ,
355     PAF_ASOT_Config *pAsotCfg
358     PAF_AST_Config *pAstCfg;
359     PAF_AST_IoOut  *pOut;
360     Int as;                     /* Audio Stream Number (1, 2, etc.) */
361     Int z;                      /* output counter */
362     Int nbufs;
363     Int zE, zS, zX;
364     Int zMD;
365     PAF_SIO_IALG_Obj    *pObj;
366     PAF_SIO_IALG_Config *pAlgConfig;
367     ioPhyCtl_t ioPhyCtl;
370     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
371     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
372     as = pAstCfg->as;
373     zMD = pAstCfg->masterDec;
375     for (z=OUTPUT1; z < OUTPUTN; z++)
376     {
377         if (pOut[z].hIoPhy)
378         {
379             // determine associated encoder and stream
380             zE = z;
381             zS = z;
382             for (zX = ENCODE1; zX < ENCODEN; zX++)
383             {
384                 if (pP->outputsFromEncodes[zX] == z)
385                 {
386                     zE = zX;
387                     zS = pP->streamsFromEncodes[zE];
388                     break;
389                 }
390             }
392             // FL, New IO: add similar thing to be figured out
393 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
394 #if 0
395             // if device selected and valid then enable stat tracking if
396             // required and start clocking
397             if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
398             {
399                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
400                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
401                 if (errno)
402                 {
403                     TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
404                     SIO_idle(pAstCfg->xOut[z].hTxSio);
405                     if (!errno)
406                     {
407                         errno = ASPERR_DEVOUT + errme;
408                     }
409                 }
410             }
411 #endif            
413             // Set sample count so that DOB knows how much data to send
414             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
415                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
417 #if 1 // FL, New IO: add similar thing to be figured out
418             // Update framework Phy transfer size
419             pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
420             // Update IO Phy transfer size
421             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
422             ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
423             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
424             // Update IO Buff delay to match Phy transfer size
425             ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
426 #endif
428             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
429             {
430                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
431                 pAlgConfig = &pObj->config;
432                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
433                     pAlgConfig->pMemRec[0].size);
434             }
436             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
437             // decoder. How should we handle the sourceProgram for multiple decoders?
438             // Override as needed
439             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
440             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
441             {
442                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
443             }
444             //JXTODO: add similar thing to be figured out
445             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
447             //JXTODO: data transfer start to be moved to output task state machine
448             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
449                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
450             {
451                 SIO_idle(pAstCfg->xOut[z].hTxSio);
452                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
453                 return errno;
454             } */
456             //JXTODO: add similar thing to be figured out
457 #if 0
458             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
459                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
460             {
461                 errno = (errno & 0xff) | ASPERR_MUTE;
462                 /* convert to sensical errno */
463                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
464                 return errno;
465             }
466             else
467             {
468                 pAstCfg->xOut[z].outBufStatus.audio
469                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
470             }
471 #endif
472             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
473         }
474     }
476     return ASOP_IO_SOK;
477 } /* asopStartOutput */
479 // -----------------------------------------------------------------------------
480 // ASOT Decoding Function Helper - SIO Driver Stop
481 //
482 //   Name:      PAF_ASOT_stopOutput
483 //   Purpose:   Decoding Function for terminating output.
484 //   From:      AST Parameter Function -> decodeProcessing
485 //              AST Parameter Function -> decodeComplete
486 //   Uses:      See code.
487 //   States:    x
488 //   Return:    Error number in standard or SIO form (0 on success).
489 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
490 //              * SIO control errors.
491 //
492 Int asopStopOutput(
493     const PAF_ASOT_Params *pP, 
494     const PAF_ASOT_Patchs *pQ, 
495     PAF_ASOT_Config *pAsotCfg
498     PAF_AST_Config *pAstCfg;
499     PAF_AST_IoOut  *pOut;
500     Int as;                     /* Audio Stream Number (1, 2, etc.) */
501     Int z;                      /* output counter */
502     Int errno, getVal;
503     Int zS, zX;
504     PAF_SIO_IALG_Obj    *pObj;
505     PAF_SIO_IALG_Config *pAlgConfig;
507     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
508     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
509     as = pAstCfg->as;
510     (void)as;  // clear compiler warning in case not used with tracing disabled
512     errno = ASOP_IO_SOK;
513     for (z=OUTPUT1; z < OUTPUTN; z++) 
514     {
515         if (pOut[z].hIoPhy) 
516         {
517             // determine associated encoder and stream
518             zS = z;
519             (void)zS;
520             for (zX = ENCODE1; zX < ENCODEN; zX++) 
521             {
522                 if (pP->outputsFromEncodes[zX] == z) 
523                 {
524                     zS = pP->streamsFromEncodes[zX];
525                     break;
526                 }
527             }
529 #if 0 // FL, New IO: add similar thing to be figured out            
530             // Mute output before audio data termination in the usual case,
531             // where such termination is due to decode error or user command.
532             // Identification of this as the usual case is provided by the
533             // "decode processing" state machine.
534             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
535                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
536                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
537             {
538                 if (!errno) 
539                 {
540                     errno = (getVal & 0xff) | ASPERR_MUTE;
541                     /* convert to sensical errno */
542                 }
543                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
544             }
546             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
547             
548             // Terminate audio data output, truncating (ignore) or flushing
549             // (play out) final samples as per (1) control register set by
550             // the user and (2) the type of audio data termination:
552 #if 0
553             // This form is not used because driver support for truncating
554             // data is not supported for internal clocks, although it is
555             // for external clocks.
556             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
557                 pC->xOut[z].outBufStatus.flush
558                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
559                 ? 1 : 0);
560             /* UNTESTED */
561 #else
562             // This form should be used when driver support for truncating
563             // data is supported for both internal and external clocks.
564             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
565                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
566                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
567                 ? 1 : 0);
568             /* TESTED */
569 #endif
571             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
573             if (!errno)
574             {
575                 errno = getVal;
576             }
578             // Mute output after audio data termination in a special case,
579             // where such termination is due to processing of a final frame
580             // or user command. Identification of this as a special case is
581             // provided by the "decode processing" state machine.
582             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
583                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
584                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
585             {
586                 if (!errno) 
587                 {
588                     errno = (getVal & 0xff) | ASPERR_MUTE;
589                     /* convert to sensical errno */
590                 }
591                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
592             }
594             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
595 #endif // FL, New IO
597             // zero output buffers
598             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
599             pAlgConfig = &pObj->config;
600             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
601         } //pAstCfg->xOut[z].hTxSio
602     }//OUTPUT
604     return errno;
605 } //asopStopOutput
607 /*===========================================================================
608  * Initialize I/O components for output processing
609 ============================================================================*/
610 Int asopIoCompsInit(
611     Int16 strAfSampleCount,     // stream audio frame sample count
612     PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
613     PAF_AST_IoOut *pOutIo       // pointer to Output IO
616     ioBuffParams_t ioBuffParams;
617     ioPhyParams_t  ioPhyParams;
619     if (pOutIo->hMcaspChan != NULL)
620     {
621         // Initialize I/O BUFF and I/O PHY components for output task
622         ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
623         // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
624         // This ensures no split buffers will be allocated on Output buffer wrap.
625         ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
626             (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
627         ioBuffParams.sync         = IOBUff_READ_SYNC;
628         ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
629         if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
630         {
631             return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
632         }
634         ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
635         ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
636         ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
637         ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
638         if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
639         {
640             return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
641         }
643         pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
644         
645         pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
646         pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
647         pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
648     }
649     
650     return ASOP_IO_SOK;
651 } /* asopIoCompsInit */
653 /*======================================================================================
654  *  This function checks whether the I/O physical layer has been initialized
655  *====================================================================================*/
656 Bool asopIoPhyCheckInit(Void)
658     if (!d10Initialized)
659         return FALSE;
660     else 
661         return TRUE;
664 /*======================================================================================
665  *  I/O physical layer prime operation required by McASP LLD
666  *====================================================================================*/
667 Void asopIoPhyPrime(
668     PAF_AST_IoOut *pOut
671     Int32        count;
673     pOut->numPrimeXfers = NUM_PRIME_XFERS;
675     for (count = 0; count < pOut->numPrimeXfers; count++)
676     {
677         ioPhyXferSubmit(pOut->hIoPhy);
678     }
679 } /* asipIoPhyPrime */
681 // Initialize Output buffer configuration
682 Int asopInitOutBufConfig(
683     PAF_AST_OutBuf *pOutBuf, 
684     PAF_AST_IoOut *pOutIo
687     PAF_OutBufConfig *pOutBufCfg;
688     ioBuffHandle_t hIoBuff;
689     ioBuffInfo_t outBuffInfo;
690     
691     pOutBufCfg = &pOutBuf->outBufConfig;
692     hIoBuff = pOutIo->hIoBuff;
693     
694     pOutBufCfg->stride = pOutIo->stride;
695     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
696     pOutBufCfg->precision = 24;
697     
698     ioBuffGetInfo(hIoBuff, &outBuffInfo);
699     pOutBufCfg->base.pLgInt = outBuffInfo.base;
700     pOutBufCfg->sizeofBuffer = outBuffInfo.size;
701     
702     pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
703     
704     return ASOP_IO_SOK;
707 Int asopGetOutBufPtrs(
708     PAF_AST_IoOut *pOutIo,
709     size_t writeSize
712     void *buff1, *buff2;
713     size_t size1, size2;
714     Int status;
716     status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
717                                 &buff1, &size1, &buff2, &size2);
718     if (status == IOBUFF_ERR_OVERFLOW)
719     {
720         pOutIo->errIoBuffOvrCnt++;
721         //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
723         // skip processing since output buffer overflows
724         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
725     }
726     else if (status == IOBUFF_ERR_UNDERFLOW)
727     {
728         pOutIo->errIoBuffUndCnt++;
729         //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
731         // already underflows and remain in underflow
732     }
733     
734     if ((buff2 != NULL) || (size2 != 0))
735     {
736         // Two buffers allocated indicates split buffer allocation on buffer wrap.
737         pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
738     }
740     // save buffer pointers & sizes for later write complete
741     pOutIo->buff1 = buff1;
742     pOutIo->size1 = size1;
743     pOutIo->buff2 = buff2;
744     pOutIo->size2 = size2;
746     return ASOP_IO_SOK;
749 #if 0
750 // Update Output buffer configuration.
751 // This is needed for proper operation of PCM encoder.
752 Int asopUpdateOutBufConfig(
753     PAF_AST_OutBuf *pOutBuf, 
754     PAF_AST_IoOut *pOutIo
757     PAF_OutBufConfig *pOutBufCfg;
758     ioBuffHandle_t hIoBuff;
759     ioBuffInfo_t outBuffInfo;
760     void *buff1, *buff2;
761     size_t size1, size2, total_write_size;
762     Int status;
764     pOutBufCfg = &pOutBuf->outBufConfig;
765     hIoBuff = pOutIo->hIoBuff;
767     // FL, New IO: original code can change these values in every DOB issue
768     //  Need to determine if this is required or not.
769     pOutBufCfg->stride = pOutIo->stride;
770     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
771     pOutBufCfg->precision = 24;
772     
773     //JXTODO: to replace hard coded write size
774     // Get write pointers of output memory pool
775     total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
776     status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
777         &buff1, &size1, &buff2, &size2);
778     if (status == IOBUFF_ERR_OVERFLOW) 
779     {
780         pOutIo->errIoBuffOvrCnt++;
781         //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
783         // skip processing since output buffer overflows        
784         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
785     }
786     else if (status == IOBUFF_ERR_UNDERFLOW) 
787     {
788         pOutIo->errIoBuffUndCnt++;
789         //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
790         
791         // already underflows and remain in underflow
792     }
793 #if 0
794     // Update Output buffer pointer for Encoder
795     pOutBufCfg->pntr.pLgInt = buff1;
796     if ((buff2 != NULL) || (size2 != 0))
797     {
798         // buff2 should always be NULL for Output & size2 should always be 0 for Output.
799         // Track this here.
800         pOutIo->ioBuffBuf2AllocCnt++; // debug
801     }
802 #endif
803     // save buffer pointers & sizes for later write complete
804     pOutIo->buff1 = buff1;
805     pOutIo->size1 = size1;
806     pOutIo->buff2 = buff2;
807     pOutIo->size2 = size2;
808     
809     return ASOP_IO_SOK;
811 #endif
813 // Mark Output buffers write complete
814 Int asopMarkOutBuffsWriteComplete(
815     PAF_AST_OutBuf *pOutBuf, 
816     PAF_AST_IoOut *pOutIo
819     ioBuffHandle_t hIoBuff;
820     void *buff1, *buff2;
821     size_t size1, size2;
822     
823     // get buffer pointers & sizes from previous IO Buff write allocation
824     buff1 = pOutIo->buff1;
825     size1 = pOutIo->size1;
826     buff2 = pOutIo->buff2; // this should always be NULL for Output
827     size2 = pOutIo->size2; // this should always be 0 for Output
828     
829     hIoBuff = pOutIo->hIoBuff;
830     
831     ioBuffWriteComplete(hIoBuff, buff1, size1);
833     if (buff2 != NULL) 
834     {
835         ioBuffWriteComplete(hIoBuff, buff2, size2);
836     }
837     
838     return ASOP_IO_SOK;
841 /*======================================================================================
842  *  This function starts an I/O PHY transfer for output
843  *====================================================================================*/
844 Void asopPhyTransferStart(
845     PAF_AST_IoOut *pOut
848     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
849     {
850         //mcaspTxReset();
851         //mcaspTxCreate();
852         //pOut->hMcaspChan = hMcaspTxChan;
853         System_abort("\nMcASP for output underruns! %d!\n");
854     }
855     else 
856     {
857         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
858         {
859             // Output buffer underflows!
860             System_abort("\nOutput buffer underflows!\n");
861         }
862         else {
863             // Output buffer operates normally
864             ;
865         }
866     }
869 /* nothing past this point */