Skip to content

Commit 9cb80b7

Browse files
committed
KARadioProtocol DRAFT
1 parent a6820d8 commit 9cb80b7

File tree

6 files changed

+366
-293
lines changed

6 files changed

+366
-293
lines changed

examples/sandbox/ka-radio-protocol-server/KA-Radio-Protocol.h

Lines changed: 0 additions & 111 deletions
This file was deleted.

examples/sandbox/ka-radio-protocol-server/ka-radio-protocol-server.ino

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#pragma once
2+
3+
#include <optional>
4+
5+
#include "AudioTools/CoreAudio/AudioBasic/Str.h"
6+
#include "AudioTools/CoreAudio/AudioPlayer.h"
7+
#include "AudioTools/Disk/AudioSource.h"
8+
9+
#define KA_VERSION "Release: 2.4, Revision: R0"
10+
11+
namespace audio_tools {
12+
13+
/***
14+
* @brief KA-Radio Protocol: We can use the KA-Radio protocol to control the
15+
* audio player provided by the audiotools. Example: volume=50&play=128&infos
16+
* See https://github.com/karawin/Ka-Radio32/blob/master/Interface.md
17+
* @author Phil Schatzmann
18+
*/
19+
20+
class KARadioProtocol {
21+
public:
22+
/// Default constructor
23+
KARadioProtocol(AudioPlayer& player) { setPlayer(player); }
24+
25+
/// Empty constructor: call setPlayer to define the player
26+
KARadioProtocol() = default;
27+
28+
/// Defines the player
29+
void setPlayer(AudioPlayer& player) {
30+
p_player = &player;
31+
volume = player.volume() * 254.0f;
32+
}
33+
34+
/// processes the commands and returns the result output via the Print object
35+
bool processCommand(const char* input, Print& result) {
36+
if (p_player == nullptr) {
37+
LOGE("player not set");
38+
return false;
39+
}
40+
41+
Str name;
42+
Str arg;
43+
StrView line = input;
44+
45+
int start = line.indexOf('?');
46+
if (start < 0) start = 0;
47+
int endPos = line.length();
48+
bool rc = true;
49+
while (start >= 0 && start < endPos) {
50+
int eqPos = line.indexOf('=', start);
51+
int toPos = getEndPos(line, start + 1);
52+
if (eqPos >= 0) {
53+
name.substring(line, start + 1, eqPos);
54+
arg.substring(line, eqPos + 1, toPos);
55+
} else {
56+
name.substring(line, start + 1, toPos);
57+
arg = "";
58+
}
59+
LOGD("start=%d, eqPos=%d, toPos=%d", start, eqPos, toPos);
60+
// remove leading and trailing spaces
61+
name.trim();
62+
arg.trim();
63+
// execute the command
64+
rc = processCommand(name, arg, result);
65+
// calculate new positions
66+
start = toPos;
67+
toPos = getEndPos(line, start + 1);
68+
}
69+
return rc;
70+
}
71+
72+
/// Processes a single command
73+
bool processCommand(Str& name, Str& arg, Print& result) {
74+
LOGI("command: %s (%s)", name.c_str(), arg.c_str());
75+
if (p_player == nullptr) {
76+
LOGE("No player set");
77+
return false;
78+
}
79+
if (name == "play") {
80+
if (!arg.isEmpty()) {
81+
int idx = arg.toInt();
82+
p_player->setIndex(idx);
83+
}
84+
} else if (name == "instant") {
85+
p_player->setPath(arg.c_str());
86+
} else if (name == "volume") {
87+
if (!arg.isEmpty()) {
88+
volume = arg.toInt();
89+
p_player->setVolume(static_cast<float>(volume) / 254.0f);
90+
}
91+
} else if (name == "volume+") {
92+
volume += 5;
93+
if (volume > 245) {
94+
volume = 254;
95+
}
96+
p_player->setVolume(static_cast<float>(volume) / 254.0f);
97+
} else if (name == "volume-") {
98+
volume -= 5;
99+
if (volume < 0) {
100+
volume = 0;
101+
}
102+
p_player->setVolume(static_cast<float>(volume) / 254.0f);
103+
} else if (name == "pause") {
104+
p_player->setActive(false);
105+
} else if (name == "resume") {
106+
p_player->setActive(true);
107+
} else if (name == "stop") {
108+
p_player->setActive(false);
109+
} else if (name == "start") {
110+
p_player->setActive(true);
111+
} else if (name == "next") {
112+
p_player->next();
113+
} else if (name == "prev") {
114+
p_player->previous();
115+
} else if (name == "version") {
116+
result.print("version: ");
117+
result.println(KA_VERSION);
118+
} else if (name == "mute") {
119+
if (!arg.isEmpty()) {
120+
p_player->setActive(!(arg.toInt() == 1));
121+
}
122+
} else if (name == "infos") {
123+
result.print("vol: ");
124+
result.println(volume);
125+
result.print("num: ");
126+
result.println(index());
127+
result.print("stn: "); // station
128+
result.println(stationName());
129+
result.print("tit: "); // title
130+
result.println(title());
131+
result.print("sts: "); // status
132+
result.println(p_player->isActive());
133+
} else if (name == "list") {
134+
// arg: 0 to 254
135+
if (!arg.isEmpty()) {
136+
p_player->setIndex(arg.toInt());
137+
}
138+
result.println(stationName());
139+
} else {
140+
LOGE("Invalid command:", name.c_str());
141+
return false;
142+
}
143+
result.flush();
144+
return true;
145+
}
146+
147+
/// Provides the actual index
148+
int index() { return p_player->audioSource().index(); }
149+
150+
/// Provides the actual title
151+
const char* title() { return title_str.c_str(); }
152+
153+
protected:
154+
AudioPlayer* p_player = nullptr;
155+
int volume = 0;
156+
Str title_str = "n/a";
157+
158+
int getEndPos(StrView& line, int start) {
159+
int endPos = line.indexOf('&', start);
160+
if (endPos < 0) {
161+
endPos = line.length();
162+
}
163+
return endPos;
164+
}
165+
166+
const char* stationName() {
167+
if (p_player != nullptr) {
168+
return p_player->audioSource().toStr();
169+
}
170+
return "";
171+
}
172+
};
173+
} // namespace audio_tools

0 commit comments

Comments
 (0)