Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

FormatConverterStream causing dropouts (under-runs?) during channel conversion #2135

Answered by pschatzmann
z-l-p asked this question in Q&A
Discussion options

I'm using FormatConverterStream to convert URLstreams with different sampling rates and channel counts, so they can eventually be sent to a mixer for further processing. I've observed the following:

  • Sampling Rate conversion works great
  • Channel conversion (mono to stereo) works fine for a few seconds before the sound breaks up.

I see no changes in the log when the sound starts breaking up, but the pace of the messages slows down to match the gaps in the audio:

[I] StreamCopy.h : 173 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 376 -> 376 -> 376 bytes - in 1 hops

(also, if I specify a larger buffer size in the StreamCopy constructor, I see no effect in the copy sizes decribed in the logs, but maybe I'm misunderstanding that?)

Test sketch that shows the problem with a mono -> stereo conversion after a few seconds:


#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
const char *ssid = ""; // Change this to your WiFi SSID
const char *password = ""; // Change this to your WiFi password
AudioInfo out_info(44100, 2, 16); // destination format for I2S (all streams will be converted to this)
URLStream url;
I2SStream i2s;
VolumeStream vol(i2s);
FormatConverterStream conv(vol);
MultiDecoder multi(url);
MP3DecoderHelix mp3;
EncodedAudioStream dec(&conv, &multi); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
 Serial.begin(115200);
 Serial.println();
 Serial.println("******************************************************");
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info); 
 
 // setup i2s
 auto config = i2s.defaultConfig(TX_MODE);
 config.copyFrom(out_info);
 // Custom I2S pins for my Xaio board
 config.pin_ws = 9; // (DAC "LRCK")
 config.pin_bck = 7; // (DAC "BCK")
 config.pin_data = 8; // (DAC "DIN")
 i2s.begin(config);
// setup VolumeStream
 auto vcfg = vol.defaultConfig();
 vcfg.allow_boost = true; // activate amplification using linear control
 vol.begin(vcfg);
 // setup audio converter
 conv.begin(multi.audioInfo(), out_info);
 // setup decoder
 multi.addDecoder(mp3, "audio/mpeg");
 dec.begin();
 url.begin("https://locus.creacast.com:9443/kernot_lillypilly.mp3"); // MONO STREAM
}
void loop() {
 copier.copy();
}
You must be logged in to vote

I can see the issue in the log: when helix reports mono, I2S is switched to mono, but it should stay as stereo.

[I] AudioTypes.h : 124 - MP3DecoderHelix sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rat...

Replies: 4 comments 4 replies

Comment options

Please share the log: double check that i2s gets informormed about the 2 channels.
Did you try just using the ChannelFormatConverterStream instead ?

You must be logged in to vote
2 replies
Comment options

I haven't tried ChannelFormatConverterStream yet (because I also need samplerate conversion for some streams) but here's the full log. (It seems like I2S begins in stereo, switches to mono but then back to stereo (with 1->2 channel conversion). The odd thing is that the conversion works great for a few seconds before the sound falls apart. (I've tried several streams with different sample rates and channel counts. The problem only occurs on mono streams.)

[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SConfigESP32V1.h : 78 - rx/tx mode: TX_MODE
[I] I2SConfigESP32V1.h : 79 - port_no: 0
[I] I2SConfigESP32V1.h : 80 - is_master: Master
[I] I2SConfigESP32V1.h : 81 - sample rate: 44100
[I] I2SConfigESP32V1.h : 82 - bits per sample: 16
[I] I2SConfigESP32V1.h : 83 - number of channels: 2
[I] I2SConfigESP32V1.h : 84 - signal_type: Digital
[I] I2SConfigESP32V1.h : 85 - buffer_count:6
[I] I2SConfigESP32V1.h : 86 - buffer_size:512
[I] I2SConfigESP32V1.h : 87 - auto_clear: true
[I] I2SConfigESP32V1.h : 89 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32V1.h : 101 - pin_bck: 7
[I] I2SConfigESP32V1.h : 104 - pin_ws: 9
[I] I2SConfigESP32V1.h : 107 - pin_data: 8
[I] I2SESP32V1.h : 259 - dma_frame_num: 768
[I] I2SESP32V1.h : 164 - tx: 8, rx: -1
[I] I2SESP32V1.h : 283 - mclk_multiple=256
[I] VolumeStream.h : 199 - setVolume: 1.000000 at 0
[I] VolumeStream.h : 199 - setVolume: 1.000000 at 1
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioStreamsConverter.h : 134 - --> ChannelFormatConverterStream
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 177 - --> ChannelFormatConverterStream
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioStreamsConverter.h : 179 - begin 2 -> 2 channels
[I] AudioStreamsConverter.h : 24 - begin 2 -> 2 channels
[I] AudioStreamsConverter.h : 502 - begin 16 -> 16 bits
[I] AudioStreamsConverter.h : 515 - no bit conversion: 16 -> 16
[I] ResampleStream.h : 64 - begin step_size: 1.000000
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] URLStream.h : 90 - virtual bool audio_tools::URLStream::begin(const char*, const char*, MethodID, const char*, const char*): https://locus.creacast.com:9443/kernot_lillypilly.mp3
[I] Url.h : 59 - Url::parse
[I] Url.h : 97 - url->https://locus.creacast.com:9443/kernot_lillypilly.mp3
[I] Url.h : 98 - host->locus.creacast.com
[I] Url.h : 99 - protocol->https
[I] Url.h : 100 - path->/kernot_lillypilly.mp3
[I] Url.h : 101 - port->9443
[I] URLStream.h : 378 - WiFiClientSecure
[I] HttpRequest.h : 240 - process connecting to host locus.creacast.com port 9443
[I] HttpRequest.h : 367 - is connected true with timeout 60000
[I] HttpRequest.h : 251 - Free heap: 205412
[I] HttpHeader.h : 262 - HttpHeader::write
[I] HttpHeader.h : 417 - -> GET /kernot_lillypilly.mp3 HTTP/1.1
[I] HttpHeader.h : 196 - -> Host: locus.creacast.com 
[I] HttpHeader.h : 196 - -> Connection: keep-alive 
[I] HttpHeader.h : 196 - -> Accept-Encoding: identity 
[I] HttpHeader.h : 196 - -> Accept: */* 
[I] HttpHeader.h : 338 - -> <CR LF> 
[I] HttpRequest.h : 316 - Request written ... waiting for reply
[I] HttpHeader.h : 230 - Waiting for data...
[I] HttpHeader.h : 239 - Data available: 481
[I] HttpHeader.h : 110 - Content-Type: audio/mpeg
[I] HttpRequest.h : 181 - no CONTENT_LENGTH found in reply
[I] URLStream.h : 98 - contentLength: 0
[I] URLStream.h : 241 - Request written ... waiting for reply
[I] URLStream.h : 105 - ==> http status: 200
[I] URLStream.h : 105 - ==> http status: 200
[I] MultiDecoder.h : 247 - mime from http request: audio/mpeg
[I] MultiDecoder.h : 199 - Using decoder for audio/mpeg (audio/mpeg)
[I] CodecMP3Helix.h : 82 - virtual bool audio_tools::MP3DecoderHelix::begin()
[I] MultiDecoder.h : 208 - Decoder audio/mpeg started
[I] StreamCopy.h : 173 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 376 -> 376 -> 376 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 376 -> 376 -> 376 bytes - in 1 hops
[I] AudioTypes.h : 124 - MP3DecoderHelix sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 105 - restarting i2s
[I] AudioTypes.h : 124 - I2SStream sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SConfigESP32V1.h : 78 - rx/tx mode: TX_MODE
[I] I2SConfigESP32V1.h : 79 - port_no: 0
[I] I2SConfigESP32V1.h : 80 - is_master: Master
[I] I2SConfigESP32V1.h : 81 - sample rate: 44100
[I] I2SConfigESP32V1.h : 82 - bits per sample: 16
[I] I2SConfigESP32V1.h : 83 - number of channels: 1
[I] I2SConfigESP32V1.h : 84 - signal_type: Digital
[I] I2SConfigESP32V1.h : 85 - buffer_count:6
[I] I2SConfigESP32V1.h : 86 - buffer_size:512
[I] I2SConfigESP32V1.h : 87 - auto_clear: true
[I] I2SConfigESP32V1.h : 89 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32V1.h : 101 - pin_bck: 7
[I] I2SConfigESP32V1.h : 104 - pin_ws: 9
[I] I2SConfigESP32V1.h : 107 - pin_data: 8
[I] I2SESP32V1.h : 259 - dma_frame_num: 1536
[I] I2SESP32V1.h : 164 - tx: 8, rx: -1
[I] I2SESP32V1.h : 283 - mclk_multiple=256
[W] I2SESP32V1.h : 241 - Using channel_format: I2SChannelSelect::Left for mono
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 134 - --> ChannelFormatConverterStream
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 105 - restarting i2s
[I] AudioTypes.h : 124 - I2SStream sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SConfigESP32V1.h : 78 - rx/tx mode: TX_MODE
[I] I2SConfigESP32V1.h : 79 - port_no: 0
[I] I2SConfigESP32V1.h : 80 - is_master: Master
[I] I2SConfigESP32V1.h : 81 - sample rate: 44100
[I] I2SConfigESP32V1.h : 82 - bits per sample: 16
[I] I2SConfigESP32V1.h : 83 - number of channels: 2
[I] I2SConfigESP32V1.h : 84 - signal_type: Digital
[I] I2SConfigESP32V1.h : 85 - buffer_count:6
[I] I2SConfigESP32V1.h : 86 - buffer_size:512
[I] I2SConfigESP32V1.h : 87 - auto_clear: true
[I] I2SConfigESP32V1.h : 89 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32V1.h : 101 - pin_bck: 7
[I] I2SConfigESP32V1.h : 104 - pin_ws: 9
[I] I2SConfigESP32V1.h : 107 - pin_data: 8
[I] I2SESP32V1.h : 259 - dma_frame_num: 768
[I] I2SESP32V1.h : 164 - tx: 8, rx: -1
[I] I2SESP32V1.h : 283 - mclk_multiple=256
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] StreamCopy.h : 173 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 376 -> 376 -> 376 bytes - in 1 hops
[I] StreamCopy.h : 173 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
Comment options

A hint:
The mono streams are playing at double the sampling rate. It's been hard to tell on my test streams of environmental audio, but here's an old radio show that makes it obvious:
https://archive.org/download/OTRR_This_Is_Your_FBI_Singles/This%20Is%20Your%20FBI%2051年12月28日%20(352)%20The%20Intruder.mp3

Comment options

I'm bumping this after doing some more troubleshooting. If I pass manually-configured AudioInfo objects to the FormatConverterStream.begin() method then mono-stereo conversion works perfectly, but if I try to use the automatic propagation from the decoder as an inputconv.begin(multi.audioInfo(), out_info); then it doesn't seem to update, even though multi.audioInfo() seems to correctly reflect the currently-loaded stream (based on printing it in the loop).
Even if I refresh it in the loop with conv.setAudioInfo(multi.audioInfo()); after a URL loads, the problem persists. (Stereo streams with different sampling rates seem to work fine, converting 48 to 44.1 when needed, with no pitch changes).

How can I use FormatConverterStream to dynamically change channel-counts after .begin()?

Reminder of the symptoms: mono URLstreams play at double speed for a few seconds and then start stuttering (probably since they are emptying 2x faster than filling).

You must be logged in to vote
0 replies
Comment options

I can see the issue in the log: when helix reports mono, I2S is switched to mono, but it should stay as stereo.

[I] AudioTypes.h : 124 - MP3DecoderHelix sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] I2SStream.h : 105 - restarting i2s

I committed a correction: double check if this makes a difference and provide the updated log.

ps. Please note that when you call conv.begin(multi.audioInfo(), out_info), multi.audioInfo() is still stereo because the decoding has not started yet.

You must be logged in to vote
1 reply
Comment options

Thanks for the update. I synced the library changes. The problem persists, though. I included the log from the test above, and also tried a few new things to troubleshoot:

  • Added conv.end() and conv.begin(multi.audioInfo(), out_info) after the url.begin() - no improvement

  • Added conv.setAudioInfo(multi.audioInfo()) after the url.begin() - no improvement

  • In setup() I called manually configured AudioInfo objects conv.begin(mono_info, stereo_info). This worked perfectly. I also switched between the AudioInfo objects in the loop using conv.setAudioInfo() and it changed correctly. BUT, if the input to conv.begin() was the multiDecoder then it ignored future setAudioInfo() attempts. Maybe the MultiDecoder is sending the wrong AudioInfo down the chain, overriding future changes to FormatConverterStream settings? (I've been printing multi.audioInfo().channels and it doesn't seem to change between mono and stereo urls.)

  • Another detail that confuses me: Even without a FormatConverterStream, a mono stream will play from both channels of my stereo i2s sink, like there's an implicit channel expander somewhere?

The log from test code above:

...[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SConfigESP32V1.h : 78 - rx/tx mode: TX_MODE
[I] I2SConfigESP32V1.h : 79 - port_no: 0
[I] I2SConfigESP32V1.h : 80 - is_master: Master
[I] I2SConfigESP32V1.h : 81 - sample rate: 44100
[I] I2SConfigESP32V1.h : 82 - bits per sample: 16
[I] I2SConfigESP32V1.h : 83 - number of channels: 2
[I] I2SConfigESP32V1.h : 84 - signal_type: Digital
[I] I2SConfigESP32V1.h : 85 - buffer_count:6
[I] I2SConfigESP32V1.h : 86 - buffer_size:512
[I] I2SConfigESP32V1.h : 87 - auto_clear: true
[I] I2SConfigESP32V1.h : 89 - i2s_format: I2S_STD_FORMAT
[I] I2SConfigESP32V1.h : 101 - pin_bck: 7
[I] I2SConfigESP32V1.h : 104 - pin_ws: 9
[I] I2SConfigESP32V1.h : 107 - pin_data: 8
[I] I2SESP32V1.h : 259 - dma_frame_num: 768
[I] I2SESP32V1.h : 164 - tx: 8, rx: -1
[I] I2SESP32V1.h : 283 - mclk_multiple=256
[I] VolumeStream.h : 199 - setVolume: 1.000000 at 0
[I] VolumeStream.h : 199 - setVolume: 1.000000 at 1
[I] VolumeStream.h : 199 - setVolume: 0.040000 at 0
[I] VolumeStream.h : 199 - setVolume: 0.040000 at 1
[I] AudioStreamsConverter.h : 784 - virtual void audio_tools::FormatConverterStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 134 - --> ChannelFormatConverterStream
[I] AudioStreamsConverter.h : 177 - --> ChannelFormatConverterStream
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioStreamsConverter.h : 179 - begin 2 -> 2 channels
[I] AudioStreamsConverter.h : 24 - begin 2 -> 2 channels
[I] AudioStreamsConverter.h : 502 - begin 16 -> 16 bits
[I] AudioStreamsConverter.h : 515 - no bit conversion: 16 -> 16
[I] ResampleStream.h : 64 - begin step_size: 1.000000
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] URLStream.h : 90 - virtual bool audio_tools::URLStream::begin(const char*, const char*, MethodID, const char*, const char*): https://s2.yesstreaming.net:17161/stream
[I] Url.h : 59 - Url::parse
[I] Url.h : 97 - url->https://s2.yesstreaming.net:17161/stream
[I] Url.h : 98 - host->s2.yesstreaming.net
[I] Url.h : 99 - protocol->https
[I] Url.h : 100 - path->/stream
[I] Url.h : 101 - port->17161
[I] URLStream.h : 378 - WiFiClientSecure
[I] HttpRequest.h : 240 - process connecting to host s2.yesstreaming.net port 17161
[I] HttpRequest.h : 367 - is connected true with timeout 60000
[I] HttpRequest.h : 251 - Free heap: 178304
[I] HttpHeader.h : 262 - HttpHeader::write
[I] HttpHeader.h : 417 - -> GET /stream HTTP/1.1
[I] HttpHeader.h : 196 - -> Host: s2.yesstreaming.net 
[I] HttpHeader.h : 196 - -> Connection: keep-alive 
[I] HttpHeader.h : 196 - -> Accept-Encoding: identity 
[I] HttpHeader.h : 196 - -> Accept: */* 
[I] HttpHeader.h : 338 - -> <CR LF> 
[I] HttpRequest.h : 316 - Request written ... waiting for reply
[I] HttpHeader.h : 230 - Waiting for data...
[I] HttpHeader.h : 239 - Data available: 500
[I] HttpHeader.h : 110 - Content-Type: audio/mpeg
[I] HttpRequest.h : 181 - no CONTENT_LENGTH found in reply
[I] URLStream.h : 98 - contentLength: 0
[I] URLStream.h : 241 - Request written ... waiting for reply
[I] URLStream.h : 105 - ==> http status: 200
[I] MultiDecoder.h : 247 - mime from http request: audio/mpeg
[I] MultiDecoder.h : 199 - Using decoder for audio/mpeg (audio/mpeg)
[I] CodecMP3Helix.h : 82 - virtual bool audio_tools::MP3DecoderHelix::begin()
[I] MultiDecoder.h : 208 - Decoder audio/mpeg started
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] AudioTypes.h : 124 - MP3DecoderHelix sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 784 - virtual void audio_tools::FormatConverterStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 134 - --> ChannelFormatConverterStream
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioStreamsConverter.h : 465 - -> NumberFormatConverterStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] ResampleStream.h : 145 - setStepSize: 1.000000
[I] ResampleStream.h : 129 - -> ResampleStream:
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] I2SStream.h : 96 - virtual void audio_tools::I2SStream::setAudioInfo(audio_tools::AudioInfo)
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] AudioTypes.h : 124 - in: sample_rate: 44100 / channels: 1 / bits_per_sample: 16
[I] AudioTypes.h : 124 - out: sample_rate: 44100 / channels: 2 / bits_per_sample: 16
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 3 hops
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops
[I] StreamCopy.h : 176 - StreamCopy::copy 1024 -> 1024 -> 1024 bytes - in 1 hops

Here is a test sketch where I'm alternating between mono and stereo URLS every 10 seconds. (I know you use an AudioKit, so I tried to make it easy: Just flip audioKit to 1 and hopefully everything will work!

#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#define audioKit 0 // 0 for Zach's Xaio+DAC, 1 for Phil's AudioKit
const char *ssid = ""; // Change this to your WiFi SSID
const char *password = ""; // Change this to your WiFi password
#if (audioKit == 1)
 AudioBoardStream i2s(AudioKitEs8388V1);
#else 
 I2SStream i2s;
#endif
AudioInfo stereo_info(44100, 2, 16); // destination format for I2S (all streams will be converted to this)
AudioInfo mono_info(44100, 1, 16); // specs for typical mono stream
URLStream url;
VolumeStream vol(i2s);
FormatConverterStream conv(vol);
MultiDecoder multi(url);
MP3DecoderHelix mp3;
EncodedAudioStream dec(&conv, &multi); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
static bool lastSwitch = 0;
void setup(){
 Serial.begin(115200);
 Serial.println();
 Serial.println("******************************************************");
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning); 
 
 // setup i2s
 auto config = i2s.defaultConfig(TX_MODE);
 config.copyFrom(stereo_info);
 if (audioKit == 0) {
 // Custom I2S pins for my Xaio board
 config.pin_ws = 9; // (DAC "LRCK")
 config.pin_bck = 7; // (DAC "BCK")
 config.pin_data = 8; // (DAC "DIN")
 }
 i2s.begin(config);
// setup VolumeStream
 auto vcfg = vol.defaultConfig();
 vcfg.allow_boost = true; // activate amplification using linear control
 vol.begin(vcfg);
 if (audioKit == 0) {
 vol.setVolume(0.03); // For my setup where amp gain is fixed and very loud!
 }
 // setup audio converter
 conv.begin(mono_info, stereo_info);
 // setup decoder
 multi.addDecoder(mp3, "audio/mpeg");
 dec.begin();
 Serial.println("Starting MONO Stream (after conv.begin)");
 url.begin("https://s2.yesstreaming.net:17161/stream"); // MONO 44k STREAM
}
void loop() {
 copier.copy();
 static uint32_t lastSerialOutputTime;
 static uint32_t lastURLTime;
 char debugInfo[128];
 if(millis() - lastSerialOutputTime > 1000){
 if (lastSwitch == 1) {
 Serial.println("(MONO Stream...)");
 } else {
 Serial.println("(STEREO Stream...)");
 }
 snprintf(debugInfo, 96,"STREAM Samplerate: %d, Depth: %d, Channels: %d", multi.audioInfo().sample_rate, multi.audioInfo().bits_per_sample, multi.audioInfo().channels );
 Serial.println(debugInfo);
 snprintf(debugInfo, 96,"OUTPUT Samplerate: %d, Depth: %d, Channels: %d", i2s.audioInfo().sample_rate, i2s.audioInfo().bits_per_sample, i2s.audioInfo().channels );
 Serial.println(debugInfo);
 Serial.println("");
 lastSerialOutputTime = millis();
 }
 
 if(millis() - lastURLTime > 10000) {
 if (lastSwitch == 0) {
 Serial.println("Starting MONO Stream");
 url.end();
 //conv.end();
 url.begin("https://s2.yesstreaming.net:17161/stream"); // MONO 44k STREAM
 conv.setAudioInfo(mono_info);
 //conv.begin(multi.audioInfo(), stereo_info);
 lastSwitch = 1;
 
 } else {
 Serial.println("Starting STEREO Stream");
 url.end();
 //conv.end();
 url.begin("http://s1.voscast.com:8652/stream"); // STEREO 44k STREAM
 conv.setAudioInfo(stereo_info);
 //conv.begin(multi.audioInfo(), stereo_info);
 lastSwitch = 0;
 }
 lastURLTime = millis();
 }
}
Answer selected by pschatzmann
Comment options

I committed some corrections to the AudioTools

  • channel changes via setAudioInfo() are now automatically restarting the ChannelFormatConverterStream

and LibHelix library

  • audio change notifications are sent not only for sample rate but also for channel changes

The following sketch is working now for me. I printing the AudioInfo for the full chain. Please note that it takes at least a copy() step for the decoder to inform about a change:

#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#define audioKit 1 // 0 for Zach's Xaio+DAC, 1 for Phil's AudioKit
const char *ssid = "tbd"; // Change this to your WiFi SSID
const char *password = "tbd"; // Change this to your WiFi password
#if (audioKit == 1)
AudioBoardStream i2s(AudioKitEs8388V1);
#else
I2SStream i2s;
#endif
AudioInfo stereo_info(44100, 2, 16); // destination format for I2S (all streams will be converted to this)
AudioInfo mono_info(44100, 1, 16); // specs for typical mono stream
URLStream url;
VolumeStream vol(i2s);
FormatConverterStream conv(vol);
MultiDecoder multi(url);
MP3DecoderHelix mp3;
EncodedAudioStream dec(&conv, &multi); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
static bool lastSwitch = 0;
void setup() {
 Serial.begin(115200);
 Serial.println();
 Serial.println("******************************************************");
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 //AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
 // setup i2s
 auto config = i2s.defaultConfig(TX_MODE);
 config.copyFrom(stereo_info);
 if (audioKit == 0) {
 // Custom I2S pins for my Xaio board
 config.pin_ws = 9; // (DAC "LRCK")
 config.pin_bck = 7; // (DAC "BCK")
 config.pin_data = 8; // (DAC "DIN")
 }
 i2s.begin(config);
 // setup VolumeStream
 auto vcfg = vol.defaultConfig();
 vcfg.allow_boost = true; // activate amplification using linear control
 vol.begin(vcfg);
 if (audioKit == 0) {
 vol.setVolume(0.03); // For my setup where amp gain is fixed and very loud!
 }
 // setup audio converter: any of these variants will work
 //conv.begin(mono_info, stereo_info);
 //conv.begin(stereo_info, stereo_info);
 conv.begin(stereo_info);
 // setup decoder
 multi.addDecoder(mp3, "audio/mpeg");
 dec.begin();
 Serial.println("Starting MONO Stream (after conv.begin)");
 url.begin("https://s2.yesstreaming.net:17161/stream"); // MONO 44k STREAM
}
void loop() {
 copier.copy();
 static uint32_t lastSerialOutputTime;
 static uint32_t lastURLTime;
 char debugInfo[128];
 if (millis() - lastSerialOutputTime > 1000) {
 if (lastSwitch == 1) {
 Serial.println("(MONO Stream...)");
 } else {
 Serial.println("(STEREO Stream...)");
 }
 snprintf(debugInfo, 96, "MP3DecoderHelix Samplerate: %d, Depth: %d, Channels: %d", mp3.audioInfo().sample_rate, mp3.audioInfo().bits_per_sample, mp3.audioInfo().channels);
 Serial.println(debugInfo);
 snprintf(debugInfo, 96, "MultiDecoder Samplerate: %d, Depth: %d, Channels: %d", multi.audioInfo().sample_rate, multi.audioInfo().bits_per_sample, multi.audioInfo().channels);
 Serial.println(debugInfo);
 snprintf(debugInfo, 96, "EncodedAudioStream Samplerate: %d, Depth: %d, Channels: %d", dec.audioInfo().sample_rate, dec.audioInfo().bits_per_sample, dec.audioInfo().channels);
 Serial.println(debugInfo);
 snprintf(debugInfo, 96, "FormatConverterStream In Samplerate: %d, Depth: %d, Channels: %d", conv.audioInfo().sample_rate, conv.audioInfo().bits_per_sample, conv.audioInfo().channels);
 Serial.println(debugInfo);
 snprintf(debugInfo, 96, "FormatConverterStream Out Samplerate: %d, Depth: %d, Channels: %d", conv.audioInfoOut().sample_rate, conv.audioInfoOut().bits_per_sample, conv.audioInfoOut().channels);
 Serial.println(debugInfo);
 snprintf(debugInfo, 96, "I2SStream Samplerate: %d, Depth: %d, Channels: %d", i2s.audioInfo().sample_rate, i2s.audioInfo().bits_per_sample, i2s.audioInfo().channels);
 Serial.println(debugInfo);
 Serial.println("");
 lastSerialOutputTime = millis();
 }
 if (millis() - lastURLTime > 10000) {
 if (lastSwitch == 0) {
 Serial.println("Starting MONO Stream");
 url.end();
 url.begin("https://s2.yesstreaming.net:17161/stream"); // MONO 44k STREAM
 lastSwitch = 1;
 } else {
 Serial.println("Starting STEREO Stream");
 url.end();
 url.begin("http://s1.voscast.com:8652/stream"); // STEREO 44k STREAM
 lastSwitch = 0;
 }
 lastURLTime = millis();
 }
}

Please also note that the source AudioInfo of the conv.begin(); call does not matter because that will be dynamically refresheshd from the decoder. Only the target matters, so any of this will work:

  • conv.begin(mono_info, stereo_info);
  • conv.begin(stereo_info, stereo_info);
  • conv.begin(stereo_info); // same as conv.begin(stereo_info, stereo_info);
 17:10:39.695 -> (STEREO Stream...)
17:10:39.695 -> MP3DecoderHelix Samplerate: 44100, Depth: 16, Channels: 2
17:10:39.695 -> MultiDecoder Samplerate: 44100, Depth: 16, Channels: 2
17:10:39.695 -> EncodedAudioStream Samplerate: 44100, Depth: 16, Channels: 2
17:10:39.695 -> FormatConverterStream In Samplerate: 44100, Depth: 16, Channels: 2
17:10:39.695 -> FormatConverterStream Out Samplerate: 44100, Depth: 16, Channels: 2
17:10:39.695 -> I2SStream Samplerate: 44100, Depth: 16, Channels: 2
...
17:10:44.542 -> (MONO Stream...)
17:10:44.542 -> MP3DecoderHelix Samplerate: 44100, Depth: 16, Channels: 1
17:10:44.542 -> MultiDecoder Samplerate: 44100, Depth: 16, Channels: 1
17:10:44.574 -> EncodedAudioStream Samplerate: 44100, Depth: 16, Channels: 1
17:10:44.574 -> FormatConverterStream In Samplerate: 44100, Depth: 16, Channels: 1
17:10:44.574 -> FormatConverterStream Out Samplerate: 44100, Depth: 16, Channels: 2
17:10:44.574 -> I2SStream Samplerate: 44100, Depth: 16, Channels: 2
You must be logged in to vote
1 reply
Comment options

I'm getting close to a deadline on a project and this update is like a ray of sunshine in the clouds. Thank you so much... for the libraries, for your willingness to track down bugs, and for your valuable explanations and examples.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /