From 52d4872cae52e7f7f217d7ddded375768e5891b7 Mon Sep 17 00:00:00 2001 From: shadow578 <52449218+shadow578@users.noreply.github.com> Date: Sat, 24 Aug 2024 14:46:46 +0200 Subject: [PATCH] add support for tts playback --- .../i2s_audio/media_player/__init__.py | 3 +- .../media_player/i2s_audio_media_player.cpp | 57 ++++++++++++++++--- .../media_player/i2s_audio_media_player.h | 2 + 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/esphome/components/i2s_audio/media_player/__init__.py b/esphome/components/i2s_audio/media_player/__init__.py index 72a11ed2bc..a7693307d3 100644 --- a/esphome/components/i2s_audio/media_player/__init__.py +++ b/esphome/components/i2s_audio/media_player/__init__.py @@ -119,7 +119,7 @@ async def to_code(config): # | |-- WiFi cg.add_library("SPI", None) cg.add_library("FS", None) - cg.add_library("FFat", None) + cg.add_library("FFat", None) cg.add_library("SD", None) cg.add_library("SD_MMC", None) cg.add_library("SPIFFS", None) @@ -131,7 +131,6 @@ async def to_code(config): cg.add_library( name="ESP32-audioI2S", version=None, - # Note: use a custom fork that removes the length limit on the host parameter in connecttohost() repository="https://github.com/shadow578/ESP32-audioI2S.git#remove_host_length_limit", ) diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 96eaa4bad0..1aba81ba68 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -21,12 +21,11 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { if (this->audio_->isRunning()) { this->audio_->stopSong(); } - const bool ok = this->audio_->connecttohost(this->current_url_.value().c_str()); - if (ok) { + if (this->connecttouri_(this->current_url_.value())) { this->state = play_state; } else { - ESP_LOGD(TAG, "failed to start audio"); this->stop_(); + ESP_LOGD(TAG, "connecttouri_ failed"); } } else { this->start(); @@ -183,20 +182,20 @@ void I2SAudioMediaPlayer::start_() { this->i2s_state_ = I2S_STATE_RUNNING; this->high_freq_.start(); - this->audio_->setVolumeSteps(255); // use 255 steps for smoother volume control + this->audio_->setVolumeSteps(255); // use 255 steps for smoother volume control this->audio_->setVolume(remap(this->volume, 0.0f, 1.0f, 0, this->audio_->maxVolume())); if (this->current_url_.has_value()) { - const bool ok = this->audio_->connecttohost(this->current_url_.value().c_str()); - if (ok) { - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + if (this->connecttouri_(this->current_url_.value())) { if (this->is_announcement_) { this->state = media_player::MEDIA_PLAYER_STATE_ANNOUNCING; + } else { + this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; } this->publish_state(); } else { - ESP_LOGD(TAG, "failed to start audio"); - stop_(); + this->stop_(); + ESP_LOGD(TAG, "connecttouri_ failed"); } } } @@ -264,6 +263,46 @@ void I2SAudioMediaPlayer::dump_config() { #endif } +bool I2SAudioMediaPlayer::connecttouri_(const std::string uri) { + if (this->audio_ == nullptr) { + return false; + } + + // web stream? + if (uri.find("http://", 0) == 0 || uri.find("https://", 0) == 0) { + ESP_LOGD(TAG, "ConnectTo WebStream '%s'", uri.c_str()); + return this->audio_->connecttohost(uri.c_str()); + } + + // local file? + if (uri.find("file://", 0) == 0) { + // format: file:// + // const std::string path = uri.substr(7); + // ESP_LOGD(TAG, "ConnectTo File '%s'", path.c_str()); + // return this->audio_->connecttoFS(?, uri.c_str() + 7); + return false; + } + + // text to speech? + if (uri.find("tts://", 0) == 0) { + // format: tts://: + const size_t colon = uri.find(':', 6); + if (colon == std::string::npos || colon > 10) { + // language code is expected to be 2-5 characters + ESP_LOGW(TAG, "Invalid TTS URI"); + return false; + } + + const std::string lang = uri.substr(6, colon - 6); + const std::string text = uri.substr(colon + 1); + + ESP_LOGD(TAG, "ConnectTo TTS: lang='%s', text='%s'", lang.c_str(), text.c_str()); + return this->audio_->connecttospeech(text.c_str(), lang.c_str()); + } + + return false; +} + } // namespace i2s_audio } // namespace esphome diff --git a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h index 5afe778122..c851d625e2 100644 --- a/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.h @@ -59,6 +59,8 @@ class I2SAudioMediaPlayer : public Component, public media_player::MediaPlayer, void stop_(); void play_(); + bool connecttouri_(const std::string uri); + I2SState i2s_state_{I2S_STATE_STOPPED}; std::unique_ptr