Documentation: https://esphome.io/
For issues, please go to the issue tracker.
For feature requests, please see feature requests.
This project forked from schreibfaul1/esp32-audioi2s
Play mp3 files from SD via I2S
License: GNU General Public License v3.0
Documentation: https://esphome.io/
For issues, please go to the issue tracker.
For feature requests, please see feature requests.
This fork hasn't been updated for a long time. I recommend making your own.
For example: https://github.com/melwinek/ESP32-audioI2S
In YAML you need to add:
esphome:
libraries:
I went to try and build it on my esp32-c3 and it failed to compile. At first glance it looks like it could be a type issue based on the library, but I really don't know enough to submit a PR or be more helpful, sorry! I did notice the old version of this library did not support the C3, so I thought it also could be something with that. Any ideas?
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'void UnpackQuads(int, int, int*)':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:3289:106: error: invalid conversion from 'int*' to 'int32_t*' {aka 'long int*'} [-fpermissive]
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET], bitBuf, &val);
^~~~
In file included from .pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:9:
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.h:490:115: note: initializing argument 4 of 'int DecodeHuffmanScalar(const short int*, const HuffInfo_t*, unsigned int, int32_t*)'
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
~~~~~~~~~^~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'void UnpackPairsNoEsc(int, int, int*)':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:3336:104: error: invalid conversion from 'int*' to 'int32_t*' {aka 'long int*'} [-fpermissive]
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val);
^~~~
In file included from .pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:9:
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.h:490:115: note: initializing argument 4 of 'int DecodeHuffmanScalar(const short int*, const HuffInfo_t*, unsigned int, int32_t*)'
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
~~~~~~~~~^~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'void UnpackPairsEsc(int, int, int*)':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:3378:104: error: invalid conversion from 'int*' to 'int32_t*' {aka 'long int*'} [-fpermissive]
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val);
^~~~
In file included from .pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:9:
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.h:490:115: note: initializing argument 4 of 'int DecodeHuffmanScalar(const short int*, const HuffInfo_t*, unsigned int, int32_t*)'
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
~~~~~~~~~^~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'int DecodeOneScaleFactor()':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:4179:82: error: invalid conversion from 'int*' to 'int32_t*' {aka 'long int*'} [-fpermissive]
nBits = DecodeHuffmanScalar(huffTabScaleFact, &huffTabScaleFactInfo, bitBuf, &val);
^~~~
In file included from .pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:9:
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.h:490:115: note: initializing argument 4 of 'int DecodeHuffmanScalar(const short int*, const HuffInfo_t*, unsigned int, int32_t*)'
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
~~~~~~~~~^~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'void GenerateNoiseVector(int*, int*, int)':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:5313:41: error: invalid conversion from 'uint32_t*' {aka 'long unsigned int*'} to 'unsigned int*' [-fpermissive]
coef[i] = ((int32_t)Get32BitVal((uint32_t *)last)) >> 16;
^~~~~~~~~~~~~~~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:5146:40: note: initializing argument 1 of 'unsigned int Get32BitVal(unsigned int*)'
unsigned int Get32BitVal(unsigned int *last)
~~~~~~~~~~~~~~^~~~
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp: In function 'int DecodeOneSymbol(int)':
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:8549:57: error: invalid conversion from 'int*' to 'int32_t*' {aka 'long int*'} [-fpermissive]
nBits = DecodeHuffmanScalar(huffTabSBR, hi, bitBuf, &val);
^~~~
In file included from .pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.cpp:9:
.pio/libdeps/c3_pico/ESP32-audioI2S/src/aac_decoder/aac_decoder.h:490:115: note: initializing argument 4 of 'int DecodeHuffmanScalar(const short int*, const HuffInfo_t*, unsigned int, int32_t*)'
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, int32_t *val);
~~~~~~~~~^~~
*** [.pio\build\c3_pico\lib645\ESP32-audioI2S\aac_decoder\aac_decoder.cpp.o] Error 1
Removed, this was posted in the wrong spot.
When playing a local file from HA (/media/local/...), HA will generate a full URL with an access token that can sometimes be very long.
Due to this line, if the URL is 503 or more characters long, it just won't play without any feedback:
if(lenHost >= 512 - 10) {
AUDIO_INFO("Hostaddress is too long");
return false;
}
This looks kinda arbitrary to not malloc more than 512 bytes, a few lines below.
Because HA limits the token to the media specific path, the token is at least as long as the file path itself, meaning we can only reach files where the path is "short".
Here is an example (not exposed, test only instance, the token is no secret) which is 542 chars long:
https://hass-xxxxx.xxxxxxxxx.rthoni.com/media/local/Lesse/Musique/Starmania-Live_Int%C3%A9grale_-_Version_originale_-_CD2/08.S.O.S._dun_terrien_en_d%C3%A9tresse.mp3?authSig=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI2MTMwYmZiM2NkZWM0ZmZkOTAxODk4ZDk4YzVlZjJkYiIsInBhdGgiOiIvbWVkaWEvbG9jYWwvTGVzc2UvTXVzaXF1ZS9TdGFybWFuaWEtTGl2ZV9JbnTDqWdyYWxlXy1fVmVyc2lvbl9vcmlnaW5hbGVfLV9DRDIvMDguUy5PLlMuX2R1bl90ZXJyaWVuX2VuX2TDqXRyZXNzZS5tcDMiLCJwYXJhbXMiOltdLCJpYXQiOjE2OTgyNTUyNTAsImV4cCI6MTY5ODM0MTY1MH0.fjWFtV4gKvW_JtnKl8G8YOC8IPgcKFgwBJb5Ak3T4WU
Is there any reason to limit the URL (host
parameter) to something that short?
Can we just, either completely remove that limit, or increase it to at least 1024?
I have setup a directory on the SD card with multiple MP3 files. I start playing the first MP3 file in Setup, then in audio_eof_mp3 find the next MP3 file in the directory and use connecttoFS to start playing that file. The first two files play correctly, but after that each file in the directory is opened and then audio_eof_mp3 is immediately called again with the end of file before any audio is played.
platformio.ini:
`[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
upload_port = COM11
monitor_speed = 115200
lib_deps =
# https://github.com/schreibfaul1/ESP32-audioI2S
esphome/ESP32-audioI2S @ ^2.0.7`
main.cpp:
`
#include <Arduino.h>
#include "Audio.h"
#include "SD.h"
#include "SPI.h"
#include "FS.h"
Audio audio;
// Steup SD Card
#define SD_CS 10
#define SD_MOSI 11
#define SD_CLK 12
#define SD_MISO 13
SPIClass spiSD(HSPI);
// Setup I2S
#define I2S_BCLK 6
#define I2S_LRC 7
#define I2S_DOUT 19
// prototypes
void printDirectory(File dir, int numTabs);
void audio_eof_mp3(const char *info);
String audioDir;
File dirOpen;
void setup() {
Serial.begin(112500);
// Setup SD Card
Serial.println("\nSD Card: Initializing ... ");
Serial.print(" SD_CLK Pin "); Serial.println(SD_CLK);
Serial.print(" SD_MISO Pin "); Serial.println(SD_MISO);
Serial.print(" SD_MOSI Pin "); Serial.println(SD_MOSI);
Serial.print(" SD_CS Pin "); Serial.println(SD_CS);
spiSD.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, spiSD)) {
Serial.println(" FAILED");
}
else {
Serial.println(" Success");
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println(" SD Card: Error, no SD card");
return;
}
else {
Serial.print("SD Card Type: ");
if (cardType == CARD_MMC) {
Serial.println("MMC");
} else if (cardType == CARD_SD) {
Serial.println("SDSC");
} else if (cardType == CARD_SDHC) {
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
// List Files on SD Card
audioDir = "/mp3";
dirOpen = SD.open(audioDir);
Serial.printf("\nDirectory: %s\n", audioDir);
printDirectory(dirOpen, 0);
Serial.println("SD Card: End of List\n");
dirOpen.close();
}
}
// Audio Setup
Serial.println("\nAudio I2s: Initializing ... ");
Serial.print(" I2S_BCLK Pin "); Serial.println(I2S_BCLK);
Serial.print(" I2S_LRC Pin "); Serial.println(I2S_LRC);
Serial.print(" I2S_DOUT Pin "); Serial.println(I2S_DOUT);
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
audio.setVolume(21); // 0...21
dirOpen = SD.open(audioDir);
File audioFile = dirOpen.openNextFile();
if (audioFile) {
String filePath = audioDir + "/" + String(audioFile.name());
if (audio.connecttoFS(SD, filePath.c_str())) {
Serial.print("File Opened: "); Serial.println(filePath);
}
else {
Serial.print("ERROR: Failed to open file"); Serial.println(filePath);
}
}
else {
Serial.printf("ERROR: Directory %s is empty", audioDir);
}
Serial.println("\nSetup Done");
}
void loop() {
audio.loop();
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void audio_eof_mp3(const char *info){ //end of file
Serial.printf("End of file: %s\n", info);
File audioFile = dirOpen.openNextFile();
Serial.print("Next File: "); Serial.println(audioFile.name());
if (audioFile) {
String filePath = audioDir + "/" + String(audioFile.name());
if (audio.connecttoFS(SD, filePath.c_str())) {
Serial.print("File Opened: "); Serial.println(filePath);
}
else {
Serial.print("ERROR: Failed to open file"); Serial.println(filePath);
}
}
else {
Serial.printf("End of Directory");
}
}
`
The last update was done a long time ago, while development continued upstream. For seperate work on the esphome audio stack it would be nice if we had an up to date version here.
Additinally this repository doesn't seem to be maintained. There is one PR open that'd help with the voice assistant and 2 PRs to update it.
Maybe we can instead upstream the little changes here and not maintain an own fork in the first place.
Hier sollte einmal ein Update gemacht werden. Das Original ist Version 3.0.8 Siehe https://github.com/schreibfaul1/ESP32-audioI2S.git
media_player can play http streams (such as HA TTS source or webstreams) but they are not able to play their https variants. Since HA is recommended to be hosted on HTTPS this is a must to have addition.
Please add a default option as verify_ssl=false. to media_player urls.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.