forked from Edzelf/Esp-radio
-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web radio chunked demo #48
Open
wmarkow
wants to merge
13
commits into
baldram:master
Choose a base branch
from
wmarkow:web-radio-chunked-demo
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
3d4a8ab
Introduce isChipConnected() method.
wmarkow 2800c57
Merge branch 'fix_for_#24'
wmarkow ec00fe9
Set the volume always.
wmarkow 28cb882
Merge branch 'fix_for_#26'
wmarkow 4f40760
Merge remote-tracking branch 'remotes/baldram/master'
wmarkow 5dd69ae
Original test code from issue #47
wmarkow 3a345ca
Modify to my NodeMcu v0.9 board. Set the correct URL. Glitches are re…
wmarkow 035ddef
Fix the glitches.
wmarkow 26032d8
Add some comments to the solution.
wmarkow 531971e
Restore the code so it is the same as WebRadioDemo.ino
wmarkow c4069bd
Handle chunked audio streams.
wmarkow d3170cc
Fix compilation problem.
wmarkow 7686629
Remove also 5 bytes length chunk control data.
wmarkow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
/** | ||
* A chunked stream handler to play web radio stations using ESP8266. | ||
* It shows how to remove chunk control data from the stream to avoid the sound glitches. | ||
* | ||
* More technical details about chunked transfer: | ||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding | ||
* https://en.wikipedia.org/wiki/Chunked_transfer_encoding | ||
* | ||
* Github discussion related to this demo: | ||
* https://github.com/baldram/ESP_VS1053_Library/issues/47 | ||
*/ | ||
|
||
#include <VS1053.h> | ||
#ifdef ARDUINO_ARCH_ESP8266 | ||
#include <ESP8266WiFi.h> | ||
#define VS1053_CS D1 | ||
#define VS1053_DCS D0 | ||
#define VS1053_DREQ D3 | ||
#endif | ||
|
||
#ifdef ARDUINO_ARCH_ESP32 | ||
#include <WiFi.h> | ||
#define VS1053_CS 5 | ||
#define VS1053_DCS 16 | ||
#define VS1053_DREQ 4 | ||
#endif | ||
|
||
// Default volume | ||
#define VOLUME 80 | ||
|
||
VS1053 player(VS1053_CS, VS1053_DCS, VS1053_DREQ); | ||
WiFiClient client; | ||
|
||
const char *ssid = "TP-Link"; | ||
const char *password = "xxxxxxxx"; | ||
|
||
// this is the audio stream which uses chunked transfer | ||
const char *host = "icecast.radiofrance.fr"; | ||
const char *path = "/franceculture-lofi.mp3"; | ||
int httpPort = 80; | ||
|
||
// The buffer size 64 seems to be optimal. At 32 and 128 the sound might be brassy. | ||
#define BUFFER_SIZE 64 | ||
uint8_t mp3buff[BUFFER_SIZE]; | ||
|
||
uint8_t remove_chunk_control_data(uint8_t *data, size_t length); | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
|
||
// Wait for VS1053 and PAM8403 to power up | ||
// otherwise the system might not start up correctly | ||
delay(3000); | ||
|
||
// This can be set in the IDE no need for ext library | ||
// system_update_cpu_freq(160); | ||
|
||
Serial.println("\n\nChunked Transfer Radio Node WiFi Radio"); | ||
|
||
SPI.begin(); | ||
|
||
player.begin(); | ||
player.switchToMp3Mode(); | ||
player.setVolume(VOLUME); | ||
|
||
Serial.print("Connecting to SSID "); | ||
Serial.println(ssid); | ||
WiFi.begin(ssid, password); | ||
WiFi.setAutoConnect(true); | ||
WiFi.setAutoReconnect(true); | ||
WiFi.reconnect(); | ||
|
||
while (WiFi.status() != WL_CONNECTED) { | ||
delay(500); | ||
Serial.print("."); | ||
} | ||
|
||
Serial.println("WiFi connected"); | ||
Serial.println("IP address: "); | ||
Serial.println(WiFi.localIP()); | ||
|
||
Serial.print("connecting to "); | ||
Serial.println(host); | ||
|
||
if (!client.connect(host, httpPort)) { | ||
Serial.println("Connection failed"); | ||
return; | ||
} | ||
|
||
Serial.print("Requesting stream: "); | ||
Serial.println(path); | ||
|
||
client.print(String("GET ") + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); | ||
} | ||
|
||
void loop() { | ||
if (!client.connected()) { | ||
Serial.println("Reconnecting..."); | ||
if (client.connect(host, httpPort)) { | ||
client.print(String("GET ") + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); | ||
} | ||
} | ||
|
||
if (client.available() > 0) { | ||
uint8_t bytesread = client.read(mp3buff, BUFFER_SIZE); | ||
bytesread = remove_chunk_control_data(mp3buff, bytesread); | ||
player.playChunk(mp3buff, bytesread); | ||
} | ||
} | ||
|
||
// Introduce here a new helper buffer with size of 8 bytes, to remove the chunked control bytes. | ||
// Variables must be aligned to avoid the Exception (9) being thrown from the ESP8266 | ||
// See here: https://arduino-esp8266.readthedocs.io/en/latest/exception_causes.html | ||
// See here: https://arduino.stackexchange.com/questions/67442/nodemcu-1-0-exception-9-fatal-exception-9loadstorealignmentcause | ||
uint8_t __attribute__((aligned(4))) helperBuffer[8]; | ||
uint8_t __attribute__((aligned(4))) helperBufferCount = 0; | ||
|
||
/*** | ||
* Removes the chunk control data from the helper buffer. | ||
* | ||
* Only the following chunk control bytes are removed: | ||
* \r\n<byte>\r\n | ||
* \r\n<byte><byte>\r\n | ||
* \r\n<byte><byte><byte>\r\n | ||
* \r\n<byte><byte><byte><byte>\r\n | ||
* | ||
*/ | ||
void remove_chunk_control_data_from_helper_buffer() { | ||
if (helperBuffer[0] != '\r') { | ||
// die fast | ||
return; | ||
} | ||
if (helperBuffer[1] != '\n') { | ||
// die fast | ||
return; | ||
} | ||
|
||
if (helperBuffer[3] == '\r' && helperBuffer[4] == '\n') { | ||
// 5 bytes length chunk control section discovered | ||
// \r\n<byte>\r\n | ||
helperBufferCount = 3; | ||
Serial.println("Removed control data: 5 bytes"); | ||
|
||
return; | ||
} | ||
|
||
if (helperBuffer[4] == '\r' && helperBuffer[5] == '\n') { | ||
// 6 bytes length chunk control section discovered | ||
// \r\n<byte><byte>\r\n | ||
helperBufferCount = 2; | ||
Serial.println("Removed control data: 6 bytes"); | ||
|
||
return; | ||
} | ||
|
||
if (helperBuffer[5] == '\r' && helperBuffer[6] == '\n') { | ||
// 7 bytes length chunk control section discovered | ||
// \r\n<byte><byte><byte>\r\n | ||
helperBufferCount = 1; | ||
Serial.println("Removed control data: 7 bytes"); | ||
|
||
return; | ||
} | ||
|
||
if (helperBuffer[6] == '\r' && helperBuffer[7] == '\n') { | ||
// 8 bytes length chunk control section discovered | ||
// \r\n<byte><byte><byte><byte>\r\n | ||
helperBufferCount = 0; | ||
Serial.println("Removed control data: 8 bytes"); | ||
|
||
return; | ||
} | ||
} | ||
|
||
/*** | ||
* Puts a byte to the input of helper buffer and returns a byte from the output of helper buffer. | ||
* In the meantime it tries to remove the chunk control data (if any available) from the buffer. | ||
* | ||
* @param incoming byte of the audio stream | ||
* @return outgoing byte of the audio stream (if available) or -1 when no bytes available (this happens | ||
* when the buffer is being populated with the data or after removal of chunk control data) | ||
*/ | ||
int16_t put_through_helper_buffer(uint8_t newValue) { | ||
// | ||
int16_t result = -1; | ||
|
||
if (helperBufferCount == 8) { | ||
result = helperBuffer[0]; | ||
} | ||
|
||
helperBuffer[0] = helperBuffer[1]; | ||
helperBuffer[1] = helperBuffer[2]; | ||
helperBuffer[2] = helperBuffer[3]; | ||
helperBuffer[3] = helperBuffer[4]; | ||
helperBuffer[4] = helperBuffer[5]; | ||
helperBuffer[5] = helperBuffer[6]; | ||
helperBuffer[6] = helperBuffer[7]; | ||
helperBuffer[7] = newValue; | ||
|
||
helperBufferCount++; | ||
if (helperBufferCount > 8) { | ||
helperBufferCount = 8; | ||
} | ||
|
||
remove_chunk_control_data_from_helper_buffer(); | ||
|
||
return result; | ||
} | ||
|
||
/*** | ||
* Removes the chunk control data from the input audio stream. Data are written back to the input | ||
* buffer and the number of bytes available (after processing) is returned. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding | ||
* @see https://en.wikipedia.org/wiki/Chunked_transfer_encoding | ||
* | ||
* @param data a pointer to the input buffer of audio stream | ||
* @param length a number of input bytes to be processed | ||
* @return the number of available bytes in the input buffer after removing the chunk control data | ||
*/ | ||
uint8_t remove_chunk_control_data(uint8_t *data, size_t length) { | ||
|
||
uint8_t writeindex = 0; | ||
uint8_t index = 0; | ||
for (index = 0; index < length; index++) { | ||
uint8_t input = data[index]; | ||
int16_t output = put_through_helper_buffer(input); | ||
if (output >= 0) { | ||
data[writeindex] = (uint8_t) output; | ||
writeindex++; | ||
} | ||
} | ||
|
||
return writeindex; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you able to exclude this file from the patchset?
It looks like it's some accidental change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is possible. I did this PR from my presonal branch and this change is there accidentaly.
I will cancel this PR and provide a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need, you can just replace this line from git history or please keep it as it is, and I will exclude it while merging.