Browse Source

Allowing mixed .m3u files (webstreams+files)

master
Torsten Stauder 4 years ago
parent
commit
9d0957d815
  1. 4
      README.md
  2. 2
      changelog.md
  3. 2
      html/management_DE.html
  4. 2
      html/management_EN.html
  5. 70
      src/AudioPlayer.cpp
  6. 1
      src/AudioPlayer.h
  7. 2
      src/HTMLmanagement_DE.h
  8. 2
      src/HTMLmanagement_EN.h
  9. 2
      src/Led.cpp
  10. 4
      src/SdCard.cpp
  11. 2
      src/Wlan.cpp
  12. 2
      src/revision.h
  13. 2
      src/values.h

4
README.md

@ -13,7 +13,7 @@ I started this project back in october 2019 and never expected it to become that
* Partition-layout for ESP32 is changed along with this branch. This step was necessary in order to resize (enlarge) the memory-region where especially the assignments for the RFID-tags are saved. As all permanent settings (e.g. WiFi-settings) are saved there too, it's necessary to re-enter WiFi-credentials after update. But the most important thing is to recover the assignments for the RFID-tags. Please consult my [migration-document](https://forum.espuino.de/t/wechsel-zum-refactoring-branch-was-ist-zu-beachten/510).
## Changelog
Last three events:
* 20.07.2021: Adding new playmode: multiple webradio-paylist from local .m3u-file
* 23.07.2021: Adding new playmode: from local .m3u-file (files or webstreams)
* 13.07.2021: Adding OTA-support via webGUI
* 09.07.2021: Making branch `refactoring` the new master
## Known bugs
@ -278,7 +278,7 @@ It's not just simply playing music; different playmodes are supported:
* `folder/playlist (alph. sorted)` => plays all tracks in alph. order from a folder forever
* `folder/playlist (random order)` => plays all tracks in random order from a folder forever
* `webradio` => always only one "track": plays a webstream
* `Webradiolist from local .m3u-File` => can be one or more webradio-stations with local .m3u as sourcefile
* `list (files from SD and/or webstreams) from local .m3u-File` => can be one or more files / webradio-stations with local .m3u as sourcefile
### Modification RFID-tags
There are special RFID-tags, that don't start music by themself but can modify things. If applied a second time, it's previous action/modification will be reversed. Please note: all sleep-modes do dimming (Neopixel) automatically because it's supposed to be used in the evening when going to bed. Well, at least that's my children's indication :-) So first make sure to start the music then use a modification-card in order to apply your desired modification:

2
changelog.md

@ -9,7 +9,7 @@
* 09.07.2021: Making branch `refactoring` the the master
* 09.07.2021: Making master the new branch `old` (not maintained any longer!)
* 13.07.2021: Adding OTA-support via webGUI
* 20.07.2021: Adding new playmode: multiple webradio-paylist from local .m3u-file
* 23.07.2021: Adding new playmode: from local .m3u-file (files or webstreams)
## Old (monolithic main.cpp)
* 11.07.2020: Added support for reversed Neopixel addressing.

2
html/management_DE.html

@ -272,7 +272,7 @@
<option class="option-folder" value="7">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option>
<option class="option-folder" value="9">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>
<option class="option-stream" value="8">Webradio</option>
<option class="option-stream" value="11">Webradioliste aus lokaler .m3u-Datei</option>
<option class="option-stream" value="11">Liste (Dateien von SD und/oder Webstreams) aus lokaler .m3u-Datei</option>
</select>
</div>
<div class="tab-pane " id="rfidmod" role="tabpanel">

2
html/management_EN.html

@ -272,7 +272,7 @@
<option class="option-folder" value="7">All tracks of a directory (sorted alph., loop)</option>
<option class="option-folder" value="9">All tracks of a directory (random, loop)</option>
<option class="option-stream" value="8">Webradio</option>
<option class="option-stream" value="11">Webradiolist from local .m3u-File</option>
<option class="option-stream" value="11">List (files from SD and/or webstreams) from local .m3u-File</option>
</select>
</div>
<div class="tab-pane " id="rfidmod" role="tabpanel">

70
src/AudioPlayer.cpp

@ -553,10 +553,18 @@ void AudioPlayer_Task(void *parameter) {
}
}
if (gPlayProperties.playMode == WEBSTREAM || gPlayProperties.playMode == WEBSTREAMS_LOCAL_M3U) { // Webstream
audio->connecttohost(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
gPlayProperties.playlistFinished = false;
if (!strncmp("http", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), 4)) {
gPlayProperties.isWebstream = true;
} else {
gPlayProperties.isWebstream = false;
}
gPlayProperties.currentRelPos = 0;
audioReturnCode = false;
if (gPlayProperties.playMode == WEBSTREAM || (gPlayProperties.playMode == LOCAL_M3U && gPlayProperties.isWebstream)) { // Webstream
audioReturnCode = audio->connecttohost(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
gPlayProperties.playlistFinished = false;
} else if (gPlayProperties.playMode != WEBSTREAM && !gPlayProperties.isWebstream) {
// Files from SD
if (!gFSystem.exists(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber))) { // Check first if file/folder exists
snprintf(Log_Buffer, Log_BufferLength, "%s: %s", (char *) FPSTR(dirOrFileDoesNotExist), *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
@ -566,31 +574,37 @@ void AudioPlayer_Task(void *parameter) {
} else {
audioReturnCode = audio->connecttoFS(gFSystem, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
// consider track as finished, when audio lib call was not successful
if (!audioReturnCode) {
System_IndicateError();
gPlayProperties.trackFinished = true;
continue;
}
}
}
if (!audioReturnCode) {
System_IndicateError();
gPlayProperties.trackFinished = true;
continue;
} else {
if (gPlayProperties.currentTrackNumber) {
Led_Indicate(LedIndicatorType::PlaylistProgress);
if (gPlayProperties.startAtFilePos > 0) {
audio->setFilePos(gPlayProperties.startAtFilePos);
gPlayProperties.startAtFilePos = 0;
snprintf(Log_Buffer, Log_BufferLength, "%s %u", (char *) FPSTR(trackStartatPos), audio->getFilePos());
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
}
}
if (gPlayProperties.startAtFilePos > 0) {
audio->setFilePos(gPlayProperties.startAtFilePos);
gPlayProperties.startAtFilePos = 0;
snprintf(Log_Buffer, Log_BufferLength, "%s %u", (char *) FPSTR(trackStartatPos), audio->getFilePos());
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
}
if (!gPlayProperties.isWebstream) { // Is done via audio_showstation()
char buf[255];
snprintf(buf, sizeof(buf) / sizeof(buf[0]), "(%d/%d) %s", (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks, (const char *)*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
#ifdef MQTT_ENABLE
publishMqtt((char *) FPSTR(topicTrackState), buf, false);
#endif
#if (LANGUAGE == DE)
snprintf(Log_Buffer, Log_BufferLength, "'%s' wird abgespielt (%d von %d)", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks);
#else
snprintf(Log_Buffer, Log_BufferLength, "'%s' is being played (%d of %d)", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks);
#endif
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
gPlayProperties.playlistFinished = false;
}
#if (LANGUAGE == DE)
snprintf(Log_Buffer, Log_BufferLength, "'%s' wird abgespielt (%d von %d)", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks);
#else
snprintf(Log_Buffer, Log_BufferLength, "'%s' is being played (%d of %d)", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks);
#endif
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
gPlayProperties.playlistFinished = false;
}
}
@ -599,20 +613,22 @@ void AudioPlayer_Task(void *parameter) {
if (gPlayProperties.seekmode == SEEK_FORWARDS) {
if (audio->setTimeOffset(jumpOffset)) {
#if (LANGUAGE == DE)
Serial.printf("%d Sekunden nach vorne gesprungen\n", jumpOffset);
snprintf(Log_Buffer, Log_BufferLength, "%d Sekunden nach vorne gesprungen", jumpOffset);
#else
Serial.printf("Jumped %d seconds forwards\n", jumpOffset);
snprintf(Log_Buffer, Log_BufferLength, "Jumped %d seconds forwards", jumpOffset);
#endif
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
} else {
System_IndicateError();
}
} else if (gPlayProperties.seekmode == SEEK_BACKWARDS) {
if (audio->setTimeOffset(-(jumpOffset))) {
#if (LANGUAGE == DE)
Serial.printf("%d Sekunden zurueck gesprungen\n", jumpOffset);
snprintf(Log_Buffer, Log_BufferLength, "%d Sekunden zurueck gesprungen", jumpOffset);
#else
Serial.printf("Jumped %d seconds backwards\n", jumpOffset);
snprintf(Log_Buffer, Log_BufferLength, "Jumped %d seconds backwards", jumpOffset);
#endif
Log_Println(Log_Buffer, LOGLEVEL_NOTICE);
} else {
System_IndicateError();
}
@ -634,7 +650,7 @@ void AudioPlayer_Task(void *parameter) {
}
// Calculate relative position in file (for neopixel) for SD-card-mode
if (!gPlayProperties.playlistFinished && gPlayProperties.playMode != WEBSTREAM) {
if (!gPlayProperties.playlistFinished && !gPlayProperties.isWebstream) {
double fp = (double)audio->getFilePos() / (double)audio->getFileSize();
if (millis() % 100 == 0) {
gPlayProperties.currentRelPos = fp * 100;
@ -866,7 +882,7 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
break;
}
case WEBSTREAMS_LOCAL_M3U: { // This is always just one "track"
case LOCAL_M3U: { // Can be one or more webradio-station(s)
Log_Println((char *) FPSTR(modeWebstreamM3u), LOGLEVEL_NOTICE);
if (Wlan_IsConnected()) {
xQueueSend(gTrackQueue, &(musicFiles), 0);

1
src/AudioPlayer.h

@ -20,6 +20,7 @@ typedef struct { // Bit field
uint8_t seekmode: 2; // If seekmode is active and if yes: forward or backwards?
bool newPlayMono: 1; // true if mono; false if stereo (helper)
bool currentPlayMono: 1; // true if mono; false if stereo
bool isWebstream: 1; // Indicates if track currenty played is a webstream
} playProps;
extern playProps gPlayProperties;

2
src/HTMLmanagement_DE.h

@ -272,7 +272,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<option class=\"option-folder\" value=\"7\">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option>\
<option class=\"option-folder\" value=\"9\">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>\
<option class=\"option-stream\" value=\"8\">Webradio</option>\
<option class=\"option-stream\" value=\"11\">Webradioliste aus lokaler .m3u-Datei</option>\
<option class=\"option-stream\" value=\"11\">Liste (Dateien von SD und/oder Webstreams) aus lokaler .m3u-Datei</option>\
</select>\
</div>\
<div class=\"tab-pane \" id=\"rfidmod\" role=\"tabpanel\">\

2
src/HTMLmanagement_EN.h

@ -272,7 +272,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<option class=\"option-folder\" value=\"7\">All tracks of a directory (sorted alph., loop)</option>\
<option class=\"option-folder\" value=\"9\">All tracks of a directory (random, loop)</option>\
<option class=\"option-stream\" value=\"8\">Webradio</option>\
<option class=\"option-stream\" value=\"11\">Webradiolist from local .m3u-File</option>\
<option class=\"option-stream\" value=\"11\">List (files from SD and/or webstreams) from local .m3u-File</option>\
</select>\
</div>\
<div class=\"tab-pane \" id=\"rfidmod\" role=\"tabpanel\">\

2
src/Led.cpp

@ -467,7 +467,7 @@ static void Led_Task(void *parameter) {
redrawProgress = true;
}
if (gPlayProperties.playMode != WEBSTREAM && gPlayProperties.playMode != WEBSTREAMS_LOCAL_M3U) {
if (!gPlayProperties.isWebstream) {
if (gPlayProperties.currentRelPos != lastPos || redrawProgress) {
redrawProgress = false;
lastPos = gPlayProperties.currentRelPos;

4
src/SdCard.cpp

@ -154,7 +154,7 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) {
}
// Parse m3u-playlist and create linear-playlist out of it
if (_playMode == WEBSTREAMS_LOCAL_M3U) {
if (_playMode == LOCAL_M3U) {
if (fileOrDirectory && !fileOrDirectory.isDirectory() && fileOrDirectory.size() >= 0) {
enablePlaylistFromM3u = true;
uint16_t allocCount = 1;
@ -170,7 +170,7 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) {
return files;
}
char buf;
char lastBuf = '0';
char lastBuf = '#';
uint32_t fPos = 1;
serializedPlaylist[0] = '#';

2
src/Wlan.cpp

@ -164,7 +164,7 @@ void writeWifiStatusToNVS(bool wifiStatus) {
if (!wifiStatus) {
if (gPrefsSettings.putUInt("enableWifi", 0)) { // disable
Log_Println((char *) FPSTR(wifiDisabledAfterRestart), LOGLEVEL_NOTICE);
if (gPlayProperties.playMode == WEBSTREAM || gPlayProperties.playMode == WEBSTREAMS_LOCAL_M3U) {
if (gPlayProperties.isWebstream) {
AudioPlayer_TrackControlToQueueSender(STOP);
}
delay(300);

2
src/revision.h

@ -1,4 +1,4 @@
#ifndef __REVISION_H__
#define __REVISION_H__
constexpr const char softwareRevision[] PROGMEM = "Software-revision: 20210720-2";
constexpr const char softwareRevision[] PROGMEM = "Software-revision: 20210723-1";
#endif

2
src/values.h

@ -25,7 +25,7 @@
#define ALL_TRACKS_OF_DIR_SORTED_LOOP 7 // Play all files of a directory (alph. sorted) in infinite-loop
#define ALL_TRACKS_OF_DIR_RANDOM_LOOP 9 // Play all files of a directory (randomized) in infinite-loop
#define WEBSTREAM 8 // Play webradio-stream
#define WEBSTREAMS_LOCAL_M3U 11 // Plays webreadio-streams with addresses from a local m3u-file
#define LOCAL_M3U 11 // Plays items (webstream or files) with addresses/paths from a local m3u-file
#define BUSY 10 // Used if playlist is created

Loading…
Cancel
Save