Hallo zusammen,
Ich dachte ich mache ein neues Thema für den 2. PR zu der Playlist Optimierung auf. Ziel ist es Smart Pointer einsetzten zu können, was mit FreeRTOS Queues nicht möglich ist, da diese „raw copy“ verwenden (siehe hier und hier). Dadurch möchte ich diese ersetzten, da wir sie mit einer Tiefe von 1 als „Message Box“ einsetzten.
Hierfür habe ich mir ein MessageBox System ausgelesen (angelehnt an PolyM) überlegt. Hier wird ein Smart Pointer von einer Basisklasse verwendet um von dieser abgeleiteten Nachrichten (mit oder ohne Payload) zu verteilen.
Statt einer Queue wird es ein Briefkasten geben mit drei Objekten:
- Der Nachricht als ein
std::unique_ptr<Msg>
- Einem
std::mutex
zum Synchronisieren des Zugriffes - Einem Binary Semaphore zur Signalisierung einer neuen Nachricht
Klassenstruktur
Damit das System auch für andere Arten von Nachrichten (zB Event von dem RFID-Treibern oder Nachrichten an das LED System) verwendet werden kann, gibt es 3 statt 2 Schichten der Abstraktion (AudioMsg
ist notwendig um die richtige Spezialisierung der Template Klasse AudioDataMsg
auszuwählen zu können).
Verteilung der Nachrichten
Die Verteilung der Nachricht würde hier durch eine zentrale Funktion erfolgen. Dieser leitet die Nachricht abhängig von MsgType
an die Module weiter, die es in den lokalen Briefkasten ablegen und dem Thread signalisieren, dass eine neue Nachricht da ist.
Codeblock für das Verteilen einer Nachricht:
Message.cpp
void Message_Send(Msg &&msg) {
// message distribution hub
switch (msg.type()) {
case Msg::AudioPlayerMsg:
AudioPlayer_SignalMessage(std::move(msg));
break;
// not implemented
case Msg::LedMsg:
Led_SignalMessage(std::move(msg));
break;
default:
Log_Printf(LOGLEVEL_ERROR, "Message with the type %d is not implemented", std::to_underlying(msg.type()));
break;
}
}
AudioPlayer.cpp
// our inbox for command & control messages to the AudioPlayer Task
static std::unique_ptr<Msg> newMsg;
static std::mutex msgGuard;
static SemaphoreHandle_t msgReceived = xSemaphoreCreateBinary();
[...]
void AudioPlayer_SignalMessage(Msg &&msg) {
{ // Don't remove because of the lifetime of the mutex
std::lock_guard<std::mutex> lock(msgGuard);
newMsg = msg.move();
log_n("Pushing new msg: cmd: %d, data: %d", ((AudioMsg &) *newMsg).event(), ((AudioMsg &) *newMsg).data());
}
xSemaphoreGive(msgReceived);
}
Codeblock für die Auswertung:
AudioPlayer.cpp
// check for new messages
auto timeout = (gPlayProperties.playMode == NO_PLAYLIST || gPlayProperties.pausePlay) ? portMAX_DELAY : pdMS_TO_TICKS(1); // if we are idle, we sleep forever
auto retValue = xSemaphoreTake(msgReceived, timeout);
if (retValue) {
// we message received
std::unique_ptr<Msg> msg;
{ // Don't remove because of the lifetime of the mutex
std::lock_guard<std::mutex> lock(msgGuard);
msg = std::move(newMsg);
}
auto &audioMsg = (AudioMsg &) (*msg);
switch (audioMsg.event()) {
case AudioMsg::TrackCommand: {
// save the trackCommand and execute it later
uint8_t command = audioMsg.data;
} break;
case AudioMsg::VolumeCommand: {
// change the volume of the audio
uint8_t volume = audioMsg.data;
} break;
case AudioMsg::PlaylistCommand: {
// got a new playlist, cast Msg --> AudioDataMsg
AudioDataMsg<std::unique_ptr<Playlist>> &playlistMsg = (AudioDataMsg<std::unique_ptr<Playlist>> &) *msg;
playlist = std::move(playlistMsg.playload());
} break;
case AudioMsg::TTSCommand: {
AudioDataMsg<pstring> &ttsMsg = (AudioDataMsg<pstring> &) *msg;
speakIt = playlistMsg.playload();
} break;
default:
Log_Printf(LOGLEVEL_ERROR, "Unknown audio event %d", std::to_underlying(audioMsg.event()));
break;
}
}
Konklusion
Das Message System ist aktuell ein Proof of Concept, sie funktioniert für den AudioPlayer um trackCommands, Lautstärkeänderungen und Playlists zu übertragen. Was ich noch implementieren möchte ist TTS (Text To Speech) und die Kapselung der Variablen der Playlist (zB currentTrack, playMode, repeat Track/Playlist, …).
Der Code ist hier zu finden: GitHub - laszloh/ESPuino at feature/playlist-queue-removal
Wenn Interesse an dem System besteht, könnten andere Teile des Systems auch auf dieses Nachrichtensystem umgestellt werden (die Led.cpp wäre prädestiniert dafür, da sie stark Event getriggert ist).