opus是一款优秀的音频编解码算法,具有很高的压缩率,尝试在ESP32平台运行opus

ESP-IDF开发环境运行opus

ESP-IDF开发环境已经有大佬做好了移植,并且制作了makefile文件,做好了第三方的components,下载地址 点击我,我们只用将文件夹下载先来拖放到components文件夹根目录即可,如下图所示

1.png

下面我们来创建一个demo用来运行,新建一个hello world工程,在创建工程师选择导入esp-libopus这个库

1 (2).png

后续的操作都一样,下面是我编写的demo函数,其中使用时间长度为20ms,采样率为8Khz,使用一个正弦波数组作为模拟压缩的对象,实际测试下在ESP32上压缩这么多数据大概需要1ms,可以说具有较好的实时性。

const int16_t testWavArray[160] = {

        0, -517, -999, -1414, -1732, -1931, -2000, -1931, -1732, -1414, -1000, -517,0, 517, 999, 1414, 1732, 1931, 2000, 1931, 1732, 1414, 1000, 517,......

};
uint8_t outputData[100]={0};
int16_t decodeData[200]={0};
typedef  struct testOpus
{
    opus_int32 sampling_rate;//源数据采样频�???????
    int channels;//通道�???????
    opus_int32 bitrate_bps;//编码的码�???????
    int error;

    opus_int16 *srcData;//源数�???????
    int srcSize;             //源数据大�???????
    unsigned char *dstData; //输出数据指针
    int dstSize;    //输出数据大小

    opus_int16 *outData;//解码后的数据大小

    opus_int32 max_payload_bytes;


}testOpus;

testOpus myAudioOpus={.sampling_rate=8*1000,
                      .channels=1,
                      .bitrate_bps=8*1000,
                      .error=0,
                      .srcData=NULL,
                      .srcSize=160,
                      .dstData=NULL,
                      .dstSize=0,
                      .outData=NULL,
                      .max_payload_bytes=160*2,
};
void opusDemo()
{
    
      OpusEncoder *enc;
      enc = opus_encoder_create(myAudioOpus.sampling_rate, myAudioOpus.channels, OPUS_APPLICATION_AUDIO, &myAudioOpus.error);
      opus_encoder_ctl(enc, OPUS_SET_BITRATE(myAudioOpus.bitrate_bps));
      opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO));
      opus_encoder_ctl(enc, OPUS_SET_VBR(1));
      opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
      opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0));
      opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0));
      opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0));
      opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(1));
      opus_encoder_ctl(enc, OPUS_SET_DTX(1));
      opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0));
      opus_int32 skip = 0;
      opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip));
      opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
      opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16));
      if(OPUS_OK!=myAudioOpus.error)
      {
          ESP_LOGI(TAG,"OPUS encoder init failed !");
      }
      else
      {
          ESP_LOGI(TAG,"OPUS encoder init success!");
      }

      ESP_LOGI(TAG,"ESP_LOGI raw data !:%d",myAudioOpus.srcSize);

        uint32_t start=xTaskGetTickCount();
        ESP_LOGI(TAG,"ready to encode!");
        myAudioOpus.dstSize=opus_encode(enc,testWavArray,myAudioOpus.srcSize,outputData,myAudioOpus.max_payload_bytes);
         uint32_t end=xTaskGetTickCount();
         uint32_t resultTime = end - start ;
         ESP_LOGI(TAG,"encode spend :%d ms! ",resultTime);
      if(myAudioOpus.dstSize<0)
      {
          ESP_LOGI(TAG,"OPUS encode failed :%d!",myAudioOpus.dstSize);
      }
      else
      {
          ESP_LOGI(TAG,"OPUS encode success! len :%d",myAudioOpus.dstSize);
      }
      //压缩完成->>>>�???????始解�???????

      OpusDecoder *dec;
      dec= opus_decoder_create(myAudioOpus.sampling_rate,myAudioOpus.channels,&myAudioOpus.error);
      if(OPUS_OK!=myAudioOpus.error)
      {
          ESP_LOGI(TAG,"OPUS decoder init failed !");
      }
      else
      {
          ESP_LOGI(TAG,"OPUS decoder init success!");
      }
        start=xTaskGetTickCount();
        int decodeOutlen=opus_decode(dec,outputData,myAudioOpus.dstSize,decodeData,myAudioOpus.srcSize,0);
        end=xTaskGetTickCount();
        resultTime = end - start ;
        ESP_LOGI(TAG,"decode spend :%d ms! ",resultTime);
      if(decodeOutlen<0)
      {
            ESP_LOGI(TAG,"OPUS decode failed :%d!",decodeOutlen);
      }
      else
      {
          ESP_LOGI(TAG,"OPUS decode success! len :%d",decodeOutlen);
      }

    opus_encoder_destroy(enc);
    opus_decoder_destroy(dec);
}

Arduino开发环境运行opus

在库管理器中下载ESP8266Audio这个库,下载安装。

3.png

创建一个点灯代码引入以下头文件:

#include "AudioGeneratorOpus.h"
#include "libopus/opus.h"

其他地方可以照抄上面的ESP-IDF代码,printf代码需要修改,在Arduino环境下,编译时非常慢,opus源文件有130+,编译可能长达十分钟!