调用百度语音合成的API来进行播报

请问有没有人做过用ESP32调用百度语音合成的API或者讯飞语音合成的API来进行播报,用arduino编写的

该回答引用ChatGPT-3.5

#include <stdio.h>
#include <string.h>
#include "esp_event.h"
#include "esp_log.h"
#include "esp_http_client.h"
#include "esp_audio.h"
#include "audio_board.h"
#include "audio_pipeline.h"
#include "audio_element.h"
#include "i2s_stream.h"
#include "http_stream.h"
#include "raw_stream.h"

// 百度语音合成API接口地址
#define BAIDU_API_URL "https://tsn.baidu.com/text2audio"

// 百度语音合成API接口参数
#define BAIDU_API_KEY "your_api_key"
#define BAIDU_SECRET_KEY "your_secret_key"
#define BAIDU_PER "0" // 发音人选择,0为女声,1为男声
#define BAIDU_SPD "5" // 语速,取值0-15,默认为5中语速
#define BAIDU_PIT "5" // 音调,取值0-15,默认为5中语调
#define BAIDU_VOL "7" // 音量,取值0-9,默认为第5中音量

static const char *TAG = "baidu_tts";

// HTTP请求头部
static esp_err_t http_event_handle(esp_http_client_event_t *evt)
{
    switch (evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGE(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            break;
    }
    return ESP_OK;
}

// 百度语音合成API请求参数
static void get_params(char *params, int max_len, const char *text)
{
    snprintf(params, max_len, "tex=%s&cuid=esp32&lan=zh&per=%s&spd=%s&pit=%s&vol=%s&tok=24.02b8fbff6d0c56b289f1b07a70939e2c.2592000.1626938935.282335-24234292",
             text, BAIDU_PER, BAIDU_SPD, BAIDU_PIT, BAIDU_VOL);
}

// 请求百度语音合成API,返回语音文件数据
static esp_err_t request_tts_data(const char *text, uint8_t **data, uint32_t *size)
{
    char url[256];
    char params[512];
    get_params(params, sizeof(params), text);

    esp_http_client_config_t http_cfg = {
        .url = BAIDU_API_URL,
        .event_handler = http_event_handle,
    }; 

    esp_http_client_handle_t client = esp_http_client_init(&http_cfg);
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
    esp_http_client_set_post_field(client, params, strlen(params));
    esp_err_t err = esp_http_client_perform(client);
    if (err != ESP_OK) goto end;

    *size = esp_http_client_fetch_headers(client);
    *data = (uint8_t*)malloc(*size);
    esp_http_client_read_response(client, (char*)*data, *size);

end:
    esp_http_client_cleanup(client);
    return err;
}

// 播放语音文件
static void play_tts_data(uint8_t *data, uint32_t size)
{
    audio_pipeline_handle_t pipeline;
    audio_element_handle_t i2s_stream_writer, http_stream_reader, raw_read_el;

    i2s_stream_cfg_t i2s_cfg = {
        .type = AUDIO_STREAM_WRITER,
        .i2s_config = {
            .mode = I2S_MODE_MASTER | I2S_MODE_TX,
            .sample_rate = 16000,
            .bits_per_sample = 16,
            .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        },
        .dma_buf_count = 5,
        .dma_buf_len = 300,
    };
    i2s_stream_writer = i2s_stream_init(&i2s_cfg);

    http_stream_cfg_t http_cfg = {
        .type = AUDIO_STREAM_READER,
        .event_handle = http_event_handle,
        .task_stack = 4 * 1024,
        .task_prio = 2,
        .out_rb_size = 8192,
        .buffer_size = 1024,
    };
    http_stream_reader = http_stream_init(&http_cfg);
    http_stream_set_url(http_stream_reader, "");

    raw_stream_cfg_t raw_cfg = {
        .type = AUDIO_STREAM_WRITER,
    };
    raw_read_el = raw_stream_init(&raw_cfg);

    pipeline = audio_pipeline_init();
    audio_pipeline_register(pipeline, http_stream_reader, "http");
    audio_pipeline_register(pipeline, raw_read_el, "raw");
    audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");

    audio_pipeline_link(pipeline, (const char *[]) {"http", "raw", "i2s"}, 3);

    audio_element_set_uri(http_stream_reader, "");
    audio_element_run(pipeline);

    int offset = 0;
    while (offset < size) {
        int wlen = i2s_stream_writer_write(i2s_stream_writer, data + offset, size - offset, 100 / portTICK_RATE_MS);
        if (wlen > 0) offset += wlen;
        else break;
    }

    audio_element_stop(pipeline);
    audio_element_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);
    audio_pipeline_unregister(pipeline, http_stream_reader);
    audio_pipeline_unregister(pipeline, raw_read_el);
    audio_pipeline_unregister(pipeline, i2s_stream_writer);
    audio_pipeline_remove_listener(pipeline);
    audio_pipeline_deinit(pipeline);
    mem_free(data);
}

// 主函数
void app_main()
{
    ESP_LOGI(TAG, "Start");

    esp_err_t err;
    uint8_t *data;
    uint32_t size;

    // 请求语音文件数据
    err = request_tts_data("百度语音合成API测试", &data, &size);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Request TTS data failed");
        return;
    }

    // 播放语音文件
    err = audio_board_init();
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Initialize audio board failed");
        free(data);
        return;
    }
    err = esp_audio_hal_ctrl_codec_mode(ESP_AUDIO_CODEC_MODE_ENCODE);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Set audio codec mode failed");
        free(data);
        return;
    }
    play_tts_data(data, size);
}

以上代码需要设置好BAIDU_API_KEY和BAIDU_SECRET_KEY,即百度开发者平台所给的API Key和Secret Key。

请注意,此示例仅供参考,实际使用中还需处理网络连接超时等可能出现的异常情况。同时,本示例仅支持16KHz采样率、16位采样精度、单声道格式的语音播放,如需修改,请适当调整代码。

  • 请看👉 :ESP32开发中常用的IDF指令【知道这些就足够了】
  • 除此之外, 这篇博客: esp32对接阿里云生活物联网平台 天猫精灵控制 云智能APP远程控制 ali-sdk开发中的 一,提前搭建好Linux ESP-IDF开发环境,本博客不叙述具体搭建过程,请参考网上教程。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • ESP-IDF: 请切换到 release v4.2 tag 版本: git checkout v4.2

    ESP8266_RTOS_SDK: 请切换到 v3.3 tag 版本: git checkout v3.3

  • 以下回答由chatgpt基于相关博客总结生成:

    由于我是一个AI语言模型,我没有具体的编程能力和环境,无法提供完整的代码实现,但我可以提供一些基本步骤和思路供参考:

    1. 首先获取并注册百度语音合成或讯飞语音合成的API Key和Secret Key,具体步骤可以参考百度AI开放平台和讯飞开放平台的文档。
    2. 在ESP32开发环境中添加与语音合成API的通信库,可以选择官方提供的SDK或第三方库。
    3. 编写ESP32代码,在其中调用语音合成API的接口传入合成文本,获取返回的语音音频数据。
    4. 将获取到的音频数据发送到DAC或扬声器以实现播放。

    以下是一个简单的代码示例,仅供参考:

    // 引入需要使用的库
    #include "esp_http_client.h"
    #include "esp_log.h"
    
    static const char *TAG = "speech_synthesis";
    
    // 百度语音合成API Key和Secret Key
    #define BAIDU_API_KEY "YOUR_BAIDU_API_KEY"
    #define BAIDU_SECRET_KEY "YOUR_BAIDU_SECRET_KEY"
    
    // 百度语音合成API地址
    #define BAIDU_API_URL "http://tsn.baidu.com/text2audio"
    
    // 合成文本
    #define SYNTHESIS_TEXT "您好,欢迎使用ESP32语音合成功能!"
    
    // HTTP请求回调函数,用于接收响应数据
    static esp_err_t http_event_handler(esp_http_client_event_t *evt)
    {
        switch(evt->event_id) {
            case HTTP_EVENT_ERROR:
                ESP_LOGE(TAG, "HTTP_EVENT_ERROR");
                break;
            case HTTP_EVENT_ON_CONNECTED:
                ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
                break;
            case HTTP_EVENT_HEADER_SENT:
                ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
                break;
            case HTTP_EVENT_ON_HEADER:
                ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
                break;
            case HTTP_EVENT_ON_DATA:
                ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
                // 将获取到的音频数据发送到DAC或扬声器
                break;
            case HTTP_EVENT_ON_FINISH:
                ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
                break;
            case HTTP_EVENT_DISCONNECTED:
                ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
                break;
        }
        return ESP_OK;
    }
    
    void app_main()
    {
        esp_err_t err;
    
        // 创建HTTP客户端
        esp_http_client_config_t config = {
            .url = BAIDU_API_URL,
            .event_handler = http_event_handler,
        };
        esp_http_client_handle_t client = esp_http_client_init(&config);
    
        // 设置参数和Header
        char *buffer = malloc(strlen(SYNTHESIS_TEXT) + strlen(BAIDU_API_KEY) + strlen(BAIDU_SECRET_KEY) + 128);
        sprintf(buffer, "tex=%s&lan=zh&cuid=esp32&ctp=1&aue=3&tok=%s.%s", SYNTHESIS_TEXT, BAIDU_API_KEY, BAIDU_SECRET_KEY);
        esp_http_client_set_method(client, HTTP_METHOD_GET);
        esp_http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
        esp_http_client_set_header(client, "Accept", "audio/mp3");
        esp_http_client_set_header(client, "User-Agent", "Mozilla/5.0");
    
        // 发送HTTP请求
        err = esp_http_client_perform(client);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
        }
    
        // 释放资源
        free(buffer);
        esp_http_client_cleanup(client);
    }
    

    这里仅是一个基础的示例代码,仍需要根据具体的API和开发环境等情况进行相应的调整。如果对此部分有任何疑问或需要更详细的指导,请参考官方文档或在相关社区寻求帮助。