- 2024-11-01
-
上传了资料:
智联音响
-
发表了主题帖:
2024 DigiKey 创意大赛】之智联音响
本帖最后由 rertet 于 2024-11-1 09:02 编辑
一、作品简介
本环境项目模块目的是将有线音响赋值成无线wifi音响
处于同一局域网下即可实现音频传输
手机端使用酷狗音进行音乐推送
二、系统框图
三、功能说明
ESP32 评估板:负责数据处理和传输
LCD 触摸屏显示器:显示信息
手机app酷狗客户端
四、作品源码
#include "esp_log.h"
#include "nvs_flash.h"
#include "board.h"
#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "audio_mem.h"
#include "esp_wifi.h"
#include "esp_ssdp.h"
#include "esp_dlna.h"
#include "esp_audio.h"
#include "esp_decoder.h"
#include "http_stream.h"
#include "i2s_stream.h"
#include "media_lib_adapter.h"
#include "audio_idf_version.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
#include "esp_netif.h"
#else
#include "tcpip_adapter.h"
#endif
static const char *TAG = "DLNA_EXAMPLE";
#define DLNA_UNIQUE_DEVICE_NAME "ESP32_DMR_8db0797a"
#define DLNA_DEVICE_UUID "8db0797a-f01a-4949-8f59-51188b181809"
#define DLNA_ROOT_PATH "/rootDesc.xml"
static esp_audio_handle_t player = NULL;
static esp_dlna_handle_t dlna_handle = NULL;
static int vol, mute;
static char *track_uri = NULL;
static const char *trans_state = "STOPPED";
static void player_event_handler(esp_audio_state_t *state, void *ctx)
{
if (dlna_handle == NULL) {
return ;
}
switch (state->status) {
case AUDIO_STATUS_RUNNING:
trans_state = "PLAYING";
esp_dlna_notify_avt_by_action(dlna_handle, "TransportState");
break;
case AUDIO_STATUS_PAUSED:
trans_state = "PAUSED_PLAYBACK";
esp_dlna_notify_avt_by_action(dlna_handle, "TransportState");
break;
case AUDIO_STATUS_STOPPED:
case AUDIO_STATUS_FINISHED:
trans_state = "STOPPED";
esp_dlna_notify_avt_by_action(dlna_handle, "TransportState");
break;
default:
break;
}
}
int renderer_request(esp_dlna_handle_t dlna, const upnp_attr_t *attr, int attr_num, char *buffer, int max_buffer_len)
{
int req_type;
int tmp_data = 0, buffer_len = 0;
int hour = 0, min = 0, sec = 0;
if (attr_num != 1) {
return 0;
}
req_type = attr->type & 0xFF;
switch (req_type) {
case RCS_GET_MUTE:
ESP_LOGD(TAG, "get mute = %d", mute);
return snprintf(buffer, max_buffer_len, "%d", mute);
case RCS_SET_MUTE:
mute = atoi(buffer);
ESP_LOGD(TAG, "set mute = %d", mute);
if (mute) {
esp_audio_vol_set(player, 0);
} else {
esp_audio_vol_set(player, vol);
}
esp_dlna_notify(dlna, "RenderingControl");
return 0;
case RCS_GET_VOL:
esp_audio_vol_get(player, &vol);
ESP_LOGI(TAG, "get vol = %d", vol);
return snprintf(buffer, max_buffer_len, "%d", vol);
case RCS_SET_VOL:
vol = atoi(buffer);
ESP_LOGI(TAG, "set vol = %d", vol);
esp_audio_vol_set(player, vol);
esp_dlna_notify(dlna, "RenderingControl");
return 0;
case AVT_PLAY:
ESP_LOGI(TAG, "Play with speed=%s trans_state %s", buffer, trans_state);
esp_audio_state_t state = { 0 };
esp_audio_state_get(player, &state);
if (state.status == AUDIO_STATUS_PAUSED) {
esp_audio_resume(player);
esp_dlna_notify(dlna, "AVTransport");
break;
} else if (track_uri != NULL) {
esp_audio_play(player, AUDIO_CODEC_TYPE_DECODER, track_uri, 0);
esp_dlna_notify(dlna, "AVTransport");
}
return 0;
case AVT_STOP:
ESP_LOGI(TAG, "Stop instance=%s", buffer);
esp_audio_stop(player, TERMINATION_TYPE_NOW);
esp_dlna_notify_avt_by_action(dlna_handle, "TransportState");
return 0;
case AVT_PAUSE:
ESP_LOGI(TAG, "Pause instance=%s", buffer);
esp_audio_pause(player);
esp_dlna_notify_avt_by_action(dlna_handle, "TransportState");
return 0;
case AVT_NEXT:
case AVT_PREV:
esp_audio_stop(player, TERMINATION_TYPE_NOW);
return 0;
case AVT_SEEK:
sscanf(buffer, "%d:%d:%d", &hour, &min, &sec);
tmp_data = hour * 3600 + min * 60 + sec;
ESP_LOGI(TAG, "Seekto %d s", tmp_data);
esp_audio_seek(player, tmp_data);
return 0;
case AVT_SET_TRACK_URI:
ESP_LOGI(TAG, "SetAVTransportURI=%s", buffer);
esp_audio_state_t state_t = { 0 };
esp_audio_state_get(player, &state_t);
if ((track_uri != NULL) && (state_t.status == AUDIO_STATUS_RUNNING) && strcasecmp(track_uri, buffer)) {
esp_audio_stop(player, TERMINATION_TYPE_NOW);
esp_dlna_notify(dlna, "AVTransport");
}
free(track_uri);
track_uri = NULL;
if (track_uri == NULL) {
asprintf(&track_uri, "%s", buffer);
}
return 0;
case AVT_SET_TRACK_METADATA:
ESP_LOGD(TAG, "CurrentURIMetaData=%s", buffer);
return 0;
case AVT_GET_TRACK_URI:
if (track_uri != NULL) {
return snprintf(buffer, max_buffer_len, "%s", track_uri);
} else {
return 0;
}
case AVT_GET_PLAY_SPEED: /* ["1"] */
return snprintf(buffer, max_buffer_len, "%d", 1);
case AVT_GET_PLAY_MODE:
return snprintf(buffer, max_buffer_len, "NORMAL");
case AVT_GET_TRANS_STATUS: /* ["ERROR_OCCURRED", "OK"] */
return snprintf(buffer, max_buffer_len, "OK");
case AVT_GET_TRANS_STATE: /* ["STOPPED", "PAUSED_PLAYBACK", "TRANSITIONING", "NO_MEDIA_PRESENT"] */
ESP_LOGI(TAG, "_avt_get_trans_state %s", trans_state);
return snprintf(buffer, max_buffer_len, trans_state);
case AVT_GET_TRACK_DURATION:
case AVT_GET_MEDIA_DURATION:
esp_audio_duration_get(player, &tmp_data);
tmp_data /= 1000;
buffer_len = snprintf(buffer, max_buffer_len, "%02d:%02d:%02d", tmp_data / 3600, tmp_data / 60, tmp_data % 60);
ESP_LOGD(TAG, "_avt_get_duration %s", buffer);
return buffer_len;
case AVT_GET_TRACK_NO:
return snprintf(buffer, max_buffer_len, "%d", 1);
case AVT_GET_TRACK_METADATA:
return 0;
// case AVT_GET_POS_ABSTIME:
case AVT_GET_POS_RELTIME:
esp_audio_time_get(player, &tmp_data);
tmp_data /= 1000;
buffer_len = snprintf(buffer, max_buffer_len, "%02d:%02d:%02d", tmp_data / 3600, tmp_data / 60, tmp_data % 60);
ESP_LOGD(TAG, "_avt_get_time %s", buffer);
return buffer_len;
// case AVT_GET_POS_ABSCOUNT:
case AVT_GET_POS_RELCOUNT:
esp_audio_pos_get(player, &tmp_data);
buffer_len = snprintf(buffer, max_buffer_len, "%d", tmp_data);
ESP_LOGD(TAG, "_avt_get_pos %s", buffer);
return buffer_len;
}
return 0;
}
static int _http_stream_event_handle(http_stream_event_msg_t *msg)
{
if (msg->event_id == HTTP_STREAM_RESOLVE_ALL_TRACKS) {
return ESP_OK;
}
if (msg->event_id == HTTP_STREAM_FINISH_TRACK) {
return http_stream_next_track(msg->el);
}
if (msg->event_id == HTTP_STREAM_FINISH_PLAYLIST) {
return http_stream_restart(msg->el);
}
return ESP_OK;
}
static void audio_player_init(void)
{
audio_board_handle_t board_handle = audio_board_init();
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START);
esp_audio_cfg_t cfg = DEFAULT_ESP_AUDIO_CONFIG();
cfg.vol_handle = board_handle->audio_hal;
cfg.vol_set = (audio_volume_set)audio_hal_set_volume;
cfg.vol_get = (audio_volume_get)audio_hal_get_volume;
cfg.prefer_type = ESP_AUDIO_PREFER_MEM;
cfg.resample_rate = 48000;
player = esp_audio_create(&cfg);
// Create readers and add to esp_audio
http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
http_cfg.event_handle = _http_stream_event_handle;
http_cfg.type = AUDIO_STREAM_READER;
http_cfg.enable_playlist_parser = true;
http_cfg.task_prio = 12;
http_cfg.stack_in_ext = true;
audio_element_handle_t http_stream_reader = http_stream_init(&http_cfg);
esp_audio_input_stream_add(player, http_stream_reader);
audio_decoder_t auto_decode[] = {
DEFAULT_ESP_MP3_DECODER_CONFIG(),
DEFAULT_ESP_WAV_DECODER_CONFIG(),
DEFAULT_ESP_AAC_DECODER_CONFIG(),
DEFAULT_ESP_M4A_DECODER_CONFIG(),
DEFAULT_ESP_TS_DECODER_CONFIG(),
};
esp_decoder_cfg_t auto_dec_cfg = DEFAULT_ESP_DECODER_CONFIG();
esp_audio_codec_lib_add(player, AUDIO_CODEC_TYPE_DECODER, esp_decoder_init(&auto_dec_cfg, auto_decode, 5));
// Create writers and add to esp_audio
i2s_stream_cfg_t i2s_writer = I2S_STREAM_CFG_DEFAULT();
i2s_writer.type = AUDIO_STREAM_WRITER;
i2s_writer.stack_in_ext = true;
i2s_writer.task_core = 1;
audio_element_handle_t i2s_stream_writer = i2s_stream_init(&i2s_writer);
i2s_stream_set_clk(i2s_stream_writer, 48000, 16, 2);
esp_audio_output_stream_add(player, i2s_stream_writer);
// Set default volume
esp_audio_vol_set(player, 35);
}
static void start_dlna()
{
const ssdp_service_t ssdp_service[] = {
{ DLNA_DEVICE_UUID, "upnp:rootdevice", NULL },
{ DLNA_DEVICE_UUID, "urn:schemas-upnp-org:device:MediaRenderer:1", NULL },
{ DLNA_DEVICE_UUID, "urn:schemas-upnp-org:service:ConnectionManager:1", NULL },
{ DLNA_DEVICE_UUID, "urn:schemas-upnp-org:service:RenderingControl:1", NULL },
{ DLNA_DEVICE_UUID, "urn:schemas-upnp-org:service:AVTransport:1", NULL },
{ NULL, NULL, NULL },
};
ssdp_config_t ssdp_config = SSDP_DEFAULT_CONFIG();
ssdp_config.udn = DLNA_UNIQUE_DEVICE_NAME;
ssdp_config.location = "http://${ip}"DLNA_ROOT_PATH;
esp_ssdp_start(&ssdp_config, ssdp_service);
static httpd_handle_t httpd = NULL;
httpd_config_t httpd_config = HTTPD_DEFAULT_CONFIG();
httpd_config.max_uri_handlers = 25;
httpd_config.stack_size = 6 * 1024;
if (httpd_start(&httpd, &httpd_config) != ESP_OK) {
ESP_LOGI(TAG, "Error starting httpd");
}
extern const uint8_t logo_png_start[] asm("_binary_logo_png_start");
extern const uint8_t logo_png_end[] asm("_binary_logo_png_end");
dlna_config_t dlna_config = {
.friendly_name = "ESP32 MD (ESP32 Renderer)",
.uuid = (const char *)DLNA_DEVICE_UUID,
.logo = {
.mime_type = "image/png",
.data = (const char *)logo_png_start,
.size = logo_png_end - logo_png_start,
},
.httpd = httpd,
.httpd_port = httpd_config.server_port,
.renderer_req = renderer_request,
.root_path = DLNA_ROOT_PATH,
.device_list = false
};
dlna_handle = esp_dlna_start(&dlna_config);
ESP_LOGI(TAG, "DLNA Started...");
}
void app_main()
{
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
esp_log_level_set("AUDIO_ELEMENT", ESP_LOG_WARN);
esp_log_level_set("AUDIO_PIPELINE", ESP_LOG_ERROR);
esp_log_level_set("ESP_AUDIO_CTRL", ESP_LOG_WARN);
media_lib_add_default_adapter();
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
ESP_ERROR_CHECK(esp_netif_init());
#else
tcpip_adapter_init();
#endif
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
periph_wifi_cfg_t wifi_cfg = {
.wifi_config.sta.ssid = "WiFi_8G",
.wifi_config.sta.password = "IIll1122",
};
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);
audio_player_init();
esp_audio_callback_set(player, player_event_handler, NULL);
start_dlna();
}
下载地址:我的下载_个人中心- - 电子工程世界EEWORLD
五、作品功能演示视频
因为需要安卓手机的酷狗音乐app,我使用的是苹果的,手上暂时,后续补上
六、项目总结
通过本项目,我们构建了一个基于esp32wifi音频传输模块使有线音响赋值无限“意义”。
- 2024-09-04
-
发表了主题帖:
2024 DigiKey 创意大赛】之esp32开发环境搭建
距离收到板子已经快有一个月了,最近一直苦于这个开发环境的搭建,在公司电脑实现了vscode开发环境的搭建,在自己电脑上死活不行。暂且记分享下搭建开发环境的步骤吧。
之前没使用过这个开发环境,网上查找信息了解到安装离线包可以使用于是折腾了2天发现一个问题,通过离线包安装IDF环境可以用,直接使用win10 的命令行,在需要编译的工程目录下直接依次输入以下命令可以完成,工程配置,编译 ,烧录。(使用s3不需要按住boot烧录 使用esp32则需要按住)
idf.py set-target esp32s3 选择芯片
idf.py menuconfig 配置
idf.py build 编译
idf.py -p COM39 flash 烧录
idf.py -p COM39 -b 460800 flash 烧录
idf.py -p COM39monitor 监视
但是在使用ADF时候就出问题,过程很复杂没解决,出现git clone 的问题参考这篇文章解决问题吧:ESP32 ADF windows开发环境搭建 适配ADF到ESP32A1S_esp-adf gitmodules-CSDN博客。
关于git clone 问题还有一个解决办法:使用官方工具esp-gitee-tools,具体方法
1.先从gitee上拉取辅助包esp-gitee-tools
git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git
2.接着我们来拉取esp-adf,记住先只拉取esp-adf(esp-idf同理),不包含子模块
git clone https://github.com/espressif/esp-adf.git
3.通过esp-gitee-tools来更新esp-idf(包括子模块)
cd esp-gitee-tools
./submodule-update.sh ~/自己实际要存放的路径/esp-adf
ESP-IDF、ESP-ADF安装与配置-CSDN博客 本来不想使用vs code。 没办法使用vscode安装了一个插件,然后才跑通里面的例程,但是还有个别的没跑通。
安装方法参考:基于 VScode 搭建ESP32开发环境 esp-idf_visual studio code连接esp32-CSDN博客
在vscode是里面可以选择不在线安装,可以先离线安装好后,在使用vscode插件来找到你安装的路径(第一步骤是在线安装,第三个选项就是选择离线包)。它会自动扫描的安装文件
在使用里面demo时候有一个报错:
E (3045) MEDIA_OS: Not found right xTaskCreateRestrictedPinnedToCore.
Please enter IDF-PATH with "cd $IDF_PATH" and apply the IDF patch with "git apply $ADF_PATH/idf_patches/idf_v3.3_freertos.patch" first
E (3065) AUDIO_THREAD: Error creating RestrictedPinnedToCore media_task
E (3075) ESP_AUDIO_CTRL: Error create media_task
解决办法:
git apply $ADF_PATH/idf_patches/idf_v3.3_freertos.patch
补丁路径:xx/esp_adf/idf_patches
然后就可以找一个demo使用开头的方法编译下载进去了。
网上使用esp-idf的很多使用esp-adf就很少,因为我这个项目使用的音频相关的得需要adf这个框架,总之这个环境搭建的很麻烦。
- 2024-08-07
-
发表了主题帖:
【2024 DigiKey 创意大赛】之esp32-s3-lcd开箱
经过几天的焦急等待终于拿到esp32-s3-lcd开发板,那么一睹这个板子的风采吧
首先是他经美的外包装(看是多么的亮眼)
都已经迫不及待的打开他了。
这个做工还是相当的可以的。上电开下效果吧:
出场自带了两个演示的demo ,一个是语音控制,一个智能家居的ui控制很nice
这个界面果然很nice,即能控制,还可以切换主题,可玩性还是很高的。对了还有一个传感器,这个包装可是可以的:
完事具备下一步就是开干,期待我的成品吧