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