mirror of https://github.com/arendst/Tasmota.git
Audio for Core3, MP3Stream and Shine (#20540)
This commit is contained in:
parent
6b4254a014
commit
30c3165b6f
|
@ -79,7 +79,8 @@ typedef struct{
|
|||
uint8_t slot_config = I2S_SLOT_MSB;// B07 - slot configuration MSB = 0, PCM = 1, PHILIPS = 2
|
||||
uint8_t channels = 2; // B08 - mono/stereo - 1 is added for both
|
||||
bool apll = 1; // B09 - will be ignored on unsupported SOC's
|
||||
uint8_t spare[6]; // B0A-0F
|
||||
bool stream_enable = 0; // B0A - enable streaming of MP3
|
||||
uint8_t spare[5]; // B0B-0F
|
||||
} tx;
|
||||
struct {
|
||||
uint32_t sample_rate = 16000; // B00-03
|
||||
|
|
|
@ -65,6 +65,7 @@ void Cmd_Time(void);
|
|||
void Rtttl(char *buffer);
|
||||
void CmndI2SRtttl(void);
|
||||
void I2sWebRadioStopPlaying(void);
|
||||
void CmndI2SMP3Stream(void);
|
||||
|
||||
/*********************************************************************************************\
|
||||
* More structures
|
||||
|
@ -79,7 +80,7 @@ struct AUDIO_I2S_MP3_t {
|
|||
void *mp3ram = NULL;
|
||||
#endif // USE_I2S_MP3
|
||||
|
||||
#if defined(USE_I2S_MP3) || defined(USE_I2S_WEBRADIO)
|
||||
#if defined(USE_I2S_MP3) || defined(USE_I2S_WEBRADIO) || defined(USE_SHINE) || defined(MP3_MIC_STREAM)
|
||||
AudioGeneratorMP3 *decoder = NULL;
|
||||
TaskHandle_t mp3_task_handle;
|
||||
TaskHandle_t mic_task_handle;
|
||||
|
@ -108,6 +109,9 @@ struct AUDIO_I2S_MP3_t {
|
|||
|
||||
} audio_i2s_mp3;
|
||||
|
||||
#define I2S_AUDIO_MODE_MIC 1
|
||||
#define I2S_AUDIO_MODE_SPK 2
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands definitions
|
||||
\*********************************************************************************************/
|
||||
|
@ -1033,7 +1037,7 @@ void CmndI2SMicGain(void) {
|
|||
\*********************************************************************************************/
|
||||
|
||||
void I2sMp3Loop(void);
|
||||
void I2sMp3Init(void);
|
||||
void I2sMp3Init(uint32_t on);
|
||||
void MP3ShowStream(void);
|
||||
|
||||
bool Xdrv42(uint32_t function) {
|
||||
|
@ -1059,7 +1063,7 @@ bool Xdrv42(uint32_t function) {
|
|||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
audio_i2s.stream_enable = 1;
|
||||
audio_i2s.Settings->tx.stream_enable = 1;
|
||||
I2sMp3Init(1);
|
||||
#endif
|
||||
#if defined(I2S_BRIDGE)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#if ESP32 && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
|
||||
uint32_t SpeakerMic(uint8_t spkr) {
|
||||
|
|
|
@ -70,14 +70,14 @@ void mic_task(void *arg){
|
|||
|
||||
shine_set_config_mpeg_defaults(&config.mpeg);
|
||||
|
||||
if (audio_i2s.mic_channels == 1) {
|
||||
if (audio_i2s.Settings->rx.channels == 1) {
|
||||
config.mpeg.mode = MONO;
|
||||
} else {
|
||||
config.mpeg.mode = STEREO;
|
||||
}
|
||||
config.mpeg.bitr = 128;
|
||||
config.wave.samplerate = audio_i2s.mic_rate;
|
||||
config.wave.channels = (channels)audio_i2s.mic_channels;
|
||||
config.wave.samplerate = audio_i2s.Settings->rx.sample_rate;
|
||||
config.wave.channels = (channels)audio_i2s.Settings->rx.channels;
|
||||
|
||||
if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) {
|
||||
error = 3;
|
||||
|
@ -91,7 +91,7 @@ void mic_task(void *arg){
|
|||
}
|
||||
|
||||
samples_per_pass = shine_samples_per_pass(s);
|
||||
bytesize = samples_per_pass * 2 * audio_i2s.mic_channels;
|
||||
bytesize = samples_per_pass * 2 * audio_i2s.Settings->rx.channels;
|
||||
|
||||
buffer = (int16_t*)malloc(bytesize);
|
||||
if (!buffer) {
|
||||
|
@ -103,17 +103,18 @@ void mic_task(void *arg){
|
|||
|
||||
while (!audio_i2s_mp3.mic_stop) {
|
||||
uint32_t bytes_read;
|
||||
i2s_read(audio_i2s.mic_port, (char *)buffer, bytesize, &bytes_read, (100 / portTICK_RATE_MS));
|
||||
bytes_read = audio_i2s.in->readMic((uint8_t*)buffer, bytesize, true /*dc_block*/, false /*apply_gain*/, true /*lowpass*/, nullptr /*peak_ptr*/);
|
||||
// i2s_read(audio_i2s.mic_port, (char *)buffer, bytesize, &bytes_read, (100 / portTICK_PERIOD_MS));
|
||||
|
||||
if (audio_i2s.mic_gain > 1) {
|
||||
if (audio_i2s.Settings->rx.gain > 1) {
|
||||
// set gain
|
||||
for (uint32_t cnt = 0; cnt < bytes_read / 2; cnt++) {
|
||||
buffer[cnt] *= audio_i2s.mic_gain;
|
||||
buffer[cnt] *= audio_i2s.Settings->rx.gain;
|
||||
}
|
||||
}
|
||||
ucp = shine_encode_buffer_interleaved(s, buffer, &written);
|
||||
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
if (!audio_i2s.Settings->tx.stream_enable) {
|
||||
bwritten = mp3_out.write(ucp, written);
|
||||
if (bwritten != written) {
|
||||
break;
|
||||
|
@ -152,11 +153,11 @@ exit:
|
|||
audio_i2s_mp3.client.stop();
|
||||
}
|
||||
|
||||
SpeakerMic(MODE_SPK);
|
||||
SpeakerMic(I2S_AUDIO_MODE_SPK);
|
||||
audio_i2s_mp3.mic_stop = 0;
|
||||
audio_i2s_mp3.mic_error = error;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("mp3task result code: %d"), error);
|
||||
audio_i2s.mic_task_h = 0;
|
||||
audio_i2s_mp3.mic_task_handle = 0;
|
||||
audio_i2s_mp3.recdur = 0;
|
||||
audio_i2s_mp3.stream_active = 0;
|
||||
vTaskDelete(NULL);
|
||||
|
@ -166,14 +167,14 @@ exit:
|
|||
int32_t i2s_record_shine(char *path) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if (audio_i2s.mic_port == 0) {
|
||||
if (audio_i2s.in) {
|
||||
if (audio_i2s_mp3.decoder || audio_i2s_mp3.mp3) return 0;
|
||||
}
|
||||
|
||||
err = SpeakerMic(MODE_MIC);
|
||||
err = SpeakerMic(I2S_AUDIO_MODE_MIC);
|
||||
if (err) {
|
||||
if (audio_i2s.mic_port == 0) {
|
||||
SpeakerMic(MODE_SPK);
|
||||
if (audio_i2s.in) {
|
||||
SpeakerMic(I2S_AUDIO_MODE_SPK);
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("mic init error: %d"), err);
|
||||
return err;
|
||||
|
@ -191,7 +192,7 @@ esp_err_t err = ESP_OK;
|
|||
stack = 8000;
|
||||
}
|
||||
|
||||
err = xTaskCreatePinnedToCore(mic_task, "MIC", stack, NULL, 3, &audio_i2s.mic_task_h, 1);
|
||||
err = xTaskCreatePinnedToCore(mic_task, "MIC", stack, NULL, 3, &audio_i2s_mp3.mic_task_handle, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -206,7 +207,7 @@ void Cmd_MicRec(void) {
|
|||
ResponseCmndChar(XdrvMailbox.data);
|
||||
}
|
||||
} else {
|
||||
if (audio_i2s.mic_task_h) {
|
||||
if (audio_i2s_mp3.mic_task_handle) {
|
||||
// stop task
|
||||
audio_i2s_mp3.mic_stop = 1;
|
||||
while (audio_i2s_mp3.mic_stop) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#ifdef ESP32
|
||||
#if defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if defined(USE_SHINE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
|
||||
#ifdef MP3_MIC_STREAM
|
||||
|
@ -61,4 +61,4 @@ void Cmd_MP3Stream(void) {
|
|||
|
||||
|
||||
#endif // USE_SHINE
|
||||
#endif // ESP32
|
||||
#endif // defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
xdrv_42_2_i2s_mp3stream_idf51.ino - Audio dac support for Tasmota
|
||||
|
||||
Copyright (C) 2024 Gerhard Mutz and Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
||||
#if defined(USE_I2S_AUDIO) && defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
|
||||
#ifndef MP3_STREAM_PORT
|
||||
#define MP3_STREAM_PORT 81
|
||||
#endif
|
||||
|
||||
|
||||
void Stream_mp3(void) {
|
||||
if (!audio_i2s.Settings->tx.stream_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_i2s_mp3.stream_active) {
|
||||
return;
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Handle mp3server"));
|
||||
audio_i2s_mp3.stream_active = 1;
|
||||
audio_i2s_mp3.client = audio_i2s_mp3.MP3Server->client();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Create client"));
|
||||
i2s_record_shine((char*)"stream.mp3");
|
||||
}
|
||||
|
||||
void I2sMp3Loop(void) {
|
||||
if (audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server->handleClient();
|
||||
}
|
||||
}
|
||||
|
||||
void I2sMp3Init(uint32_t on) {
|
||||
if (on) {
|
||||
if (!audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server = new ESP8266WebServer(MP3_STREAM_PORT);
|
||||
audio_i2s_mp3.MP3Server->on(PSTR("/stream.mp3"), Stream_mp3);
|
||||
audio_i2s_mp3.MP3Server->on(PSTR("/stream.m3a"), Stream_mp3);
|
||||
audio_i2s_mp3.MP3Server->begin();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server created on port: %d "), MP3_STREAM_PORT);
|
||||
}
|
||||
} else {
|
||||
if (audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server->stop();
|
||||
delete audio_i2s_mp3.MP3Server;
|
||||
audio_i2s_mp3.MP3Server = nullptr;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server deleted"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CmndI2SMP3Stream(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
|
||||
audio_i2s_mp3.stream_enable = XdrvMailbox.payload;
|
||||
}
|
||||
I2sMp3Init(audio_i2s_mp3.stream_enable);
|
||||
ResponseCmndNumber(audio_i2s_mp3.stream_enable);
|
||||
}
|
||||
|
||||
#endif // defined(USE_I2S_AUDIO) && defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
#endif // defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
Loading…
Reference in New Issue