This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Wifi Audio App 8k sample rate delayed playback

Other Parts Discussed in Thread: CC3200SDK, CC3200

Hi,

I am using "wifi_audio_app" provided with SDK CC3200SDK_1.0.0 as starting point. (Added a CLI feature over UART)

My HW is CC3200 launch-xl 3.2 Along with that I have Audio booster daughter card rev 3.0.

I have modified the code to support varied sampling rates of audio with a CLI (cc3200 running a CLI).

I am playing back the audio in the "Microphone" thread. The "Speaker" thread is not running. So when I speak in microphone, I hear it back with a delay.

This delay is OK (~70 ms as seen in DSO) for 32kHz sampling (16bit mono). But this delay increases to almost 800 ms for 8kHz audio sampling.

What do I need to adjust to get ~70 ms delay?

AIC3254 parameters remains the same in both the cases. I achieve different sampling rates by adjusting I2S block's frequency in CC3200.

The parameters that I have adjusted is:

"CB_TRANSFER_SZ"

"PACKET_SIZE".

But it does not help. I am not sending any packet to network. It is plain and simple loopback.

Any help is really appreciated.

Thanks,

Shashi.

  • Hi Shashi,


    Other than above re-configuration for 8KHz, you need to re-configure codec clock (reg 4,5,6,7,11, 12,13,14, 18,19,20 on page 0) in ConfigureAudioCodec() function also.


    Regards,
    Aashish

  • Hi,

    As I mentioned in my query, it is playing it properly. It is just that voice come AFTER 800ms.

    As I know, Codec chip cannot buffer. So the delay cannot be introduced by the Codec chip. But CC3200 can buffer.

    Besides, I can see in the oscilloscope that bit pattern changes at the INPUT to CC3200 as I speak in the mic almost instantly. (Higher bits get set in the 16 bit sample data, indicating voice data update).

    So the delay is probably due to DMA or probably the way circular buffer is maintained.

    Please share your opinion.

    Regards,

    Shashi.

  • Hi Shashi,


    Can you try by reducing PLAY_WATERMARK macro value as it currently set as 30K. The speaker will not start playing until circular buffer have 30K data and in 8KHz case it will be large. We will suggest to set watermark value to 8K.


    Regards,
    Aashish
  • Hi Aashish,

    I set the variable g_uiPlayWaterMark to '1' whenever, GetBufferFilledSize(pTxBuffer) returns more than 128 bytes. After that FillBuffer() is called.
    This is in reference to function "void Microphone( void *pvParameters )".

    So in effectively, PLAY_WATERMARK is 0.

    Also, I have another test case where I speak in my laptop's mic and send it to CC3200 over WiFi (using UDP). The voice data gets played back almost instantly (~100ms).

    So I believe that the problem is in the capture part in CC3200.
    But I am not sure where exactly.

    Regards,
    Shashi.
  • Hi Shashi,


    Please share modified code with us to debug the issue.


    Regards,
    Aashish Bhanawat
  • Calling sequence is same as given in the Audio Sample App.
    I have carved out the clock programming of codec separately for you easy understanding in CodecConfig_Clock(). This function is provided for your understanding.
    Point is that I am making division factor as 32. So that I can control the codec frequency to work for the desired sampling rate just by changing the I2S clock in CC3200.

    Thread is created as Microphone().
    To start the audio capture thread capturing audio and playing back, call TriggerMicThread(). I have tried adjusting chunkSize.
    Other constants are available in the Sample APP and used as is. In case you find trouble, revert to me.

    You can change the sampling rate by selecting one value from the table AudFreqTable[] for AUD_MCLK_FREQ.

    AudioInit() starts all the required threads and inits the codec and i2s. It can be called multiple times.

    ---------------------------------------------------------------------------------------------

    void CodecConfig_Clock()
    {
    CodecPageSelect(0);
    CodecRegWrite(AUD_INTF_SET_REG, 0);
    CodecRegWrite(0x04, BYTE(0000, 0011)); // 0x03
    #define SET_P_R(OnOff, P, R) (((OnOff) << 7) | ((P) << 4) | ((R) << 0))
    CodecRegWrite(0x05, SET_P_R(1, 1, 1)); // 0x94 P=1 R=1
    #define AUD_J_VAL 4
    #define SET_J(J) (J)
    CodecRegWrite(0x06, SET_J(AUD_J_VAL));

    #define SET_D_MSB(D) (((D) & 0x300) >> 8)
    #define SET_D_LSB(D) (((D) & 0x0FF) >> 0)
    #define AUD_D_VAL 0 // 4.0960 // use GUI for Clock interface of AIC3254
    CodecRegWrite(0x07, SET_D_MSB(AUD_D_VAL)); // 0x00 D=0 MSB
    // Clock Setting Register 5
    CodecRegWrite(0x08, SET_D_LSB(AUD_D_VAL)); // 0x00 D=0 LSB

    #define SET_N_DIV(OnOff, N_VAL) (((OnOff) << 7) | ((N_VAL) << 0))
    #define NDAC_DIV_VAL 1
    CodecRegWrite(0x0B, SET_N_DIV(1, NDAC_DIV_VAL)); // 0x8E NDAC = 14

    #define SET_M_DIV(OnOff, M_Val) (((OnOff) << 7) | ((M_Val) << 0))
    #define MDAC_DIV_VAL 1
    CodecRegWrite(0x0C, SET_M_DIV(1, MDAC_DIV_VAL)); // 0x81 MDAC=1


    #define SET_DOSR_MSB(DOSR) (((DOSR) & 0x300) >> 8)
    #define SET_DOSR_LSB(DOSR) (((DOSR) & 0x0FF) >> 0)

    #define AUD_DOSR 128

    CodecRegWrite(0x0D, SET_DOSR_MSB(AUD_DOSR)); // 0x01
    // DAC OSR Setting Register 2, LSB
    CodecRegWrite(0x0E, SET_DOSR_LSB(AUD_DOSR)); // DOSR = 0x180 (384'd) // 0x80

    #define NADC_DIV_VAL NDAC_DIV_VAL
    CodecRegWrite(0x12, SET_N_DIV(0, NADC_DIV_VAL)); /* NADC is powered up and set to 1 */ // 0x95 NADC = 0x15 (21'd)

    #define MADC_DIV_VAL MDAC_DIV_VAL
    CodecRegWrite(0x13, SET_M_DIV(0, MADC_DIV_VAL)); /* MADC is powered up and set to 1 */ // 0x82 MADC=2

    #define AUD_AOSR AUD_DOSR
    CodecRegWrite(0x14, AUD_AOSR); /* AOSR set to 128 */ //0x80 = 128(Use with PRB_R1 to PRB_R6, ADC Filter Type A)
    }

    int AUD_Init(void)
    {
    if( osi_SyncObjCreate(&semAudMicStart) < 0 )
    {
    LOOP_FOREVER();
    }
    if( osi_SyncObjCreate(&semAudSpkrStart) < 0 )
    {
    LOOP_FOREVER();
    }
    return SUCCESS;
    }

    OsiReturnVal_e WaitForMicTrigger(void)
    {
    return osi_SyncObjWait(&semAudMicStart, OSI_WAIT_FOREVER);
    }

    OsiReturnVal_e WaitForSpkrTrigger(void)
    {
    return osi_SyncObjWait(&semAudSpkrStart, OSI_WAIT_FOREVER);
    }

    OsiReturnVal_e TriggerMicThread(void)
    {
    g_ucMicStartFlag = 1;
    return osi_SyncObjSignal(&semAudMicStart);
    }

    OsiReturnVal_e TriggerSpkrThread(void)
    {
    g_ucSpkrStartFlag = 1;
    return osi_SyncObjSignal(&semAudSpkrStart);
    }

    void StopMicThread(void)
    {
    //osi_SyncObjClear(&semAudMicStart);
    g_ucMicStartFlag = 0;
    osi_SyncObjSignal(&semMicDataReady);
    }

    void StopSpkrThread(void)
    {
    //osi_SyncObjClear(&semAudSpkrStart);
    g_ucSpkrStartFlag = 0;
    osi_SyncObjSignal(&semSpeakerDataReady);
    }

    void AudioInit(void)
    {
    int lRetVal;
    //
    // Create RX and TX Buffer
    //
    if( !pTxBuffer )
    {
    if( osi_SyncObjCreate(&semMicDataReady) < 0 )
    {
    LOOP_FOREVER();
    }
    if( osi_SyncObjCreate(&semSpeakerDataReady) < 0 )
    {
    LOOP_FOREVER();
    }
    }

    PRCMPeripheralReset(PRCM_I2S);

    /* Init circ buffer here. This will be called every time audio started. We may need (in future) to
    adjust the buffer size based on sampling rates */
    pTxBuffer = CreateCircularBuffer(INIT_TX_CIRC_BUFF, TX_BUFFER_SIZE);
    if(pTxBuffer == NULL)
    {
    CON_PRINT("Unable to Allocate Memory for Tx Buffer\n\r");
    LOOP_FOREVER();
    }
    pRxBuffer = CreateCircularBuffer(INIT_RX_CIRC_BUFF, RX_BUFFER_SIZE);
    if(pRxBuffer == NULL)
    {
    CON_PRINT("Unable to Allocate Memory for Rx Buffer\n\r");
    LOOP_FOREVER();
    }

    //
    // Initialising the I2C Interface
    //
    lRetVal = I2C_IF_Open(I2C_MASTER_MODE_FST);
    if(lRetVal < 0)
    {
    CON_PRINT("Unable open I2C %d\n\r", lRetVal);
    LOOP_FOREVER();
    }

    //
    // Configure Audio Codec
    //
    ConfigureAudioCodec(CODEC_I2S_WORD_LEN_16);
    CON_PRINT("Audio Codec finished\n\r");

    //
    // Initialize the Audio(I2S) Module
    //
    AudioCapturerInit();
    CON_PRINT("MacASP setup\n\r");

    UDMAInit();
    UDMAChannelSelect(UDMA_CH4_I2S_RX, NULL);
    UDMAChannelSelect(UDMA_CH5_I2S_TX, NULL);

    //
    // Setup the DMA Mode
    //
    SetupPingPongDMATransferTx();
    SetupPingPongDMATransferRx();

    //
    // Setup the Audio In/Out
    //
    lRetVal = AudioCapturerSetupDMAMode(DMAPingPongCompleteAppCB_opt, \
    CB_EVENT_CONFIG_SZ);
    if(lRetVal < 0)
    {
    CON_PRINT("Met with DMA ERROR!!!\n\r");
    LOOP_FOREVER();
    }
    else
    {
    CON_PRINT("DMA Mode set\n\r");
    }
    AudioCaptureRendererConfigure();
    CON_PRINT("Renderer Config\n\r");

    //
    // Start Audio Tx/Rx
    //
    Audio_Start();
    CON_PRINT("Aud start\n\r");

    #if 0
    //
    // Start the Control Task
    //
    lRetVal = ControlTaskCreate();
    CON_PRINT("Ctrl Task\n\r");
    if(lRetVal < 0)
    {
    CON_PRINT("Met with ERROR in Ctrl creation!!!\n\r");
    LOOP_FOREVER();
    }
    #endif
    if( !g_MicTask )
    {
    //
    // Start the Microphone Task
    //
    lRetVal = osi_TaskCreate( Microphone,(signed char*)"MicroPhone", \
    2 * 1024, NULL,
    11, &g_MicTask );
    //CON_PRINT("Microphone Task\n\r");
    if(lRetVal < 0)
    {
    CON_PRINT("Met with ERROR in Microphone creation!!!\n\r");
    LOOP_FOREVER();
    }

    #if 0
    //
    // Start the Speaker Task
    //
    lRetVal = osi_TaskCreate( Speaker, (signed char*)"Speaker", 2 * 1024, \
    NULL, 11, &g_SpeakerTask );
    //CON_PRINT("Speaker Task\n\r");
    if(lRetVal < 0)
    {
    CON_PRINT("Met with ERROR in Speaker creation!!!\n\r");
    LOOP_FOREVER();
    }
    #endif
    }

    }

    void Microphone( void *pvParameters )
    {
    long lRetVal = -1;
    int iBufferFilled;
    int packetSize;
    int chunkSize;

    CON_PRINT("Inside Microphone task\n\r");

    while(1)
    {
    CON_PRINT("Mic Stopped\n\r");
    WaitForMicTrigger();

    chunkSize = 128;

    while(g_ucMicStartFlag)
    {
    iBufferFilled = GetBufferFilledSize(pTxBuffer);
    if(iBufferFilled >= (chunkSize))
    {
    g_uiPlayWaterMark = 1;
    lRetVal = FillBuffer(pRxBuffer,\
    (unsigned char*)(pTxBuffer->pucReadPtr), \
    chunkSize, AUD_COMPRESSION_NONE);
    if(lRetVal < 0)
    {
    CON_PRINT("Unable to fill buffer\n\r");
    LOOP_FOREVER();
    }
    UpdateReadPtr(pTxBuffer, chunkSize);
    }
    }
    }
    }

    const int AudFreqTable[AUD_SAMPLE_MAX] =
    {
    /* AUD_SAMPLE_08p000 = 8000 * 32 (CODEC_SAMPLE_TO_CLK_FREQ_DIV_FACTOR) */
    256000,
    /* AUD_SAMPLE_11p025 */
    352800,
    /* AUD_SAMPLE_16p000 */
    512000,
    /* AUD_SAMPLE_22p050 */
    705600,
    /* AUD_SAMPLE_32p000 */
    1024000,
    /* AUD_SAMPLE_44p100 */
    1411200,
    /* AUD_SAMPLE_48p000 */
    1536000,
    /* AUD_SAMPLE_96p000 */
    3072000
    };


    int AUD_MCLK_FREQ = 256000; /* AUD_SAMPLE_08p000 */

    void McASPInit()
    {

    PRCMPeripheralClkEnable(PRCM_I2S, PRCM_RUN_MODE_CLK);
    PRCMI2SClockFreqSet(AUD_MCLK_FREQ);
    //512000 = 16*2*16000Khz(Num of bytes * STEREO * 16000 sampling)

    }


    void AudioCaptureRendererConfigure()
    {

    I2SConfigSetExpClk(I2S_BASE, AUD_MCLK_FREQ, AUD_MCLK_FREQ, I2S_SLOT_SIZE_16 |
    I2S_PORT_DMA);
    I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_1, I2S_SER_MODE_RX,
    I2S_INACT_LOW_LEVEL);
    I2SSerializerConfig(I2S_BASE, I2S_DATA_LINE_0, I2S_SER_MODE_TX,
    I2S_INACT_LOW_LEVEL);

    }
  • Hi,

    Let me know if you need anymore information from me.

    Regards,

    Shashi.

  • Hi Shashi,

    We modified SDK wifi-audio code with following changes to re-create scenario as you mentioned in previous post:

    1. modified 

    if(iBufferFilled >= (2*PACKET_SIZE))  to   if(iBufferFilled >= 128)    in microphone task

    2. configure bclk, mclk to 256KHz

    3. Modified Codec reg 

    Reg 0x05 = 0x91 // P=1, R =1

    Reg 0x06 = 0x04 // J=1

    Reg 0x07 = 0x00 // D=0

    Reg 0x0B = 0x81 // NDAC=1

    Reg 0x0C = 0x81 // MDAC=1

    Reg 0x0D = 0x00 // DOSR=128

    Reg 0x0E = 0x80 // DOSR=128

    Reg 0x12 = 0x81 // NADC=1

    Reg 0x13 = 0x81 // MADC=1

    Reg 0x14 = 0x80 // D=0

    We are getting delay of 48ms for 8KHz, stereo, 16-bit and 24ms for 16KHz, 16-bit, stereo. Unfortunately we are unable to reproduce 800ms delay issue that you are facing for 8KHz.  Can you please do same changes in SDK applicaton without enabling CLI support on your test environment.

    Regards,

    Aashish

       

  • Hi,

    Thanks for the effort.

    But strange I am seeing this. CLI thread is always blocking on input from sl_Recv().

    I have following query:

    When you say that you saw delay of 48 ms, it is between what and what?

    1. Is it between, "you speak in mic" and "it appears in the pTxBuffer circular buffer"? OR
    2. Is it between, "you speak in mic" and "it is heard on the speaker"?
    3. Or something else.

    How did you measure the timing?

    Regards,
    Shashi.
  • Hi Shashi,

    We probed pin 64 (I2S DOUT) and pin 50 (I2S DIN) and measured time difference. So its between mic and speaker. 

    Regards,

    Aashish Bhanawat

  • hmmm...
    Something does not add up.

    I did some more experimentation:

    I reduced the value of TX_BUFFER_SIZE from 16K to 1K and the audio played back almost instantly!
    This is done with all the other parameters exactly same.

    So it points that circular buffer is read 360 degree apart.

    By the way, I2S DIN and DOUT will always remain active even in silence the mic. How did you distinguish between a silence and a voice?

    Regards,
    Shashi.
  • Hi Shashi,


    By comparing data at the start of execution or in other word after audio_init.


    Regards,
    Aashish
  • Well that does not indicate the audio delay.
    What you measured was the init delay. The moment you called init and first data starts entering and "some" data getting played.
    This "some" data getting played may not be the same I2S captured.

    That is why your measurement, and mine are different.

    Ideal would be that you inset a mic and a headphone in audiobooster and play the real audio.

    Regards,
    Shashi.
  • Hi Shashi,

    We measured loopback latency using Audacity (http://manual.audacityteam.org/o/man/latency_test.html). And, here is result:

    1. 16KHz, Stereo, 16 bit - 50ms
    2. 8KHz, Stereo, 16-bit - 107ms.


    For latency test we took watermark size for mic and speaker buffer is 2K because of following reason:
    1. As each DMA copying 1K data in each transcation (512B in ping and 512B in pong mode)
    2. As we are using circular buffer, we are taking index margin of 2 to avoid false buffer full or empty alarm (writePtr == readPtr)


    1. 16KHz, Stereo, 16 bit - 50ms
    1K audio packet ~ 16ms audio data.

    mic watermark size is 2K so delay will be 2 * 16 = 32ms
    + speaker watermark size is 2K that will be achieve when mic buffer have 3K data so delay will be 1 * 16 = 16ms
    + copying 1K data from mic buffer to speaker buffer 1*2 = 2ms (Note: This delay can vary as we are copying in non-DMA context and its depend upon how many cpu cycles available.)

    = 50 ms

    2. 8KHz, Stereo, 16 bit - 107ms
    1K audio packet ~ 32ms audio data.

    2*32 + 1 * 32 + 11 = 107 ms



    Regards,

    Aashish
  • Hi Aashish,

    Thanks a lot for the reply. Really appreciate it.

    Maybe I have made some changes which is causing this issue. I am to look even more closely into the code.

    Will it be possible to share your code base with me? (with the changes you made for measurements)

    Regards,
    Shashi.
  • Hi Shashi,

    It is same as SDK code except watermark set from 30K to 2K and and configure for 8KHz audio. For your reference we are attaching code (wifi_audio_app.zip).

    Regards,

    Aashish

  • Hi Aashish,

    This is one fo the solution i was looking for in the thread : e2e.ti.com/.../390582

    Thanks and for the details.

    I would be glad if you can help me to get more details on the codec configuration part. Whats the meaning of different values on different registers.

    As a starting point i need to know how to set different sampling rate in ADC( capture ) and DAC(playout) and gain settings of the capture/playout path.

    Please help out with any resource documents if you have.

    Regards,
    sreenivasa.

    Also i find a lot of low frequency noise( buzzzzz kind of ) in the captured audio signal( captured in silent room ). Is too much noise expected in the audio booster pack capture? Is there anyregister settings which can bring it down?
  • Hi ,

    did u explore on mono capture or mono playout using audio booster pack on CC3200?

    Were your experiemnts always with stereo signals?

    With repect to the above thread on audio front end latency, what kind of delay did u finally find?

    Regards,
    Sreenivasa