diff --git a/main/audio/radio_pipeline.c b/main/audio/radio_pipeline.c index 8d2d43e..3ee0a32 100644 --- a/main/audio/radio_pipeline.c +++ b/main/audio/radio_pipeline.c @@ -178,6 +178,7 @@ static void decode_task(void *arg) uint32_t out_cap = DEC_OUT_CAP_INIT; uint8_t *out = malloc(out_cap); bool codec_open = false; + int dec_ch = 1; // channels reported by the stream (1 or 2) if (!inbuf || !out || !codec) { ESP_LOGE(TAG, "decode buffers/codec unavailable"); @@ -225,19 +226,21 @@ static void decode_task(void *arg) } if (frame.decoded_size > 0) { if (!codec_open) { - // Open the codec at the rate/channels reported by the stream - // on the first decoded PCM, exactly like aac_player.c. esp_audio_simple_dec_info_t info = {0}; esp_audio_simple_dec_get_info(dec, &info); - ESP_LOGI(TAG, "MP3 %" PRIu32 " Hz %u ch %u bit", + dec_ch = (info.channel >= 2) ? 2 : 1; + ESP_LOGI(TAG, "MP3 %" PRIu32 " Hz %u ch %u bit -> codec mono", info.sample_rate, info.channel, info.bits_per_sample); - lisael_udp_send("RADIO: decoded MP3 %" PRIu32 " Hz %u ch %u bit -> opening codec", - info.sample_rate, info.channel, info.bits_per_sample); + // Open the codec in MONO regardless of the stream: a stereo + // 44.1 kHz I2S slot needs more internal DMA RAM than is free + // (it fails "i2s_std_set_slot: dma descriptor"). The podcast + // path works precisely because its files are mono. We downmix + // stereo PCM below before writing. esp_codec_dev_close(codec); esp_codec_dev_sample_info_t fs = { .bits_per_sample = info.bits_per_sample, - .channel = info.channel, + .channel = 1, .sample_rate = info.sample_rate, }; esp_codec_dev_open(codec, &fs); @@ -245,8 +248,17 @@ static void decode_task(void *arg) (float)lisael_audio_get_volume()); codec_open = true; } - // Blocking write — this is what paces the whole pipeline. - esp_codec_dev_write(codec, frame.buffer, frame.decoded_size); + if (dec_ch == 2) { + // Downmix interleaved 16-bit stereo to mono, in place. + int16_t *pcm = (int16_t *)frame.buffer; + int frames = (int)(frame.decoded_size / 4); // 4 bytes/stereo frame + for (int i = 0; i < frames; i++) { + pcm[i] = (int16_t)(((int)pcm[2 * i] + (int)pcm[2 * i + 1]) / 2); + } + esp_codec_dev_write(codec, frame.buffer, frames * 2); + } else { + esp_codec_dev_write(codec, frame.buffer, frame.decoded_size); + } } if (raw.consumed == 0 && frame.decoded_size == 0) { break; // no progress on this chunk; fetch more from the network diff --git a/main/modes/radio.c b/main/modes/radio.c index f202ded..05a8dfd 100644 --- a/main/modes/radio.c +++ b/main/modes/radio.c @@ -38,9 +38,14 @@ typedef struct { // listen.radioking.com mounts. static const radio_station_t k_stations[] = { // Radio Doudou — comptines & berceuses pour les tout-petits. - { "Radio Doudou", "https://listen.radioking.com/radio/11565/stream/22961" }, + // Plain HTTP on purpose: the box's internal RAM is too tight to also run the + // mbedtls/AES handshake while streaming (TLS failed "esp-aes: alloc"). These + // RadioKing mounts serve identical audio over http:// (no 3xx to https). + { "Radio Doudou", "http://listen.radioking.com/radio/11565/stream/22961" }, // Radio Pomme d'Api (Bayard) — la radio des 3-7 ans. - { "Pomme d'Api", "https://listen.radioking.com/radio/361753/stream/411352" }, + { "Pomme d'Api", "http://listen.radioking.com/radio/361753/stream/411352" }, + // SuperLoustic — la radio des enfants (chansons, génériques, histoires). + { "SuperLoustic", "http://radio6.pro-fhi.net/radio/9004/stream" }, }; #define K_STATIONS_COUNT ((int)(sizeof(k_stations) / sizeof(k_stations[0])))