<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【ESP32 在線語音】音頻接收的緩存機制和網絡發送分包機制

      首先是初始化 I2S 設備中,可能用到了緩存

      //初始化 I2S 設備 INMP441
        Serial.println("Setup I2S ...");
        i2s_install();
        i2s_setpin();
        esp_err_t err = i2s_start(I2S_PORT_0);

       其中的  i2s_install() 配置了 i2s 的相關設置,函數具體內容如下:

      /**
       * @brief 配置 i2s 參數
       * 
       */
      void i2s_install()
      {
        const i2s_config_t i2s_config = {
            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
            .sample_rate = SAMPLE_RATE,
            .bits_per_sample = i2s_bits_per_sample_t(16),
            .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
            .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
            .intr_alloc_flags = 0, // default interrupt priority
            .dma_buf_count = 8,
            .dma_buf_len = 1024,
            .use_apll = false};
      
        esp_err_t err = i2s_driver_install(I2S_PORT_0, &i2s_config, 0, NULL);
        if (err != ESP_OK)
        {
          Serial.printf("I2S driver install failed (I2S_PORT_0): %d\n", err);
          while (true)
              ;
        }
        else
        {
          Serial.printf("I2S driver install OK\r\n");
        }
      }

      其中,與緩存有關的包括下面的結構體成員和 i2s_driver_install() 函數:

           .dma_buf_count = 8,
            .dma_buf_len = 1024,
      
      
          int                     dma_buf_count;              /**< The total number of DMA buffers to receive/transmit data.
                                                                * A descriptor includes some information such as buffer address,
                                                                * the address of the next descriptor, and the buffer length.
                                                                * Since one descriptor points to one buffer, therefore, 'dma_desc_num' can be interpreted as the total number of DMA buffers used to store data from DMA interrupt.
                                                                * Notice that these buffers are internal to'i2s_read' and descriptors are created automatically inside of the I2S driver.
                                                                * Users only need to set the buffer number while the length is derived from the parameter described below.
                                                                */
          int                     dma_buf_len;                /**< Number of frames in a DMA buffer.
                                                                *  A frame means the data of all channels in a WS cycle.
                                                                *  The real_dma_buf_size = dma_buf_len * chan_num * bits_per_chan / 8.
                                                                *  For example, if two channels in stereo mode (i.e., 'channel_format' is set to 'I2S_CHANNEL_FMT_RIGHT_LEFT') are active,
                                                                *  and each channel transfers 32 bits (i.e., 'bits_per_sample' is set to 'I2S_BITS_PER_CHAN_32BIT'),
                                                                *  then the total number of bytes of a frame is 'channel_format' * 'bits_per_sample' = 2 * 32 / 8 = 8 bytes.
                                                                *  We assume that the current 'dma_buf_len' is 100, then the real length of the DMA buffer is 8 * 100 = 800 bytes.
                                                                *  Note that the length of an internal real DMA buffer shouldn't be greater than 4092.
                                                                */

       從注釋(Notice that these buffers are internal to'i2s_read)可以得到 , DMA功能的使用,指定即可,而不需要自己實現——內部會自動完成相關的配置。

       

      i2s_driver_install() 函數定義如下

      /**
       * @brief Install and start I2S driver.
       *
       * @param i2s_num         I2S port number
       *
       * @param i2s_config      I2S configurations - see i2s_config_t struct
       *
       * @param queue_size      I2S event queue size/depth.
       *i2s 隊列尺寸           I2S事件隊列尺寸
       * @param i2s_queue       I2S event queue handle, if set NULL, driver will not use an event queue.
       * /*i2s 隊列            I2S事件隊列句柄
       * This function must be called before any I2S driver read/write operations.
       *
       * @return
       *     - ESP_OK              Success
       *     - ESP_ERR_INVALID_ARG Parameter error
       *     - ESP_ERR_NO_MEM      Out of memory
       *     - ESP_ERR_INVALID_STATE  Current I2S port is in use
       */
      esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue);

       實際代碼中沒有使用,暫時也不知道所謂的 I2S 時間是什么?(莫非可能自動檢測VAD端點檢測?)

       

      I2S讀取真正的過程如下:

      /**
             * @brief  
             * recordingSize:采樣得到的字節數的1/2 或者說uint16_t 的個數(每次采樣,深度為16bit,得到2字節)
             * recordTimeSeconds:此處為3s
             * SAMPLE_RATE:此處為16k 
             * recordTimeSeconds * SAMPLE_RATE 表示i2s采集,經過3s所得到的 uint16_t 的個數 
             */
      while (recordingSize < recordTimeSeconds * SAMPLE_RATE)
      {
          // 開始循環錄音,將錄制結果保存在pcm_data中
          esp_err_t result = i2s_read(I2S_PORT_0, audioData, sizeof(audioData), &bytes_read, portMAX_DELAY);
          memcpy(pcm_data + recordingSize/*pcm_data 是 uint16_t 類型的指針,因此recordingSize不需要乘2*/, 
                 audioData, 
                 bytes_read);
          recordingSize += bytes_read / 2; //此處除以2,很有意思
      }

      這段代碼一直讀取 i2s 數據到 audioData 中,并將讀取到的字節數賦值給 bytes_read, 直到讀取到3s的音頻為止(前提:在 i2s 初始化中,已經將采樣率設置為了 16k)

      其中主要用到了 i2s_read() 函數。

      /**
       * @brief Read data from I2S DMA receive buffer
       *
       * @param i2s_num         I2S port number
       *
       * @param dest            Destination address to read into
       * 數據的目的地            
       * @param size            Size of data in bytes
       * 數據目的地的容量
       * @param[out] bytes_read Number of bytes read, if timeout, bytes read will be less than the size passed in.
       * 實際讀出數據
       * @param ticks_to_wait   RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
       *
       * @note If the built-in ADC mode is enabled, we should call i2s_adc_enable and i2s_adc_disable around the whole reading process,
       *       to prevent the data getting corrupted.
       *
       * @return
       *     - ESP_OK               Success
       *     - ESP_ERR_INVALID_ARG  Parameter error
       */
      esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);

       

      代碼展望:

      1. 阻塞式讀取的風險:使用portMAX_DELAY意味著無限期等待數據,在實時系統中可能造成線程阻塞,缺乏超時保護機制。

      2. 內存拷貝的性能損耗:每次讀取都執行memcpy到全局緩沖區,在高速音頻流處理中可能成為性能瓶頸,直接DMA傳輸會是更優選擇。

       

       

      以下是訊飛星火語音聽寫的接口調用流程:從下面可以看到,上傳音頻的時候還需要特殊的處理 https://www.xfyun.cn/doc/asr/voicedictation/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B

      image

      由于采集到的是PCM格式的數據,因此設置每次傳輸 1280 字節數據(實測:一次發送1280x8字節數據是可行的,而且反應速度更快)

      另外:需要科普一下"幀"的概念:從一個問題引出——16k 采樣率 單聲道,16bit深度的PCM音頻,其一幀大小是多少

      重要澄清:幀 vs. 數據包

      在實際編程和處理中(例如使用WebRTC、Opus編碼器等),人們常說的“幀”可能指的是一個時間塊,比如20ms的音頻數據。這更像一個數據包

      我們來計算一下一個 20ms的數據包 有多大:

      1. 計算20ms內的樣本數量
        采樣率 × 時間 = 16000 樣本/秒 × 0.020 秒 = 320 個樣本

      2. 計算這個數據包的總大小
        樣本數量 × 每樣本字節數 × 聲道數 = 320 × 2 字節 × 1 = 640 字節

      所以,雖然技術上一幀是2字節,但在討論網絡傳輸或編碼時,一個包含320個樣本(即320幀)、大小為640字節的數據塊,也經常被稱作“一幀音頻”或“一個音頻包”。

      (對于科大訊飛星火模型而言,其時間塊長度應該為40ms,所以文檔中寫為 1280 字節)

      簡短回答

      對于 16kHz, 單聲道, 16bit 的PCM音頻,一幀的大小是 2 字節


      詳細解釋

      要理解這個答案,我們需要先明確幾個概念:

      1. 采樣率:每秒采集(或播放)多少個樣本。16kHz 表示每秒 16,000 個樣本。

      2. 聲道:單聲道 表示只有1個聲音通道。

      3. 位深度:每個樣本用多少比特來表示。16bit 表示每個樣本占用 16 個比特。

      4. :在PCM音頻中,一幀等于一個采樣點在所有聲道上的數據總和

      計算步驟

      對于單聲道音頻,計算非常簡單:

      一幀大小(字節) = (位深度 / 8) × 聲道數

      • 位深度(字節)16 bit / 8 = 2 字節(因為1字節=8比特,這是每個樣本的大小)

      • 聲道數1

      所以:
      一幀大小 = 2 字節/樣本 × 1 聲道 = 2 字節

       

      總結

      • 從純PCM格式定義上講:一幀 = 2 字節

        • 這是音頻處理底層(如直接操作PCM數組)時最精確的概念。

      • 從實時音頻傳輸/編碼的上下文上講:一幀(或一個包)可能指 640 字節(對應20ms時長)。

        • 這是在高層次應用(如WebRTC, VoIP)中更常見的說法。

      在與人溝通或編寫代碼時,請務必根據上下文確認“幀”的具體含義。如果您是在處理原始的PCM字節流,那么 2字節 是正確的答案。

       

      posted @ 2025-10-29 01:19  FBshark  閱讀(18)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美激欧美啪啪片| 欧洲熟妇色xxxx欧美老妇免费| 婷婷六月色| 国产一区二区三区在线观| 欧美啪啪网| 成人午夜激情在线观看| 狠狠色噜噜狠狠狠888米奇视频| 天堂mv在线mv免费mv香蕉| 永久免费观看美女裸体的网站| a4yy私人毛片| 亚洲精品一区二区三区大| 久久久国产精品VA麻豆| 亚洲一区二区精品另类| 99在线小视频| 国产高潮刺激叫喊视频| 茶陵县| 久久精品国产九一九九九| 国产在线中文字幕精品 | 亚洲成a人无码av波多野| 91福利一区福利二区| 国产成人啪精品视频免费软件| a4yy私人毛片| 中文字幕日韩国产精品| 本道久久综合无码中文字幕| 亚洲精品入口一区二区乱| 又湿又紧又大又爽A视频男| 国产91丝袜在线播放动漫| 男女啪啪高潮激烈免费版| 熟女视频一区二区三区嫩草 | 罗田县| 国产99视频精品免费视频76 | 丰满少妇人妻久久久久久| 久久国产国内精品国语对白| 在国产线视频A在线视频| 无码福利一区二区三区| 国内熟妇人妻色在线视频| 亚洲香蕉免费有线视频| 人妻体内射精一区二区三区| 国产精品国产亚洲区久久| 亚洲av成人免费在线| 推油少妇久久99久久99久久|