espressif / esp-adf

Espressif Audio Development Framework
Other
1.53k stars 671 forks source link

http_play_and_save_to_file example doesn't properly write MP3 file to SPIFFS (AUD-4671) #1021

Closed Nathanael29 closed 1 year ago

Nathanael29 commented 1 year ago

Environment

Problem Description

Edited http_play_and_save_to_file example to save to SPIFFS instead of sd card. MP3 file in SPIFFS is incomplete and is cut off when played using pipeline_spiffs_mp3 example. If there is a way to download MP3 only without playing at the same time that would be better.

I tried setting up pipeline to only be http -> raw -> spiffs but the file just won't download at all.

Expected Behavior

The MP3 file that is played from spiffs should be identical to the MP3 file downloaded to spiffs

Actual Behavior

MP3 file is cut off

Steps to Reproduce

  1. Run modified http_play_and_save_to_file.c http_play_and_save_to_file.zip

  2. Run pipeline_spiffs_mp3

// If possible, attach a picture of your setup/wiring here.

Code to Reproduce This Issue

// the code should be wrapped in the ```cpp tag so that it will be displayed better.
#include "esp_log.h"

//Replaced the SD card mount with this code

ESP_LOGI(TAG, "[ 1 ] Mount spiffs");
    // Initialize Spiffs peripheral
    periph_spiffs_cfg_t spiffs_cfg = {
        .root = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true
    };
    esp_periph_handle_t spiffs_handle = periph_spiffs_init(&spiffs_cfg);

    // Start spiffs
    esp_periph_start(set, spiffs_handle);

    // Wait until spiffs is mounted
    while (!periph_spiffs_is_mounted(spiffs_handle)) {
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }

//Replaced fatfs stream with spiffs stream

 ESP_LOGI(TAG, "[3.1] Create spiffs stream to save file");
    spiffs_stream_cfg_t flash_cfg = SPIFFS_STREAM_CFG_DEFAULT();
    flash_cfg.type = AUDIO_STREAM_WRITER;
    spiffs_stream_reader = spiffs_stream_init(&flash_cfg);

// If your code is longer than 30 lines, GIST is preferred.

Debug Logs

Debug log goes here. It should contain the backtrace, as well as the reset source if it is a crash.
Please copy the plaintext here for us to search the error log. Or attach the complete logs and leave the main part here if the log is *too* long.

Other Items If Possible

TempoTian commented 1 year ago

You code is also work after fix build error, If you want to download file without play you can build up a simple pipeline: That contains http reader and spiffs writer only.

void download_file(audio_event_iface_handle_t evt)
{
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    audio_pipeline_handle_t pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[2.1] Create http stream to read data");
    http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
    audio_element_handle_t http_stream_reader = http_stream_init(&http_cfg);
    audio_element_set_uri(http_stream_reader, "http://smarttalk-api.tochtech.com/audio/prompt/_wificonnected.mp3");

    spiffs_stream_cfg_t flash_cfg = SPIFFS_STREAM_CFG_DEFAULT();
    flash_cfg.type = AUDIO_STREAM_WRITER;
    audio_element_handle_t spiffs_writer = spiffs_stream_init(&flash_cfg);
    audio_element_set_uri(spiffs_writer, "/spiffs/adf_music.mp3");

    audio_pipeline_register(pipeline, http_stream_reader, "http");
    audio_pipeline_register(pipeline, spiffs_writer, "mp3");

    const char *link_tag[3] = {"http", "mp3"};
    audio_pipeline_link(pipeline, &link_tag[0], 2);
    audio_pipeline_set_listener(pipeline, evt);
    audio_pipeline_run(pipeline);
     printf("Src: %p %p\n", spiffs_writer, http_stream_reader);
    while (1) {
        audio_event_iface_msg_t msg;
        esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
            continue;
        }
        printf("Src: %p data %d\n", msg.source, (int)msg.data);
        /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
        if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) spiffs_writer &&
            msg.cmd == AEL_MSG_CMD_REPORT_STATUS &&
            (((int) msg.data == AEL_STATUS_STATE_STOPPED) || ((int) msg.data == AEL_STATUS_STATE_FINISHED))) {
            ESP_LOGW(TAG, "[ * ] Stop event received");
            break;
        }
    }
    ESP_LOGI(TAG, "[ 7 ] Stop pipelines");
    audio_pipeline_remove_listener(pipeline);
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);
    audio_pipeline_deinit(pipeline);
}

void play_file(audio_event_iface_handle_t evt)
{
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    audio_pipeline_handle_t pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    spiffs_stream_cfg_t flash_cfg = SPIFFS_STREAM_CFG_DEFAULT();
    flash_cfg.type = AUDIO_STREAM_READER;
    audio_element_handle_t spiffs_reader = spiffs_stream_init(&flash_cfg);
    audio_element_set_uri(spiffs_reader, "/spiffs/adf_music.mp3");
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.type = AUDIO_STREAM_WRITER;
    audio_element_handle_t i2s_stream_writer = i2s_stream_init(&i2s_cfg);

    mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
    audio_element_handle_t mp3_decoder = mp3_decoder_init(&mp3_cfg);
    audio_pipeline_register(pipeline, spiffs_reader, "spiffs");
    audio_pipeline_register(pipeline, mp3_decoder, "mp3");
    audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");

    const char *link_tag[3] = {"spiffs", "mp3", "i2s"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);
    audio_pipeline_set_listener(pipeline, evt);
    audio_pipeline_run(pipeline);

    while (1) {
        audio_event_iface_msg_t msg;
        esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
            continue;
        }
        if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) mp3_decoder &&
            msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
            audio_element_info_t music_info = {0};
            audio_element_getinfo(mp3_decoder, &music_info);

            ESP_LOGI(TAG, "[ * ] Receive music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d",
                     music_info.sample_rates, music_info.bits, music_info.channels);

            i2s_stream_set_clk(i2s_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
            continue;
        }
        /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
        if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer &&
            msg.cmd == AEL_MSG_CMD_REPORT_STATUS &&
            (((int) msg.data == AEL_STATUS_STATE_STOPPED) || ((int) msg.data == AEL_STATUS_STATE_FINISHED))) {
            ESP_LOGW(TAG, "[ * ] Stop event received");
        }
    }
    ESP_LOGI(TAG, "[ 7 ] Stop pipelines");
    audio_pipeline_remove_listener(pipeline);
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);
    /* Release all resources */
    audio_pipeline_deinit(pipeline);
}

void app_main(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
    ESP_ERROR_CHECK(esp_netif_init());
#else
    tcpip_adapter_init();
#endif
    esp_log_level_set("*", ESP_LOG_INFO);
    esp_log_level_set(TAG, ESP_LOG_DEBUG);

    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);

    esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
    esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);

    audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);

    // Initialize Spiffs peripheral
    periph_spiffs_cfg_t spiffs_cfg = {
        .root = "/spiffs", .partition_label = NULL, .max_files = 5, .format_if_mount_failed = true};
    esp_periph_handle_t spiffs_handle = periph_spiffs_init(&spiffs_cfg);
    // Start spiffs
    esp_periph_start(set, spiffs_handle);

    // Wait until spiffs is mounted
    while (!periph_spiffs_is_mounted(spiffs_handle)) {
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    audio_board_handle_t board_handle = audio_board_init();
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);

    ESP_LOGI(TAG, "[4.0] Start and wait for Wi-Fi network");
    periph_wifi_cfg_t wifi_cfg = {
        .ssid = CONFIG_WIFI_SSID,
        .password = CONFIG_WIFI_PASSWORD,
    };
    esp_periph_handle_t wifi_handle = periph_wifi_init(&wifi_cfg);
    esp_periph_start(set, wifi_handle);
    periph_wifi_wait_for_connected(wifi_handle, portMAX_DELAY);

    download_file(evt);
    play_file(evt);

    esp_periph_set_stop_all(set);
    audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);
    esp_periph_set_destroy(set);
}
jason-mao commented 1 year ago

This topic has become inactive so I'm going to close the issue. Please reopen this if you have any questions or need any further assistance.