c@75
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@75
|
2
|
c@75
|
3 /*
|
c@75
|
4 Piper C++
|
c@75
|
5
|
c@75
|
6 Centre for Digital Music, Queen Mary, University of London.
|
cannam@220
|
7 Copyright 2015-2017 QMUL.
|
c@75
|
8
|
c@75
|
9 Permission is hereby granted, free of charge, to any person
|
c@75
|
10 obtaining a copy of this software and associated documentation
|
c@75
|
11 files (the "Software"), to deal in the Software without
|
c@75
|
12 restriction, including without limitation the rights to use, copy,
|
c@75
|
13 modify, merge, publish, distribute, sublicense, and/or sell copies
|
c@75
|
14 of the Software, and to permit persons to whom the Software is
|
c@75
|
15 furnished to do so, subject to the following conditions:
|
c@75
|
16
|
c@75
|
17 The above copyright notice and this permission notice shall be
|
c@75
|
18 included in all copies or substantial portions of the Software.
|
c@75
|
19
|
c@75
|
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
c@75
|
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
c@75
|
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
c@75
|
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
c@75
|
24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
c@75
|
25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
c@75
|
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
c@75
|
27
|
c@75
|
28 Except as contained in this notice, the names of the Centre for
|
c@75
|
29 Digital Music; Queen Mary, University of London; and Chris Cannam
|
c@75
|
30 shall not be used in advertising or otherwise to promote the sale,
|
c@75
|
31 use or other dealings in this Software without prior written
|
c@75
|
32 authorization.
|
c@75
|
33 */
|
c@75
|
34
|
c@75
|
35 #ifndef PIPER_VAMP_JSON_H
|
c@75
|
36 #define PIPER_VAMP_JSON_H
|
c@75
|
37
|
c@75
|
38 #include <vector>
|
c@75
|
39 #include <string>
|
c@75
|
40 #include <sstream>
|
c@122
|
41 #include <iterator>
|
c@139
|
42 #include <cmath>
|
c@75
|
43
|
c@75
|
44 #include <json11/json11.hpp>
|
c@75
|
45 #include <base-n/include/basen.hpp>
|
c@75
|
46
|
c@75
|
47 #include <vamp-hostsdk/Plugin.h>
|
c@75
|
48 #include <vamp-hostsdk/PluginLoader.h>
|
c@97
|
49
|
cannam@220
|
50 #include "vamp-support/StaticOutputDescriptor.h"
|
c@97
|
51 #include "vamp-support/PluginStaticData.h"
|
c@97
|
52 #include "vamp-support/PluginConfiguration.h"
|
c@97
|
53 #include "vamp-support/RequestResponse.h"
|
c@75
|
54
|
c@75
|
55 #include "vamp-support/PluginHandleMapper.h"
|
c@75
|
56 #include "vamp-support/PluginOutputIdMapper.h"
|
c@75
|
57 #include "vamp-support/RequestResponseType.h"
|
c@75
|
58
|
c@97
|
59 namespace piper_vamp {
|
c@75
|
60
|
c@75
|
61 /**
|
c@75
|
62 * Convert the structures laid out in the Vamp SDK classes into JSON
|
c@75
|
63 * (and back again) following the schema in the vamp-json-schema
|
c@75
|
64 * project repo.
|
c@75
|
65 *
|
c@75
|
66 * Functions with names starting "from" convert from a Vamp SDK object
|
c@75
|
67 * to JSON output. Most of them return a json11::Json object, with a
|
c@75
|
68 * few exceptions for low-level utilities that return a string. These
|
c@75
|
69 * functions succeed all of the time.
|
c@75
|
70 *
|
c@75
|
71 * Functions with names starting "to" convert to a Vamp SDK object
|
c@75
|
72 * from JSON input. These functions all accept a json11::Json object
|
c@75
|
73 * as first argument, with a few exceptions for low-level utilities
|
c@75
|
74 * that accept a string. These functions all accept a string reference
|
c@75
|
75 * as a final argument and return an error string through it if the
|
c@75
|
76 * conversion fails. If conversion fails the return value is
|
c@75
|
77 * undefined, and any returned object may be incomplete or
|
c@75
|
78 * invalid. Callers should check for an empty error string (indicating
|
c@75
|
79 * success) before using the returned value.
|
c@75
|
80 */
|
c@75
|
81
|
c@75
|
82 class VampJson
|
c@75
|
83 {
|
c@75
|
84 public:
|
c@75
|
85 /** Serialisation format for arrays of floats (process input and
|
c@75
|
86 * feature values). Wherever such an array appears, it may
|
c@75
|
87 * alternatively be replaced by a single string containing a
|
c@75
|
88 * base-64 encoding of the IEEE float buffer. When parsing, if a
|
c@75
|
89 * string is found instead of an array in this case, it will be
|
c@75
|
90 * interpreted as a base-64 encoded buffer. Only array or base-64
|
c@75
|
91 * encoding may be provided, not both.
|
c@75
|
92 */
|
c@75
|
93 enum class BufferSerialisation {
|
c@75
|
94
|
c@75
|
95 /** Default JSON serialisation of values in array form. This
|
c@75
|
96 * is relatively slow to parse and serialise, and can take a
|
c@75
|
97 * lot of space.
|
c@75
|
98 */
|
c@75
|
99 Array,
|
c@75
|
100
|
c@75
|
101 /** Base64-encoded string of the raw data as packed
|
c@75
|
102 * little-endian IEEE 32-bit floats. Faster and more compact
|
c@75
|
103 * than the text encoding but more complicated to
|
c@75
|
104 * provide. Note that Base64 serialisations produced by this
|
c@75
|
105 * library do not including padding characters and so are not
|
c@75
|
106 * necessarily multiples of 4 characters long. You will need
|
c@75
|
107 * to pad them yourself if concatenating them or supplying to
|
c@75
|
108 * a consumer that expects padding.
|
c@75
|
109 */
|
c@75
|
110 Base64
|
c@75
|
111 };
|
c@75
|
112
|
c@75
|
113 static bool failed(const std::string &err) {
|
c@75
|
114 return err != "";
|
c@75
|
115 }
|
c@75
|
116
|
c@75
|
117 template <typename T>
|
c@75
|
118 static json11::Json
|
c@75
|
119 fromBasicDescriptor(const T &t) {
|
c@75
|
120 return json11::Json::object {
|
c@75
|
121 { "identifier", t.identifier },
|
c@75
|
122 { "name", t.name },
|
c@75
|
123 { "description", t.description }
|
c@75
|
124 };
|
c@75
|
125 }
|
c@75
|
126
|
c@75
|
127 template <typename T>
|
c@75
|
128 static void
|
c@75
|
129 toBasicDescriptor(json11::Json j, T &t, std::string &err) {
|
c@75
|
130 if (!j.is_object()) {
|
c@75
|
131 err = "object expected for basic descriptor content";
|
c@75
|
132 return;
|
c@75
|
133 }
|
c@75
|
134 if (!j["identifier"].is_string()) {
|
c@75
|
135 err = "string expected for identifier";
|
c@75
|
136 return;
|
c@75
|
137 }
|
c@75
|
138 t.identifier = j["identifier"].string_value();
|
c@75
|
139 t.name = j["name"].string_value();
|
c@75
|
140 t.description = j["description"].string_value();
|
c@75
|
141 }
|
c@75
|
142
|
c@75
|
143 template <typename T>
|
c@75
|
144 static json11::Json
|
c@75
|
145 fromValueExtents(const T &t) {
|
c@75
|
146 return json11::Json::object {
|
c@75
|
147 { "min", t.minValue },
|
c@75
|
148 { "max", t.maxValue }
|
c@75
|
149 };
|
c@75
|
150 }
|
c@75
|
151
|
c@75
|
152 template <typename T>
|
c@75
|
153 static bool
|
c@75
|
154 toValueExtents(json11::Json j, T &t, std::string &err) {
|
c@75
|
155 if (j["extents"].is_null()) {
|
c@75
|
156 return false;
|
c@75
|
157 } else if (j["extents"].is_object()) {
|
c@75
|
158 if (j["extents"]["min"].is_number() &&
|
c@75
|
159 j["extents"]["max"].is_number()) {
|
c@140
|
160 t.minValue = float(j["extents"]["min"].number_value());
|
c@140
|
161 t.maxValue = float(j["extents"]["max"].number_value());
|
c@75
|
162 return true;
|
c@75
|
163 } else {
|
c@75
|
164 err = "numbers expected for min and max";
|
c@75
|
165 return false;
|
c@75
|
166 }
|
c@75
|
167 } else {
|
c@75
|
168 err = "object expected for extents (if present)";
|
c@75
|
169 return false;
|
c@75
|
170 }
|
c@75
|
171 }
|
c@75
|
172
|
c@75
|
173 static json11::Json
|
c@75
|
174 fromRealTime(const Vamp::RealTime &r) {
|
c@75
|
175 return json11::Json::object {
|
c@75
|
176 { "s", r.sec },
|
c@75
|
177 { "n", r.nsec }
|
c@75
|
178 };
|
c@75
|
179 }
|
c@75
|
180
|
c@75
|
181 static Vamp::RealTime
|
c@75
|
182 toRealTime(json11::Json j, std::string &err) {
|
c@75
|
183 json11::Json sec = j["s"];
|
c@75
|
184 json11::Json nsec = j["n"];
|
c@75
|
185 if (!sec.is_number() || !nsec.is_number()) {
|
c@75
|
186 err = "invalid Vamp::RealTime object " + j.dump();
|
c@75
|
187 return {};
|
c@75
|
188 }
|
c@75
|
189 return Vamp::RealTime(sec.int_value(), nsec.int_value());
|
c@75
|
190 }
|
c@75
|
191
|
c@75
|
192 static std::string
|
c@75
|
193 fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType type) {
|
c@75
|
194 switch (type) {
|
c@75
|
195 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep:
|
c@75
|
196 return "OneSamplePerStep";
|
c@75
|
197 case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
|
c@75
|
198 return "FixedSampleRate";
|
c@75
|
199 case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
|
c@75
|
200 return "VariableSampleRate";
|
c@75
|
201 }
|
c@75
|
202 return "";
|
c@75
|
203 }
|
c@75
|
204
|
c@75
|
205 static Vamp::Plugin::OutputDescriptor::SampleType
|
c@75
|
206 toSampleType(std::string text, std::string &err) {
|
c@75
|
207 if (text == "OneSamplePerStep") {
|
c@75
|
208 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
|
c@75
|
209 } else if (text == "FixedSampleRate") {
|
c@75
|
210 return Vamp::Plugin::OutputDescriptor::FixedSampleRate;
|
c@75
|
211 } else if (text == "VariableSampleRate") {
|
c@75
|
212 return Vamp::Plugin::OutputDescriptor::VariableSampleRate;
|
c@75
|
213 } else {
|
c@75
|
214 err = "invalid sample type string: " + text;
|
c@75
|
215 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
|
c@75
|
216 }
|
c@75
|
217 }
|
c@75
|
218
|
c@75
|
219 static json11::Json
|
cannam@220
|
220 fromStaticOutputDescriptor(const StaticOutputDescriptor &sd) {
|
cannam@220
|
221 json11::Json::object jo;
|
cannam@220
|
222 if (sd.typeURI != "") {
|
cannam@220
|
223 jo["typeURI"] = sd.typeURI;
|
cannam@220
|
224 }
|
cannam@220
|
225 return json11::Json(jo);
|
cannam@220
|
226 }
|
cannam@220
|
227
|
cannam@220
|
228 static json11::Json
|
c@75
|
229 fromConfiguredOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) {
|
c@75
|
230 json11::Json::object jo {
|
c@75
|
231 { "unit", desc.unit },
|
c@75
|
232 { "sampleType", fromSampleType(desc.sampleType) },
|
c@75
|
233 { "sampleRate", desc.sampleRate },
|
c@75
|
234 { "hasDuration", desc.hasDuration }
|
c@75
|
235 };
|
c@75
|
236 if (desc.hasFixedBinCount) {
|
c@75
|
237 jo["binCount"] = int(desc.binCount);
|
c@75
|
238 jo["binNames"] = json11::Json::array
|
c@75
|
239 (desc.binNames.begin(), desc.binNames.end());
|
c@75
|
240 }
|
c@75
|
241 if (desc.hasKnownExtents) {
|
c@75
|
242 jo["extents"] = fromValueExtents(desc);
|
c@75
|
243 }
|
c@75
|
244 if (desc.isQuantized) {
|
c@75
|
245 jo["quantizeStep"] = desc.quantizeStep;
|
c@75
|
246 }
|
c@75
|
247 return json11::Json(jo);
|
c@75
|
248 }
|
c@75
|
249
|
c@75
|
250 static json11::Json
|
cannam@220
|
251 fromOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc,
|
cannam@220
|
252 const StaticOutputDescriptor &sd) {
|
c@75
|
253 json11::Json::object jo {
|
c@75
|
254 { "basic", fromBasicDescriptor(desc) },
|
cannam@220
|
255 { "static", fromStaticOutputDescriptor(sd) },
|
c@75
|
256 { "configured", fromConfiguredOutputDescriptor(desc) }
|
c@75
|
257 };
|
c@75
|
258 return json11::Json(jo);
|
c@75
|
259 }
|
cannam@220
|
260
|
cannam@220
|
261 static StaticOutputDescriptor
|
cannam@220
|
262 toStaticOutputDescriptor(json11::Json j, std::string &err) {
|
cannam@220
|
263
|
cannam@220
|
264 StaticOutputDescriptor sd;
|
cannam@220
|
265 if (!j.is_object()) {
|
cannam@220
|
266 err = "object expected for static output descriptor";
|
cannam@233
|
267 return sd;
|
cannam@220
|
268 }
|
cannam@220
|
269
|
cannam@220
|
270 sd.typeURI = j["typeURI"].string_value();
|
cannam@220
|
271 return sd;
|
cannam@220
|
272 }
|
c@75
|
273
|
c@75
|
274 static Vamp::Plugin::OutputDescriptor
|
c@75
|
275 toConfiguredOutputDescriptor(json11::Json j, std::string &err) {
|
c@75
|
276
|
c@75
|
277 Vamp::Plugin::OutputDescriptor od;
|
c@75
|
278 if (!j.is_object()) {
|
c@75
|
279 err = "object expected for output descriptor";
|
c@75
|
280 return {};
|
c@75
|
281 }
|
c@75
|
282
|
c@75
|
283 od.unit = j["unit"].string_value();
|
c@75
|
284
|
c@75
|
285 od.sampleType = toSampleType(j["sampleType"].string_value(), err);
|
c@75
|
286 if (failed(err)) return {};
|
c@75
|
287
|
c@75
|
288 if (!j["sampleRate"].is_number()) {
|
c@75
|
289 err = "number expected for sample rate";
|
c@75
|
290 return {};
|
c@75
|
291 }
|
c@139
|
292 od.sampleRate = float(j["sampleRate"].number_value());
|
c@75
|
293 od.hasDuration = j["hasDuration"].bool_value();
|
c@75
|
294
|
c@75
|
295 if (j["binCount"].is_number() && j["binCount"].int_value() > 0) {
|
c@75
|
296 od.hasFixedBinCount = true;
|
c@75
|
297 od.binCount = j["binCount"].int_value();
|
c@75
|
298 for (auto &n: j["binNames"].array_items()) {
|
c@75
|
299 if (!n.is_string()) {
|
c@75
|
300 err = "string expected for bin name";
|
c@75
|
301 return {};
|
c@75
|
302 }
|
c@75
|
303 od.binNames.push_back(n.string_value());
|
c@75
|
304 }
|
c@75
|
305 } else {
|
c@75
|
306 od.hasFixedBinCount = false;
|
c@75
|
307 }
|
c@75
|
308
|
c@75
|
309 bool extentsPresent = toValueExtents(j, od, err);
|
c@75
|
310 if (failed(err)) return {};
|
c@75
|
311
|
c@75
|
312 od.hasKnownExtents = extentsPresent;
|
c@75
|
313
|
c@75
|
314 if (j["quantizeStep"].is_number()) {
|
c@75
|
315 od.isQuantized = true;
|
c@139
|
316 od.quantizeStep = float(j["quantizeStep"].number_value());
|
c@75
|
317 } else {
|
c@75
|
318 od.isQuantized = false;
|
c@75
|
319 }
|
c@75
|
320
|
c@75
|
321 return od;
|
c@75
|
322 }
|
c@75
|
323
|
cannam@220
|
324 static std::pair<Vamp::Plugin::OutputDescriptor, StaticOutputDescriptor>
|
c@75
|
325 toOutputDescriptor(json11::Json j, std::string &err) {
|
c@75
|
326
|
c@75
|
327 Vamp::Plugin::OutputDescriptor od;
|
c@75
|
328 if (!j.is_object()) {
|
c@75
|
329 err = "object expected for output descriptor";
|
c@75
|
330 return {};
|
c@75
|
331 }
|
c@75
|
332
|
dev@175
|
333 od = toConfiguredOutputDescriptor(j["configured"], err);
|
c@75
|
334 if (failed(err)) return {};
|
c@75
|
335
|
c@75
|
336 toBasicDescriptor(j["basic"], od, err);
|
c@75
|
337 if (failed(err)) return {};
|
c@75
|
338
|
cannam@220
|
339 StaticOutputDescriptor sd;
|
cannam@220
|
340 if (j["static"] != json11::Json()) {
|
cannam@220
|
341 sd = toStaticOutputDescriptor(j["static"], err);
|
cannam@220
|
342 if (failed(err)) return {};
|
cannam@220
|
343 }
|
cannam@220
|
344
|
cannam@220
|
345 return { od, sd };
|
c@75
|
346 }
|
c@75
|
347
|
c@75
|
348 static json11::Json
|
c@75
|
349 fromParameterDescriptor(const Vamp::PluginBase::ParameterDescriptor &desc) {
|
c@75
|
350
|
c@75
|
351 json11::Json::object jo {
|
c@75
|
352 { "basic", fromBasicDescriptor(desc) },
|
c@75
|
353 { "unit", desc.unit },
|
c@75
|
354 { "extents", fromValueExtents(desc) },
|
c@75
|
355 { "defaultValue", desc.defaultValue },
|
c@75
|
356 { "valueNames", json11::Json::array
|
c@75
|
357 (desc.valueNames.begin(), desc.valueNames.end()) }
|
c@75
|
358 };
|
c@75
|
359 if (desc.isQuantized) {
|
c@75
|
360 jo["quantizeStep"] = desc.quantizeStep;
|
c@75
|
361 }
|
c@75
|
362 return json11::Json(jo);
|
c@75
|
363 }
|
c@75
|
364
|
c@75
|
365 static Vamp::PluginBase::ParameterDescriptor
|
c@75
|
366 toParameterDescriptor(json11::Json j, std::string &err) {
|
c@75
|
367
|
c@75
|
368 Vamp::PluginBase::ParameterDescriptor pd;
|
c@75
|
369 if (!j.is_object()) {
|
c@75
|
370 err = "object expected for parameter descriptor";
|
c@75
|
371 return {};
|
c@75
|
372 }
|
c@75
|
373
|
c@75
|
374 toBasicDescriptor(j["basic"], pd, err);
|
c@75
|
375 if (failed(err)) return {};
|
c@75
|
376
|
c@75
|
377 pd.unit = j["unit"].string_value();
|
c@75
|
378
|
c@75
|
379 bool extentsPresent = toValueExtents(j, pd, err);
|
c@75
|
380 if (failed(err)) return {};
|
c@75
|
381 if (!extentsPresent) {
|
c@75
|
382 err = "extents must be present in parameter descriptor";
|
c@75
|
383 return {};
|
c@75
|
384 }
|
c@75
|
385
|
c@75
|
386 if (!j["defaultValue"].is_number()) {
|
c@75
|
387 err = "number expected for default value";
|
c@75
|
388 return {};
|
c@75
|
389 }
|
c@75
|
390
|
c@139
|
391 pd.defaultValue = float(j["defaultValue"].number_value());
|
c@75
|
392
|
c@75
|
393 pd.valueNames.clear();
|
c@75
|
394 for (auto &n: j["valueNames"].array_items()) {
|
c@75
|
395 if (!n.is_string()) {
|
c@75
|
396 err = "string expected for value name";
|
c@75
|
397 return {};
|
c@75
|
398 }
|
c@75
|
399 pd.valueNames.push_back(n.string_value());
|
c@75
|
400 }
|
c@75
|
401
|
c@75
|
402 if (j["quantizeStep"].is_number()) {
|
c@75
|
403 pd.isQuantized = true;
|
c@139
|
404 pd.quantizeStep = float(j["quantizeStep"].number_value());
|
c@75
|
405 } else {
|
c@75
|
406 pd.isQuantized = false;
|
c@75
|
407 }
|
c@75
|
408
|
c@75
|
409 return pd;
|
c@75
|
410 }
|
c@75
|
411
|
c@75
|
412 static std::string
|
c@75
|
413 fromFloatBuffer(const float *buffer, size_t nfloats) {
|
c@75
|
414 // must use char pointers, otherwise the converter will only
|
c@75
|
415 // encode every 4th byte (as it will count up in float* steps)
|
c@75
|
416 const char *start = reinterpret_cast<const char *>(buffer);
|
c@75
|
417 const char *end = reinterpret_cast<const char *>(buffer + nfloats);
|
c@75
|
418 std::string encoded;
|
c@75
|
419 bn::encode_b64(start, end, back_inserter(encoded));
|
c@75
|
420 return encoded;
|
c@75
|
421 }
|
c@75
|
422
|
c@75
|
423 static std::vector<float>
|
c@75
|
424 toFloatBuffer(std::string encoded, std::string & /* err */) {
|
c@75
|
425 std::string decoded;
|
c@75
|
426 bn::decode_b64(encoded.begin(), encoded.end(), back_inserter(decoded));
|
c@75
|
427 const float *buffer = reinterpret_cast<const float *>(decoded.c_str());
|
c@75
|
428 size_t n = decoded.size() / sizeof(float);
|
c@75
|
429 return std::vector<float>(buffer, buffer + n);
|
c@75
|
430 }
|
c@75
|
431
|
c@75
|
432 static json11::Json
|
c@75
|
433 fromFeature(const Vamp::Plugin::Feature &f,
|
c@75
|
434 BufferSerialisation serialisation) {
|
c@75
|
435
|
c@75
|
436 json11::Json::object jo;
|
c@75
|
437 if (f.values.size() > 0) {
|
c@75
|
438 if (serialisation == BufferSerialisation::Array) {
|
c@75
|
439 jo["featureValues"] = json11::Json::array(f.values.begin(),
|
c@75
|
440 f.values.end());
|
c@75
|
441 } else {
|
c@75
|
442 jo["featureValues"] = fromFloatBuffer(f.values.data(),
|
c@75
|
443 f.values.size());
|
c@75
|
444 }
|
c@75
|
445 }
|
c@75
|
446 if (f.label != "") {
|
c@75
|
447 jo["label"] = f.label;
|
c@75
|
448 }
|
c@75
|
449 if (f.hasTimestamp) {
|
c@75
|
450 jo["timestamp"] = fromRealTime(f.timestamp);
|
c@75
|
451 }
|
c@75
|
452 if (f.hasDuration) {
|
c@75
|
453 jo["duration"] = fromRealTime(f.duration);
|
c@75
|
454 }
|
c@75
|
455 return json11::Json(jo);
|
c@75
|
456 }
|
c@75
|
457
|
c@75
|
458 static Vamp::Plugin::Feature
|
c@75
|
459 toFeature(json11::Json j, BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
460
|
c@75
|
461 Vamp::Plugin::Feature f;
|
c@75
|
462 if (!j.is_object()) {
|
c@75
|
463 err = "object expected for feature";
|
c@75
|
464 return {};
|
c@75
|
465 }
|
c@75
|
466 if (j["timestamp"].is_object()) {
|
c@75
|
467 f.timestamp = toRealTime(j["timestamp"], err);
|
c@75
|
468 if (failed(err)) return {};
|
c@75
|
469 f.hasTimestamp = true;
|
c@75
|
470 }
|
c@75
|
471 if (j["duration"].is_object()) {
|
c@75
|
472 f.duration = toRealTime(j["duration"], err);
|
c@75
|
473 if (failed(err)) return {};
|
c@75
|
474 f.hasDuration = true;
|
c@75
|
475 }
|
c@75
|
476 if (j["featureValues"].is_string()) {
|
c@75
|
477 f.values = toFloatBuffer(j["featureValues"].string_value(), err);
|
c@75
|
478 if (failed(err)) return {};
|
c@75
|
479 serialisation = BufferSerialisation::Base64;
|
c@75
|
480 } else if (j["featureValues"].is_array()) {
|
c@75
|
481 for (auto v : j["featureValues"].array_items()) {
|
c@139
|
482 f.values.push_back(float(v.number_value()));
|
c@75
|
483 }
|
c@75
|
484 serialisation = BufferSerialisation::Array;
|
c@75
|
485 }
|
c@75
|
486 f.label = j["label"].string_value();
|
c@75
|
487 return f;
|
c@75
|
488 }
|
c@75
|
489
|
c@75
|
490 static json11::Json
|
c@75
|
491 fromFeatureSet(const Vamp::Plugin::FeatureSet &fs,
|
c@75
|
492 const PluginOutputIdMapper &omapper,
|
c@75
|
493 BufferSerialisation serialisation) {
|
c@75
|
494
|
c@75
|
495 json11::Json::object jo;
|
c@75
|
496 for (const auto &fsi : fs) {
|
c@75
|
497 std::vector<json11::Json> fj;
|
c@75
|
498 for (const Vamp::Plugin::Feature &f: fsi.second) {
|
c@75
|
499 fj.push_back(fromFeature(f, serialisation));
|
c@75
|
500 }
|
c@75
|
501 jo[omapper.indexToId(fsi.first)] = fj;
|
c@75
|
502 }
|
c@75
|
503 return json11::Json(jo);
|
c@75
|
504 }
|
c@75
|
505
|
c@75
|
506 static Vamp::Plugin::FeatureList
|
c@75
|
507 toFeatureList(json11::Json j,
|
c@75
|
508 BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
509
|
c@75
|
510 Vamp::Plugin::FeatureList fl;
|
c@75
|
511 if (!j.is_array()) {
|
c@75
|
512 err = "array expected for feature list";
|
cannam@203
|
513 return fl;
|
c@75
|
514 }
|
c@75
|
515 for (const json11::Json &fj : j.array_items()) {
|
c@75
|
516 fl.push_back(toFeature(fj, serialisation, err));
|
cannam@203
|
517 if (failed(err)) return fl;
|
c@75
|
518 }
|
c@75
|
519 return fl;
|
c@75
|
520 }
|
c@75
|
521
|
c@75
|
522 static Vamp::Plugin::FeatureSet
|
c@75
|
523 toFeatureSet(json11::Json j,
|
c@75
|
524 const PluginOutputIdMapper &omapper,
|
c@75
|
525 BufferSerialisation &serialisation,
|
c@75
|
526 std::string &err) {
|
c@75
|
527
|
c@75
|
528 Vamp::Plugin::FeatureSet fs;
|
c@75
|
529 if (!j.is_object()) {
|
c@75
|
530 err = "object expected for feature set";
|
cannam@203
|
531 return fs;
|
c@75
|
532 }
|
c@75
|
533 for (auto &entry : j.object_items()) {
|
c@75
|
534 int n = omapper.idToIndex(entry.first);
|
c@75
|
535 if (fs.find(n) != fs.end()) {
|
c@75
|
536 err = "duplicate numerical index for output";
|
cannam@203
|
537 return fs;
|
c@75
|
538 }
|
c@75
|
539 fs[n] = toFeatureList(entry.second, serialisation, err);
|
cannam@203
|
540 if (failed(err)) return fs;
|
c@75
|
541 }
|
c@75
|
542 return fs;
|
c@75
|
543 }
|
c@75
|
544
|
c@75
|
545 static std::string
|
c@75
|
546 fromInputDomain(Vamp::Plugin::InputDomain domain) {
|
c@75
|
547
|
c@75
|
548 switch (domain) {
|
c@75
|
549 case Vamp::Plugin::TimeDomain:
|
c@75
|
550 return "TimeDomain";
|
c@75
|
551 case Vamp::Plugin::FrequencyDomain:
|
c@75
|
552 return "FrequencyDomain";
|
c@75
|
553 }
|
c@75
|
554 return "";
|
c@75
|
555 }
|
c@75
|
556
|
c@75
|
557 static Vamp::Plugin::InputDomain
|
c@75
|
558 toInputDomain(std::string text, std::string &err) {
|
c@75
|
559
|
c@75
|
560 if (text == "TimeDomain") {
|
c@75
|
561 return Vamp::Plugin::TimeDomain;
|
c@75
|
562 } else if (text == "FrequencyDomain") {
|
c@75
|
563 return Vamp::Plugin::FrequencyDomain;
|
c@75
|
564 } else {
|
c@75
|
565 err = "invalid input domain string: " + text;
|
c@75
|
566 return {};
|
c@75
|
567 }
|
c@75
|
568 }
|
c@75
|
569
|
c@75
|
570 static json11::Json
|
c@97
|
571 fromPluginStaticData(const PluginStaticData &d) {
|
c@75
|
572
|
c@75
|
573 json11::Json::object jo;
|
c@75
|
574 jo["key"] = d.pluginKey;
|
c@75
|
575 jo["basic"] = fromBasicDescriptor(d.basic);
|
c@75
|
576 jo["maker"] = d.maker;
|
cannam@216
|
577 jo["rights"] = d.copyright;
|
c@75
|
578 jo["version"] = d.pluginVersion;
|
c@75
|
579
|
c@75
|
580 json11::Json::array cat;
|
c@75
|
581 for (const std::string &c: d.category) cat.push_back(c);
|
c@75
|
582 jo["category"] = cat;
|
c@75
|
583
|
c@105
|
584 jo["minChannelCount"] = int(d.minChannelCount);
|
c@105
|
585 jo["maxChannelCount"] = int(d.maxChannelCount);
|
c@75
|
586
|
c@75
|
587 json11::Json::array params;
|
c@75
|
588 Vamp::PluginBase::ParameterList vparams = d.parameters;
|
c@75
|
589 for (auto &p: vparams) params.push_back(fromParameterDescriptor(p));
|
c@75
|
590 jo["parameters"] = params;
|
c@75
|
591
|
c@75
|
592 json11::Json::array progs;
|
c@75
|
593 Vamp::PluginBase::ProgramList vprogs = d.programs;
|
c@75
|
594 for (auto &p: vprogs) progs.push_back(p);
|
c@75
|
595 jo["programs"] = progs;
|
c@75
|
596
|
c@75
|
597 jo["inputDomain"] = fromInputDomain(d.inputDomain);
|
c@75
|
598
|
c@75
|
599 json11::Json::array outinfo;
|
c@75
|
600 auto vouts = d.basicOutputInfo;
|
c@75
|
601 for (auto &o: vouts) outinfo.push_back(fromBasicDescriptor(o));
|
c@75
|
602 jo["basicOutputInfo"] = outinfo;
|
cannam@220
|
603
|
cannam@220
|
604 json11::Json::object statinfo;
|
cannam@220
|
605 auto souts = d.staticOutputInfo;
|
cannam@221
|
606 for (auto &s: souts) {
|
cannam@221
|
607 statinfo[s.first] = fromStaticOutputDescriptor(s.second);
|
cannam@221
|
608 }
|
cannam@221
|
609 jo["staticOutputInfo"] = statinfo;
|
cannam@220
|
610
|
c@75
|
611 return json11::Json(jo);
|
c@75
|
612 }
|
c@75
|
613
|
cannam@221
|
614 static StaticOutputInfo
|
cannam@221
|
615 toStaticOutputInfo(json11::Json j, std::string &err) {
|
cannam@221
|
616
|
cannam@221
|
617 if (j == json11::Json()) return {};
|
cannam@221
|
618
|
cannam@221
|
619 if (!j.is_object()) {
|
cannam@221
|
620 err = "object expected for static output info";
|
cannam@221
|
621 return {};
|
cannam@221
|
622 }
|
cannam@221
|
623
|
cannam@221
|
624 StaticOutputInfo sinfo;
|
cannam@221
|
625 auto items = j.object_items();
|
cannam@221
|
626 for (auto i: items) {
|
cannam@221
|
627 sinfo[i.first] = toStaticOutputDescriptor(i.second, err);
|
cannam@221
|
628 if (failed(err)) return {};
|
cannam@221
|
629 }
|
cannam@221
|
630 return sinfo;
|
cannam@221
|
631 }
|
cannam@221
|
632
|
c@97
|
633 static PluginStaticData
|
c@75
|
634 toPluginStaticData(json11::Json j, std::string &err) {
|
c@75
|
635
|
c@75
|
636 if (!j.has_shape({
|
c@75
|
637 { "key", json11::Json::STRING },
|
c@75
|
638 { "version", json11::Json::NUMBER },
|
c@75
|
639 { "minChannelCount", json11::Json::NUMBER },
|
c@75
|
640 { "maxChannelCount", json11::Json::NUMBER },
|
c@75
|
641 { "inputDomain", json11::Json::STRING }}, err)) {
|
c@75
|
642
|
c@75
|
643 err = "malformed plugin static data: " + err;
|
c@75
|
644
|
c@75
|
645 } else if (!j["basicOutputInfo"].is_array()) {
|
c@75
|
646
|
c@75
|
647 err = "array expected for basic output info";
|
c@75
|
648
|
c@75
|
649 } else if (!j["maker"].is_null() &&
|
c@75
|
650 !j["maker"].is_string()) {
|
c@75
|
651
|
c@75
|
652 err = "string expected for maker";
|
c@75
|
653
|
cannam@216
|
654 } else if (!j["rights"].is_null() &&
|
cannam@216
|
655 !j["rights"].is_string()) {
|
cannam@230
|
656
|
cannam@216
|
657 err = "string expected for rights";
|
c@75
|
658
|
c@75
|
659 } else if (!j["category"].is_null() &&
|
c@75
|
660 !j["category"].is_array()) {
|
c@75
|
661
|
c@75
|
662 err = "array expected for category";
|
c@75
|
663
|
c@75
|
664 } else if (!j["parameters"].is_null() &&
|
c@75
|
665 !j["parameters"].is_array()) {
|
c@75
|
666
|
c@75
|
667 err = "array expected for parameters";
|
c@75
|
668
|
c@75
|
669 } else if (!j["programs"].is_null() &&
|
c@75
|
670 !j["programs"].is_array()) {
|
c@75
|
671
|
c@75
|
672 err = "array expected for programs";
|
c@75
|
673
|
c@75
|
674 } else if (!j["inputDomain"].is_null() &&
|
c@75
|
675 !j["inputDomain"].is_string()) {
|
c@75
|
676
|
c@75
|
677 err = "string expected for inputDomain";
|
c@75
|
678
|
cannam@221
|
679 } else if (!j["staticOutputInfo"].is_null() &&
|
cannam@221
|
680 !j["staticOutputInfo"].is_object()) {
|
cannam@221
|
681
|
cannam@221
|
682 err = "object expected for staticOutputInfo";
|
cannam@221
|
683
|
c@75
|
684 } else {
|
c@75
|
685
|
c@97
|
686 PluginStaticData psd;
|
c@75
|
687
|
c@75
|
688 psd.pluginKey = j["key"].string_value();
|
c@75
|
689
|
c@75
|
690 toBasicDescriptor(j["basic"], psd.basic, err);
|
c@75
|
691 if (failed(err)) return {};
|
c@75
|
692
|
c@75
|
693 psd.maker = j["maker"].string_value();
|
cannam@216
|
694 psd.copyright = j["rights"].string_value();
|
c@75
|
695 psd.pluginVersion = j["version"].int_value();
|
c@75
|
696
|
c@75
|
697 for (const auto &c : j["category"].array_items()) {
|
c@75
|
698 if (!c.is_string()) {
|
c@75
|
699 err = "strings expected in category array";
|
c@75
|
700 return {};
|
c@75
|
701 }
|
c@75
|
702 psd.category.push_back(c.string_value());
|
c@75
|
703 }
|
c@75
|
704
|
c@75
|
705 psd.minChannelCount = j["minChannelCount"].int_value();
|
c@75
|
706 psd.maxChannelCount = j["maxChannelCount"].int_value();
|
c@75
|
707
|
c@75
|
708 for (const auto &p : j["parameters"].array_items()) {
|
c@75
|
709 auto pd = toParameterDescriptor(p, err);
|
c@75
|
710 if (failed(err)) return {};
|
c@75
|
711 psd.parameters.push_back(pd);
|
c@75
|
712 }
|
c@75
|
713
|
c@75
|
714 for (const auto &p : j["programs"].array_items()) {
|
c@75
|
715 if (!p.is_string()) {
|
c@75
|
716 err = "strings expected in programs array";
|
c@75
|
717 return {};
|
c@75
|
718 }
|
c@75
|
719 psd.programs.push_back(p.string_value());
|
c@75
|
720 }
|
c@75
|
721
|
c@75
|
722 psd.inputDomain = toInputDomain(j["inputDomain"].string_value(), err);
|
c@75
|
723 if (failed(err)) return {};
|
c@75
|
724
|
c@75
|
725 for (const auto &bo : j["basicOutputInfo"].array_items()) {
|
c@97
|
726 PluginStaticData::Basic b;
|
c@75
|
727 toBasicDescriptor(bo, b, err);
|
c@75
|
728 if (failed(err)) return {};
|
c@75
|
729 psd.basicOutputInfo.push_back(b);
|
c@75
|
730 }
|
cannam@221
|
731
|
cannam@221
|
732 StaticOutputInfo sinfo =
|
cannam@221
|
733 toStaticOutputInfo(j["staticOutputInfo"], err);
|
cannam@221
|
734 if (failed(err)) return {};
|
cannam@221
|
735 psd.staticOutputInfo = sinfo;
|
cannam@221
|
736
|
c@75
|
737 return psd;
|
c@75
|
738 }
|
c@75
|
739
|
c@75
|
740 // fallthrough error case
|
c@75
|
741 return {};
|
c@75
|
742 }
|
c@75
|
743
|
c@75
|
744 static json11::Json
|
c@97
|
745 fromPluginConfiguration(const PluginConfiguration &c) {
|
c@75
|
746
|
c@75
|
747 json11::Json::object jo;
|
c@75
|
748
|
c@75
|
749 json11::Json::object paramValues;
|
c@75
|
750 for (auto &vp: c.parameterValues) {
|
c@75
|
751 paramValues[vp.first] = vp.second;
|
c@75
|
752 }
|
c@75
|
753 jo["parameterValues"] = paramValues;
|
c@75
|
754
|
c@75
|
755 if (c.currentProgram != "") {
|
c@75
|
756 jo["currentProgram"] = c.currentProgram;
|
c@75
|
757 }
|
c@75
|
758
|
c@75
|
759 jo["channelCount"] = c.channelCount;
|
cannam@185
|
760
|
cannam@185
|
761 json11::Json::object framing;
|
cannam@185
|
762 framing["stepSize"] = c.framing.stepSize;
|
cannam@185
|
763 framing["blockSize"] = c.framing.blockSize;
|
cannam@185
|
764 jo["framing"] = framing;
|
c@75
|
765
|
c@75
|
766 return json11::Json(jo);
|
c@75
|
767 }
|
c@75
|
768
|
c@97
|
769 static PluginConfiguration
|
c@75
|
770 toPluginConfiguration(json11::Json j, std::string &err) {
|
c@75
|
771
|
c@75
|
772 if (!j.has_shape({
|
cannam@185
|
773 { "channelCount", json11::Json::NUMBER } }, err)) {
|
c@75
|
774 err = "malformed plugin configuration: " + err;
|
c@75
|
775 return {};
|
c@75
|
776 }
|
c@75
|
777
|
cannam@185
|
778 if (!j["framing"].has_shape({
|
cannam@185
|
779 { "stepSize", json11::Json::NUMBER },
|
cannam@185
|
780 { "blockSize", json11::Json::NUMBER } }, err)) {
|
cannam@185
|
781 err = "malformed framing: " + err;
|
cannam@185
|
782 return {};
|
cannam@185
|
783 }
|
cannam@185
|
784
|
c@75
|
785 if (!j["parameterValues"].is_null() &&
|
c@75
|
786 !j["parameterValues"].is_object()) {
|
c@75
|
787 err = "object expected for parameter values";
|
c@75
|
788 return {};
|
c@75
|
789 }
|
c@75
|
790
|
c@75
|
791 for (auto &pv : j["parameterValues"].object_items()) {
|
c@75
|
792 if (!pv.second.is_number()) {
|
c@75
|
793 err = "number expected for parameter value";
|
c@75
|
794 return {};
|
c@75
|
795 }
|
c@75
|
796 }
|
c@75
|
797
|
c@75
|
798 if (!j["currentProgram"].is_null() &&
|
c@75
|
799 !j["currentProgram"].is_string()) {
|
c@75
|
800 err = "string expected for program name";
|
c@75
|
801 return {};
|
c@75
|
802 }
|
c@75
|
803
|
c@97
|
804 PluginConfiguration config;
|
c@75
|
805
|
c@139
|
806 config.channelCount = int(round(j["channelCount"].number_value()));
|
cannam@185
|
807 config.framing.stepSize = int(round(j["framing"]["stepSize"].number_value()));
|
cannam@185
|
808 config.framing.blockSize = int(round(j["framing"]["blockSize"].number_value()));
|
c@75
|
809
|
c@75
|
810 for (auto &pv : j["parameterValues"].object_items()) {
|
c@139
|
811 config.parameterValues[pv.first] = float(pv.second.number_value());
|
c@75
|
812 }
|
c@75
|
813
|
c@75
|
814 if (j["currentProgram"].is_string()) {
|
c@75
|
815 config.currentProgram = j["currentProgram"].string_value();
|
c@75
|
816 }
|
c@75
|
817
|
c@75
|
818 return config;
|
c@75
|
819 }
|
c@75
|
820
|
c@75
|
821 static json11::Json
|
c@75
|
822 fromAdapterFlags(int flags) {
|
c@75
|
823
|
c@75
|
824 json11::Json::array arr;
|
c@75
|
825
|
c@75
|
826 if (flags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) {
|
c@75
|
827 arr.push_back("AdaptInputDomain");
|
c@75
|
828 }
|
c@75
|
829 if (flags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) {
|
c@75
|
830 arr.push_back("AdaptChannelCount");
|
c@75
|
831 }
|
c@75
|
832 if (flags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) {
|
c@75
|
833 arr.push_back("AdaptBufferSize");
|
c@75
|
834 }
|
c@75
|
835
|
c@75
|
836 return json11::Json(arr);
|
c@75
|
837 }
|
c@75
|
838
|
c@75
|
839 static Vamp::HostExt::PluginLoader::AdapterFlags
|
c@75
|
840 toAdapterFlags(json11::Json j, std::string &err) {
|
c@75
|
841
|
c@75
|
842 int flags = 0x0;
|
c@75
|
843
|
c@75
|
844 if (!j.is_array()) {
|
c@75
|
845
|
c@75
|
846 err = "array expected for adapter flags";
|
c@75
|
847
|
c@75
|
848 } else {
|
c@75
|
849
|
c@75
|
850 for (auto &jj: j.array_items()) {
|
c@75
|
851 if (!jj.is_string()) {
|
c@75
|
852 err = "string expected for adapter flag";
|
c@75
|
853 break;
|
c@75
|
854 }
|
c@75
|
855 std::string text = jj.string_value();
|
c@75
|
856 if (text == "AdaptInputDomain") {
|
c@75
|
857 flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN;
|
c@75
|
858 } else if (text == "AdaptChannelCount") {
|
c@75
|
859 flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT;
|
c@75
|
860 } else if (text == "AdaptBufferSize") {
|
c@75
|
861 flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE;
|
c@75
|
862 } else if (text == "AdaptAllSafe") {
|
c@75
|
863 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE;
|
c@75
|
864 } else if (text == "AdaptAll") {
|
c@75
|
865 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL;
|
c@75
|
866 } else {
|
c@75
|
867 err = "invalid adapter flag string: " + text;
|
c@75
|
868 break;
|
c@75
|
869 }
|
c@75
|
870 }
|
c@75
|
871 }
|
c@75
|
872
|
c@75
|
873 return Vamp::HostExt::PluginLoader::AdapterFlags(flags);
|
c@75
|
874 }
|
c@75
|
875
|
c@75
|
876 static json11::Json
|
cannam@289
|
877 fromProgramParameters(const PluginProgramParameters &programParameters) {
|
cannam@289
|
878
|
cannam@289
|
879 json11::Json::object jo;
|
cannam@289
|
880 for (const auto &pp: programParameters.programParameters) {
|
cannam@289
|
881 auto program = pp.first;
|
cannam@289
|
882 json11::Json::object po;
|
cannam@289
|
883 for (const auto &pv: pp.second) {
|
cannam@289
|
884 po[pv.first] = pv.second;
|
cannam@289
|
885 }
|
cannam@289
|
886 jo[program] = po;
|
cannam@289
|
887 }
|
cannam@289
|
888
|
cannam@289
|
889 return json11::Json(jo);
|
cannam@289
|
890 }
|
cannam@289
|
891
|
cannam@289
|
892 static PluginProgramParameters
|
cannam@289
|
893 toProgramParameters(json11::Json j, std::string &err) {
|
cannam@289
|
894
|
cannam@289
|
895 if (!j.is_object()) {
|
cannam@289
|
896 err = "object expected for program parameters";
|
cannam@289
|
897 return {};
|
cannam@289
|
898 }
|
cannam@289
|
899
|
cannam@289
|
900 PluginProgramParameters params;
|
cannam@289
|
901
|
cannam@289
|
902 auto pp = j.object_items();
|
cannam@289
|
903 for (auto program: pp) {
|
cannam@289
|
904 std::string name = program.first;
|
cannam@289
|
905 if (!program.second.is_object()) {
|
cannam@289
|
906 err = std::string("object expected for program parameter map ") +
|
cannam@289
|
907 "(in program \"" + name + "\")";
|
cannam@289
|
908 return {};
|
cannam@289
|
909 }
|
cannam@289
|
910 for (auto p: program.second.object_items()) {
|
cannam@289
|
911 if (!p.second.is_number()) {
|
cannam@289
|
912 err = std::string("number expected for program parameter value ") +
|
cannam@289
|
913 "(in program \"" + name + "\")";
|
cannam@289
|
914 return {};
|
cannam@289
|
915 }
|
cannam@289
|
916 params.programParameters[name][p.first] = p.second.number_value();
|
cannam@289
|
917 }
|
cannam@289
|
918 }
|
cannam@289
|
919
|
cannam@289
|
920 return params;
|
cannam@289
|
921 }
|
cannam@289
|
922
|
cannam@289
|
923 static json11::Json
|
c@127
|
924 fromListRequest(const ListRequest &req) {
|
c@127
|
925 json11::Json::object jo;
|
c@127
|
926 json11::Json::array arr;
|
c@127
|
927 for (const auto &f: req.from) {
|
c@127
|
928 arr.push_back(f);
|
c@127
|
929 }
|
c@127
|
930 jo["from"] = arr;
|
c@127
|
931 return json11::Json(jo);
|
c@127
|
932 }
|
c@127
|
933
|
c@127
|
934 static ListRequest
|
c@127
|
935 toListRequest(json11::Json j, std::string &err) {
|
c@127
|
936
|
c@127
|
937 ListRequest req;
|
c@127
|
938 if (!j["from"].is_null() &&
|
c@127
|
939 !j["from"].is_array()) {
|
c@127
|
940 err = "array expected for from field";
|
c@127
|
941 return {};
|
c@127
|
942 }
|
c@127
|
943 for (const auto &a: j["from"].array_items()) {
|
c@127
|
944 if (!a.is_string()) {
|
c@127
|
945 err = "string expected for element in from array";
|
c@127
|
946 return {};
|
c@127
|
947 }
|
c@127
|
948 req.from.push_back(a.string_value());
|
c@127
|
949 }
|
c@127
|
950 return req;
|
c@127
|
951 }
|
c@127
|
952
|
c@127
|
953 static json11::Json
|
c@127
|
954 fromListResponse(const ListResponse &resp) {
|
c@127
|
955
|
c@127
|
956 json11::Json::array arr;
|
c@127
|
957 for (const auto &a: resp.available) {
|
c@127
|
958 arr.push_back(fromPluginStaticData(a));
|
c@127
|
959 }
|
c@127
|
960 json11::Json::object jo;
|
c@127
|
961 jo["available"] = arr;
|
c@127
|
962
|
c@127
|
963 return json11::Json(jo);
|
c@127
|
964 }
|
c@127
|
965
|
c@127
|
966 static ListResponse
|
c@127
|
967 toListResponse(json11::Json j, std::string &err) {
|
c@127
|
968
|
c@127
|
969 ListResponse resp;
|
dev@177
|
970 for (const auto &a: j["available"].array_items()) {
|
c@127
|
971 resp.available.push_back(toPluginStaticData(a, err));
|
c@127
|
972 if (failed(err)) return {};
|
c@127
|
973 }
|
c@127
|
974 return resp;
|
c@127
|
975 }
|
c@127
|
976
|
c@127
|
977 static json11::Json
|
c@97
|
978 fromLoadRequest(const LoadRequest &req) {
|
c@75
|
979
|
c@75
|
980 json11::Json::object jo;
|
c@75
|
981 jo["key"] = req.pluginKey;
|
c@75
|
982 jo["inputSampleRate"] = req.inputSampleRate;
|
c@75
|
983 jo["adapterFlags"] = fromAdapterFlags(req.adapterFlags);
|
c@75
|
984 return json11::Json(jo);
|
c@75
|
985 }
|
c@75
|
986
|
c@97
|
987 static LoadRequest
|
c@75
|
988 toLoadRequest(json11::Json j, std::string &err) {
|
c@75
|
989
|
c@75
|
990 if (!j.has_shape({
|
c@75
|
991 { "key", json11::Json::STRING },
|
c@75
|
992 { "inputSampleRate", json11::Json::NUMBER } }, err)) {
|
c@75
|
993 err = "malformed load request: " + err;
|
c@75
|
994 return {};
|
c@75
|
995 }
|
c@75
|
996
|
c@97
|
997 LoadRequest req;
|
c@75
|
998 req.pluginKey = j["key"].string_value();
|
c@139
|
999 req.inputSampleRate = float(j["inputSampleRate"].number_value());
|
c@75
|
1000 if (!j["adapterFlags"].is_null()) {
|
c@75
|
1001 req.adapterFlags = toAdapterFlags(j["adapterFlags"], err);
|
c@75
|
1002 if (failed(err)) return {};
|
c@75
|
1003 }
|
c@75
|
1004 return req;
|
c@75
|
1005 }
|
c@75
|
1006
|
c@75
|
1007 static json11::Json
|
c@97
|
1008 fromLoadResponse(const LoadResponse &resp,
|
c@75
|
1009 const PluginHandleMapper &pmapper) {
|
c@75
|
1010
|
c@75
|
1011 json11::Json::object jo;
|
c@75
|
1012 jo["handle"] = double(pmapper.pluginToHandle(resp.plugin));
|
c@75
|
1013 jo["staticData"] = fromPluginStaticData(resp.staticData);
|
c@75
|
1014 jo["defaultConfiguration"] =
|
c@75
|
1015 fromPluginConfiguration(resp.defaultConfiguration);
|
cannam@289
|
1016 jo["programParameters"] =
|
cannam@289
|
1017 fromProgramParameters(resp.programParameters);
|
c@75
|
1018 return json11::Json(jo);
|
c@75
|
1019 }
|
c@75
|
1020
|
c@97
|
1021 static LoadResponse
|
c@75
|
1022 toLoadResponse(json11::Json j,
|
c@75
|
1023 const PluginHandleMapper &pmapper, std::string &err) {
|
c@75
|
1024
|
c@75
|
1025 if (!j.has_shape({
|
c@75
|
1026 { "handle", json11::Json::NUMBER },
|
c@75
|
1027 { "staticData", json11::Json::OBJECT },
|
c@75
|
1028 { "defaultConfiguration", json11::Json::OBJECT } }, err)) {
|
c@75
|
1029 err = "malformed load response: " + err;
|
c@75
|
1030 return {};
|
c@75
|
1031 }
|
c@75
|
1032
|
c@97
|
1033 LoadResponse resp;
|
cannam@275
|
1034 auto h = j["handle"].int_value();
|
cannam@275
|
1035 resp.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1036 resp.staticData = toPluginStaticData(j["staticData"], err);
|
c@75
|
1037 if (failed(err)) return {};
|
cannam@289
|
1038 resp.defaultConfiguration =
|
cannam@289
|
1039 toPluginConfiguration(j["defaultConfiguration"], err);
|
c@75
|
1040 if (failed(err)) return {};
|
cannam@289
|
1041 if (j.object_items().find("programParameters") !=
|
cannam@289
|
1042 j.object_items().end()) {
|
cannam@289
|
1043 resp.programParameters =
|
cannam@289
|
1044 toProgramParameters(j["programParameters"], err);
|
cannam@289
|
1045 if (failed(err)) return {};
|
cannam@289
|
1046 }
|
c@75
|
1047 return resp;
|
c@75
|
1048 }
|
c@75
|
1049
|
c@75
|
1050 static json11::Json
|
c@97
|
1051 fromConfigurationRequest(const ConfigurationRequest &cr,
|
c@75
|
1052 const PluginHandleMapper &pmapper) {
|
c@75
|
1053
|
c@75
|
1054 json11::Json::object jo;
|
c@75
|
1055
|
c@86
|
1056 jo["handle"] = double(pmapper.pluginToHandle(cr.plugin));
|
c@75
|
1057 jo["configuration"] = fromPluginConfiguration(cr.configuration);
|
c@75
|
1058
|
c@75
|
1059 return json11::Json(jo);
|
c@75
|
1060 }
|
c@75
|
1061
|
c@97
|
1062 static ConfigurationRequest
|
c@75
|
1063 toConfigurationRequest(json11::Json j,
|
c@75
|
1064 const PluginHandleMapper &pmapper, std::string &err) {
|
c@75
|
1065
|
c@75
|
1066 if (!j.has_shape({
|
c@75
|
1067 { "handle", json11::Json::NUMBER },
|
c@75
|
1068 { "configuration", json11::Json::OBJECT } }, err)) {
|
c@75
|
1069 err = "malformed configuration request: " + err;
|
c@75
|
1070 return {};
|
c@75
|
1071 }
|
c@75
|
1072
|
c@97
|
1073 ConfigurationRequest cr;
|
cannam@275
|
1074 auto h = j["handle"].int_value();
|
cannam@275
|
1075 cr.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1076 cr.configuration = toPluginConfiguration(j["configuration"], err);
|
c@75
|
1077 if (failed(err)) return {};
|
c@75
|
1078 return cr;
|
c@75
|
1079 }
|
c@75
|
1080
|
c@75
|
1081 static json11::Json
|
c@97
|
1082 fromConfigurationResponse(const ConfigurationResponse &cr,
|
c@75
|
1083 const PluginHandleMapper &pmapper) {
|
c@75
|
1084
|
c@75
|
1085 json11::Json::object jo;
|
c@75
|
1086
|
c@86
|
1087 jo["handle"] = double(pmapper.pluginToHandle(cr.plugin));
|
c@75
|
1088
|
c@75
|
1089 json11::Json::array outs;
|
c@75
|
1090 for (auto &d: cr.outputs) {
|
cannam@220
|
1091 auto id = d.identifier;
|
cannam@220
|
1092 StaticOutputDescriptor sd;
|
cannam@220
|
1093 if (cr.staticOutputInfo.find(id) != cr.staticOutputInfo.end()) {
|
cannam@220
|
1094 sd = cr.staticOutputInfo.at(id);
|
cannam@220
|
1095 }
|
cannam@220
|
1096 outs.push_back(fromOutputDescriptor(d, sd));
|
c@75
|
1097 }
|
c@75
|
1098 jo["outputList"] = outs;
|
cannam@185
|
1099
|
cannam@185
|
1100 json11::Json::object framing;
|
cannam@185
|
1101 framing["stepSize"] = cr.framing.stepSize;
|
cannam@185
|
1102 framing["blockSize"] = cr.framing.blockSize;
|
cannam@185
|
1103 jo["framing"] = framing;
|
c@75
|
1104
|
c@75
|
1105 return json11::Json(jo);
|
c@75
|
1106 }
|
c@75
|
1107
|
c@97
|
1108 static ConfigurationResponse
|
c@75
|
1109 toConfigurationResponse(json11::Json j,
|
c@75
|
1110 const PluginHandleMapper &pmapper, std::string &err) {
|
c@75
|
1111
|
c@97
|
1112 ConfigurationResponse cr;
|
c@75
|
1113
|
cannam@185
|
1114 if (!j["framing"].has_shape({
|
cannam@185
|
1115 { "stepSize", json11::Json::NUMBER },
|
cannam@185
|
1116 { "blockSize", json11::Json::NUMBER } }, err)) {
|
cannam@185
|
1117 err = "malformed framing: " + err;
|
cannam@185
|
1118 return {};
|
cannam@185
|
1119 }
|
c@75
|
1120
|
c@75
|
1121 if (!j["outputList"].is_array()) {
|
c@75
|
1122 err = "array expected for output list";
|
c@75
|
1123 return {};
|
c@75
|
1124 }
|
cannam@185
|
1125
|
cannam@275
|
1126 auto h = j["handle"].int_value();
|
cannam@275
|
1127 cr.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1128
|
c@75
|
1129 for (const auto &o: j["outputList"].array_items()) {
|
cannam@220
|
1130 auto odpair = toOutputDescriptor(o, err);
|
c@75
|
1131 if (failed(err)) return {};
|
cannam@220
|
1132 cr.outputs.push_back(odpair.first);
|
cannam@220
|
1133 cr.staticOutputInfo[odpair.first.identifier] = odpair.second;
|
c@75
|
1134 }
|
c@75
|
1135
|
cannam@185
|
1136 cr.framing.stepSize = int(round(j["framing"]["stepSize"].number_value()));
|
cannam@185
|
1137 cr.framing.blockSize = int(round(j["framing"]["blockSize"].number_value()));
|
cannam@185
|
1138
|
c@75
|
1139 return cr;
|
c@75
|
1140 }
|
c@75
|
1141
|
c@75
|
1142 static json11::Json
|
c@97
|
1143 fromProcessRequest(const ProcessRequest &r,
|
c@75
|
1144 const PluginHandleMapper &pmapper,
|
c@75
|
1145 BufferSerialisation serialisation) {
|
c@75
|
1146
|
c@75
|
1147 json11::Json::object jo;
|
c@86
|
1148 jo["handle"] = double(pmapper.pluginToHandle(r.plugin));
|
c@75
|
1149
|
c@75
|
1150 json11::Json::object io;
|
c@75
|
1151 io["timestamp"] = fromRealTime(r.timestamp);
|
c@75
|
1152
|
c@75
|
1153 json11::Json::array chans;
|
c@75
|
1154 for (size_t i = 0; i < r.inputBuffers.size(); ++i) {
|
c@75
|
1155 if (serialisation == BufferSerialisation::Array) {
|
c@75
|
1156 chans.push_back(json11::Json::array(r.inputBuffers[i].begin(),
|
c@75
|
1157 r.inputBuffers[i].end()));
|
c@75
|
1158 } else {
|
c@75
|
1159 chans.push_back(fromFloatBuffer(r.inputBuffers[i].data(),
|
c@75
|
1160 r.inputBuffers[i].size()));
|
c@75
|
1161 }
|
c@75
|
1162 }
|
c@75
|
1163 io["inputBuffers"] = chans;
|
c@75
|
1164
|
c@75
|
1165 jo["processInput"] = io;
|
c@75
|
1166 return json11::Json(jo);
|
c@75
|
1167 }
|
c@75
|
1168
|
c@97
|
1169 static ProcessRequest
|
c@75
|
1170 toProcessRequest(json11::Json j,
|
c@75
|
1171 const PluginHandleMapper &pmapper,
|
c@75
|
1172 BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
1173
|
c@75
|
1174 if (!j.has_shape({
|
c@75
|
1175 { "handle", json11::Json::NUMBER },
|
c@75
|
1176 { "processInput", json11::Json::OBJECT } }, err)) {
|
c@75
|
1177 err = "malformed process request: " + err;
|
c@75
|
1178 return {};
|
c@75
|
1179 }
|
c@75
|
1180
|
c@75
|
1181 auto input = j["processInput"];
|
c@75
|
1182
|
c@75
|
1183 if (!input.has_shape({
|
c@75
|
1184 { "timestamp", json11::Json::OBJECT },
|
c@75
|
1185 { "inputBuffers", json11::Json::ARRAY } }, err)) {
|
c@75
|
1186 err = "malformed process request: " + err;
|
c@75
|
1187 return {};
|
c@75
|
1188 }
|
c@75
|
1189
|
c@97
|
1190 ProcessRequest r;
|
cannam@275
|
1191 auto h = j["handle"].int_value();
|
cannam@275
|
1192 r.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1193
|
c@75
|
1194 r.timestamp = toRealTime(input["timestamp"], err);
|
c@75
|
1195 if (failed(err)) return {};
|
c@75
|
1196
|
c@75
|
1197 for (const auto &a: input["inputBuffers"].array_items()) {
|
c@75
|
1198
|
c@75
|
1199 if (a.is_string()) {
|
c@75
|
1200 std::vector<float> buf = toFloatBuffer(a.string_value(),
|
c@75
|
1201 err);
|
c@75
|
1202 if (failed(err)) return {};
|
c@75
|
1203 r.inputBuffers.push_back(buf);
|
c@75
|
1204 serialisation = BufferSerialisation::Base64;
|
c@75
|
1205
|
c@75
|
1206 } else if (a.is_array()) {
|
c@75
|
1207 std::vector<float> buf;
|
c@75
|
1208 for (auto v : a.array_items()) {
|
c@139
|
1209 buf.push_back(float(v.number_value()));
|
c@75
|
1210 }
|
c@75
|
1211 r.inputBuffers.push_back(buf);
|
c@75
|
1212 serialisation = BufferSerialisation::Array;
|
c@75
|
1213
|
c@75
|
1214 } else {
|
c@75
|
1215 err = "expected arrays or strings in inputBuffers array";
|
c@75
|
1216 return {};
|
c@75
|
1217 }
|
c@75
|
1218 }
|
c@75
|
1219
|
c@75
|
1220 return r;
|
c@75
|
1221 }
|
c@75
|
1222
|
c@75
|
1223 private: // go private briefly for a couple of helper functions
|
c@75
|
1224
|
c@75
|
1225 static void
|
c@128
|
1226 checkRpcRequestType(json11::Json j, std::string expected, std::string &err) {
|
c@75
|
1227 if (!j["method"].is_string()) {
|
c@75
|
1228 err = "string expected for method";
|
c@75
|
1229 return;
|
c@75
|
1230 }
|
c@75
|
1231 if (j["method"].string_value() != expected) {
|
c@75
|
1232 err = "expected value \"" + expected + "\" for type";
|
c@75
|
1233 return;
|
c@75
|
1234 }
|
c@128
|
1235 if (!j["params"].is_null() &&
|
c@128
|
1236 !j["params"].is_object()) {
|
c@128
|
1237 err = "object expected for params";
|
c@128
|
1238 return;
|
c@128
|
1239 }
|
c@128
|
1240 if (!j["id"].is_null() &&
|
c@128
|
1241 !j["id"].is_number() &&
|
c@128
|
1242 !j["id"].is_string()) {
|
c@128
|
1243 err = "number or string expected for id";
|
c@128
|
1244 return;
|
c@128
|
1245 }
|
c@128
|
1246 if (!j["jsonrpc"].is_null() &&
|
c@128
|
1247 !j["jsonrpc"].is_string()) {
|
c@128
|
1248 err = "string expected for jsonrpc";
|
c@128
|
1249 return;
|
c@128
|
1250 }
|
c@128
|
1251 for (const auto &kv: j.object_items()) {
|
c@128
|
1252 if (kv.first != "method" &&
|
c@128
|
1253 kv.first != "params" &&
|
c@128
|
1254 kv.first != "id" &&
|
c@128
|
1255 kv.first != "jsonrpc") {
|
c@128
|
1256 err = "unexpected field \"" + kv.first + "\" in rpc request object";
|
c@128
|
1257 return;
|
c@128
|
1258 }
|
c@128
|
1259 }
|
c@75
|
1260 }
|
c@75
|
1261
|
c@75
|
1262 static bool
|
c@75
|
1263 successful(json11::Json j, std::string &err) {
|
dev@183
|
1264 const bool hasResult = j["result"].is_object();
|
dev@183
|
1265 const bool hasError = j["error"].is_object();
|
dev@183
|
1266 if (hasResult && hasError) {
|
dev@183
|
1267 err = "valid response may contain only one of result and error objects";
|
dev@183
|
1268 return false;
|
dev@183
|
1269 } else if (hasError) {
|
dev@183
|
1270 return false;
|
dev@183
|
1271 } else if (!hasResult) {
|
dev@183
|
1272 err = "either a result or an error object is required for a valid response";
|
dev@180
|
1273 return false;
|
dev@180
|
1274 } else {
|
dev@183
|
1275 return true;
|
c@75
|
1276 }
|
c@75
|
1277 }
|
c@75
|
1278
|
c@75
|
1279 static void
|
c@75
|
1280 markRPC(json11::Json::object &jo) {
|
c@75
|
1281 jo["jsonrpc"] = "2.0";
|
c@75
|
1282 }
|
c@75
|
1283
|
c@75
|
1284 static void
|
c@75
|
1285 addId(json11::Json::object &jo, const json11::Json &id) {
|
c@75
|
1286 if (!id.is_null()) {
|
c@75
|
1287 jo["id"] = id;
|
c@75
|
1288 }
|
c@75
|
1289 }
|
c@75
|
1290
|
c@75
|
1291 public:
|
c@75
|
1292
|
c@75
|
1293 static json11::Json
|
c@127
|
1294 fromRpcRequest_List(const ListRequest &req,
|
c@127
|
1295 const json11::Json &id) {
|
c@75
|
1296
|
c@75
|
1297 json11::Json::object jo;
|
c@75
|
1298 markRPC(jo);
|
c@75
|
1299
|
c@75
|
1300 jo["method"] = "list";
|
c@127
|
1301 jo["params"] = fromListRequest(req);
|
c@75
|
1302 addId(jo, id);
|
c@75
|
1303 return json11::Json(jo);
|
c@75
|
1304 }
|
c@75
|
1305
|
c@75
|
1306 static json11::Json
|
c@97
|
1307 fromRpcResponse_List(const ListResponse &resp,
|
c@75
|
1308 const json11::Json &id) {
|
c@75
|
1309
|
c@75
|
1310 json11::Json::object jo;
|
c@75
|
1311 markRPC(jo);
|
c@75
|
1312
|
c@75
|
1313 jo["method"] = "list";
|
c@127
|
1314 jo["result"] = fromListResponse(resp);
|
c@75
|
1315 addId(jo, id);
|
c@75
|
1316 return json11::Json(jo);
|
c@75
|
1317 }
|
c@75
|
1318
|
c@75
|
1319 static json11::Json
|
c@97
|
1320 fromRpcRequest_Load(const LoadRequest &req,
|
c@75
|
1321 const json11::Json &id) {
|
c@75
|
1322
|
c@75
|
1323 json11::Json::object jo;
|
c@75
|
1324 markRPC(jo);
|
c@75
|
1325
|
c@75
|
1326 jo["method"] = "load";
|
c@75
|
1327 jo["params"] = fromLoadRequest(req);
|
c@75
|
1328 addId(jo, id);
|
c@75
|
1329 return json11::Json(jo);
|
c@75
|
1330 }
|
c@75
|
1331
|
c@75
|
1332 static json11::Json
|
c@97
|
1333 fromRpcResponse_Load(const LoadResponse &resp,
|
c@75
|
1334 const PluginHandleMapper &pmapper,
|
c@75
|
1335 const json11::Json &id) {
|
c@75
|
1336
|
c@75
|
1337 if (resp.plugin) {
|
c@75
|
1338
|
c@75
|
1339 json11::Json::object jo;
|
c@75
|
1340 markRPC(jo);
|
c@75
|
1341
|
c@75
|
1342 jo["method"] = "load";
|
c@75
|
1343 jo["result"] = fromLoadResponse(resp, pmapper);
|
c@75
|
1344 addId(jo, id);
|
c@75
|
1345 return json11::Json(jo);
|
c@75
|
1346
|
c@75
|
1347 } else {
|
c@75
|
1348 return fromError("Failed to load plugin", RRType::Load, id);
|
c@75
|
1349 }
|
c@75
|
1350 }
|
c@75
|
1351
|
c@75
|
1352 static json11::Json
|
c@97
|
1353 fromRpcRequest_Configure(const ConfigurationRequest &req,
|
c@75
|
1354 const PluginHandleMapper &pmapper,
|
c@75
|
1355 const json11::Json &id) {
|
c@75
|
1356
|
c@75
|
1357 json11::Json::object jo;
|
c@75
|
1358 markRPC(jo);
|
c@75
|
1359
|
c@75
|
1360 jo["method"] = "configure";
|
c@75
|
1361 jo["params"] = fromConfigurationRequest(req, pmapper);
|
c@75
|
1362 addId(jo, id);
|
c@75
|
1363 return json11::Json(jo);
|
c@75
|
1364 }
|
c@75
|
1365
|
c@75
|
1366 static json11::Json
|
c@97
|
1367 fromRpcResponse_Configure(const ConfigurationResponse &resp,
|
c@75
|
1368 const PluginHandleMapper &pmapper,
|
c@75
|
1369 const json11::Json &id) {
|
c@75
|
1370
|
c@75
|
1371 if (!resp.outputs.empty()) {
|
c@75
|
1372
|
c@75
|
1373 json11::Json::object jo;
|
c@75
|
1374 markRPC(jo);
|
c@75
|
1375
|
c@75
|
1376 jo["method"] = "configure";
|
c@75
|
1377 jo["result"] = fromConfigurationResponse(resp, pmapper);
|
c@75
|
1378 addId(jo, id);
|
c@75
|
1379 return json11::Json(jo);
|
c@75
|
1380
|
c@75
|
1381 } else {
|
c@75
|
1382 return fromError("Failed to configure plugin", RRType::Configure, id);
|
c@75
|
1383 }
|
c@75
|
1384 }
|
c@75
|
1385
|
c@75
|
1386 static json11::Json
|
c@97
|
1387 fromRpcRequest_Process(const ProcessRequest &req,
|
c@75
|
1388 const PluginHandleMapper &pmapper,
|
c@75
|
1389 BufferSerialisation serialisation,
|
c@75
|
1390 const json11::Json &id) {
|
c@75
|
1391
|
c@75
|
1392 json11::Json::object jo;
|
c@75
|
1393 markRPC(jo);
|
c@75
|
1394
|
c@75
|
1395 jo["method"] = "process";
|
c@75
|
1396 jo["params"] = fromProcessRequest(req, pmapper, serialisation);
|
c@75
|
1397 addId(jo, id);
|
c@75
|
1398 return json11::Json(jo);
|
c@75
|
1399 }
|
c@75
|
1400
|
c@75
|
1401 static json11::Json
|
c@97
|
1402 fromRpcResponse_Process(const ProcessResponse &resp,
|
c@75
|
1403 const PluginHandleMapper &pmapper,
|
c@75
|
1404 BufferSerialisation serialisation,
|
c@75
|
1405 const json11::Json &id) {
|
c@75
|
1406
|
c@75
|
1407 json11::Json::object jo;
|
c@75
|
1408 markRPC(jo);
|
c@75
|
1409
|
c@75
|
1410 json11::Json::object po;
|
c@86
|
1411 po["handle"] = double(pmapper.pluginToHandle(resp.plugin));
|
c@75
|
1412 po["features"] = fromFeatureSet(resp.features,
|
c@75
|
1413 *pmapper.pluginToOutputIdMapper(resp.plugin),
|
c@75
|
1414 serialisation);
|
c@75
|
1415 jo["method"] = "process";
|
c@75
|
1416 jo["result"] = po;
|
c@75
|
1417 addId(jo, id);
|
c@75
|
1418 return json11::Json(jo);
|
c@75
|
1419 }
|
c@75
|
1420
|
c@75
|
1421 static json11::Json
|
c@97
|
1422 fromRpcRequest_Finish(const FinishRequest &req,
|
c@75
|
1423 const PluginHandleMapper &pmapper,
|
c@75
|
1424 const json11::Json &id) {
|
c@75
|
1425
|
c@75
|
1426 json11::Json::object jo;
|
c@75
|
1427 markRPC(jo);
|
c@75
|
1428
|
c@75
|
1429 json11::Json::object fo;
|
c@86
|
1430 fo["handle"] = double(pmapper.pluginToHandle(req.plugin));
|
c@75
|
1431
|
c@75
|
1432 jo["method"] = "finish";
|
c@75
|
1433 jo["params"] = fo;
|
c@75
|
1434 addId(jo, id);
|
c@75
|
1435 return json11::Json(jo);
|
c@75
|
1436 }
|
c@75
|
1437
|
c@75
|
1438 static json11::Json
|
c@97
|
1439 fromRpcResponse_Finish(const FinishResponse &resp,
|
c@75
|
1440 const PluginHandleMapper &pmapper,
|
c@75
|
1441 BufferSerialisation serialisation,
|
c@75
|
1442 const json11::Json &id) {
|
c@75
|
1443
|
c@75
|
1444 json11::Json::object jo;
|
c@75
|
1445 markRPC(jo);
|
c@75
|
1446
|
c@75
|
1447 json11::Json::object po;
|
c@86
|
1448 po["handle"] = double(pmapper.pluginToHandle(resp.plugin));
|
c@75
|
1449 po["features"] = fromFeatureSet(resp.features,
|
c@75
|
1450 *pmapper.pluginToOutputIdMapper(resp.plugin),
|
c@75
|
1451 serialisation);
|
c@75
|
1452 jo["method"] = "finish";
|
c@75
|
1453 jo["result"] = po;
|
c@75
|
1454 addId(jo, id);
|
c@75
|
1455 return json11::Json(jo);
|
c@75
|
1456 }
|
c@75
|
1457
|
c@75
|
1458 static json11::Json
|
c@75
|
1459 fromError(std::string errorText,
|
c@75
|
1460 RRType responseType,
|
dev@176
|
1461 const json11::Json &id,
|
dev@176
|
1462 bool writeVerbatimError = false) {
|
c@75
|
1463
|
c@75
|
1464 json11::Json::object jo;
|
c@75
|
1465 markRPC(jo);
|
c@75
|
1466
|
c@75
|
1467 std::string type;
|
c@75
|
1468
|
c@75
|
1469 if (responseType == RRType::List) type = "list";
|
c@75
|
1470 else if (responseType == RRType::Load) type = "load";
|
c@75
|
1471 else if (responseType == RRType::Configure) type = "configure";
|
c@75
|
1472 else if (responseType == RRType::Process) type = "process";
|
c@75
|
1473 else if (responseType == RRType::Finish) type = "finish";
|
c@75
|
1474 else type = "invalid";
|
c@75
|
1475
|
c@75
|
1476 json11::Json::object eo;
|
c@75
|
1477 eo["code"] = 0;
|
cannam@158
|
1478
|
dev@176
|
1479 if (responseType == RRType::NotValid || writeVerbatimError) {
|
cannam@158
|
1480 eo["message"] = errorText;
|
cannam@158
|
1481 } else {
|
cannam@158
|
1482 eo["message"] =
|
cannam@158
|
1483 std::string("error in ") + type + " request: " + errorText;
|
cannam@158
|
1484 }
|
c@75
|
1485
|
c@75
|
1486 jo["method"] = type;
|
c@75
|
1487 jo["error"] = eo;
|
c@75
|
1488 addId(jo, id);
|
c@75
|
1489 return json11::Json(jo);
|
c@75
|
1490 }
|
c@75
|
1491
|
c@75
|
1492 static RRType
|
c@75
|
1493 getRequestResponseType(json11::Json j, std::string &err) {
|
c@75
|
1494
|
c@75
|
1495 if (!j["method"].is_string()) {
|
c@75
|
1496 err = "string expected for method";
|
c@75
|
1497 return RRType::NotValid;
|
c@75
|
1498 }
|
c@75
|
1499
|
c@75
|
1500 std::string type = j["method"].string_value();
|
c@75
|
1501
|
c@75
|
1502 if (type == "list") return RRType::List;
|
c@75
|
1503 else if (type == "load") return RRType::Load;
|
c@75
|
1504 else if (type == "configure") return RRType::Configure;
|
c@75
|
1505 else if (type == "process") return RRType::Process;
|
c@75
|
1506 else if (type == "finish") return RRType::Finish;
|
c@75
|
1507 else if (type == "invalid") return RRType::NotValid;
|
c@75
|
1508 else {
|
c@75
|
1509 err = "unknown or unexpected request/response type \"" + type + "\"";
|
c@75
|
1510 return RRType::NotValid;
|
c@75
|
1511 }
|
c@75
|
1512 }
|
c@75
|
1513
|
c@127
|
1514 static ListRequest
|
c@75
|
1515 toRpcRequest_List(json11::Json j, std::string &err) {
|
c@127
|
1516
|
c@128
|
1517 checkRpcRequestType(j, "list", err);
|
c@127
|
1518 if (failed(err)) return {};
|
c@127
|
1519 return toListRequest(j["params"], err);
|
c@75
|
1520 }
|
c@75
|
1521
|
c@97
|
1522 static ListResponse
|
c@75
|
1523 toRpcResponse_List(json11::Json j, std::string &err) {
|
c@75
|
1524
|
c@97
|
1525 ListResponse resp;
|
c@75
|
1526 if (successful(j, err) && !failed(err)) {
|
c@127
|
1527 resp = toListResponse(j["result"], err);
|
c@75
|
1528 }
|
c@75
|
1529 return resp;
|
c@75
|
1530 }
|
c@75
|
1531
|
c@97
|
1532 static LoadRequest
|
c@75
|
1533 toRpcRequest_Load(json11::Json j, std::string &err) {
|
c@75
|
1534
|
c@128
|
1535 checkRpcRequestType(j, "load", err);
|
c@75
|
1536 if (failed(err)) return {};
|
c@75
|
1537 return toLoadRequest(j["params"], err);
|
c@75
|
1538 }
|
c@75
|
1539
|
c@97
|
1540 static LoadResponse
|
c@75
|
1541 toRpcResponse_Load(json11::Json j,
|
c@75
|
1542 const PluginHandleMapper &pmapper,
|
c@75
|
1543 std::string &err) {
|
c@75
|
1544
|
c@97
|
1545 LoadResponse resp;
|
c@75
|
1546 if (successful(j, err) && !failed(err)) {
|
c@75
|
1547 resp = toLoadResponse(j["result"], pmapper, err);
|
c@75
|
1548 }
|
c@75
|
1549 return resp;
|
c@75
|
1550 }
|
c@75
|
1551
|
c@97
|
1552 static ConfigurationRequest
|
c@75
|
1553 toRpcRequest_Configure(json11::Json j,
|
c@75
|
1554 const PluginHandleMapper &pmapper,
|
c@75
|
1555 std::string &err) {
|
c@75
|
1556
|
c@128
|
1557 checkRpcRequestType(j, "configure", err);
|
c@75
|
1558 if (failed(err)) return {};
|
c@75
|
1559 return toConfigurationRequest(j["params"], pmapper, err);
|
c@75
|
1560 }
|
c@75
|
1561
|
c@97
|
1562 static ConfigurationResponse
|
c@75
|
1563 toRpcResponse_Configure(json11::Json j,
|
c@75
|
1564 const PluginHandleMapper &pmapper,
|
c@75
|
1565 std::string &err) {
|
c@75
|
1566
|
c@97
|
1567 ConfigurationResponse resp;
|
c@75
|
1568 if (successful(j, err) && !failed(err)) {
|
c@75
|
1569 resp = toConfigurationResponse(j["result"], pmapper, err);
|
c@75
|
1570 }
|
c@75
|
1571 return resp;
|
c@75
|
1572 }
|
c@75
|
1573
|
c@97
|
1574 static ProcessRequest
|
c@75
|
1575 toRpcRequest_Process(json11::Json j, const PluginHandleMapper &pmapper,
|
c@75
|
1576 BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
1577
|
c@128
|
1578 checkRpcRequestType(j, "process", err);
|
c@75
|
1579 if (failed(err)) return {};
|
c@75
|
1580 return toProcessRequest(j["params"], pmapper, serialisation, err);
|
c@75
|
1581 }
|
c@75
|
1582
|
c@97
|
1583 static ProcessResponse
|
c@75
|
1584 toRpcResponse_Process(json11::Json j,
|
c@75
|
1585 const PluginHandleMapper &pmapper,
|
c@75
|
1586 BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
1587
|
c@97
|
1588 ProcessResponse resp;
|
c@75
|
1589 if (successful(j, err) && !failed(err)) {
|
c@75
|
1590 auto jc = j["result"];
|
c@75
|
1591 auto h = jc["handle"].int_value();
|
c@75
|
1592 resp.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1593 resp.features = toFeatureSet(jc["features"],
|
c@75
|
1594 *pmapper.handleToOutputIdMapper(h),
|
c@75
|
1595 serialisation, err);
|
c@75
|
1596 }
|
c@75
|
1597 return resp;
|
c@75
|
1598 }
|
c@75
|
1599
|
c@97
|
1600 static FinishRequest
|
c@75
|
1601 toRpcRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper,
|
c@75
|
1602 std::string &err) {
|
c@75
|
1603
|
c@128
|
1604 checkRpcRequestType(j, "finish", err);
|
c@75
|
1605 if (failed(err)) return {};
|
c@97
|
1606 FinishRequest req;
|
cannam@275
|
1607 auto h = j["params"]["handle"].int_value();
|
cannam@275
|
1608 req.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1609 return req;
|
c@75
|
1610 }
|
c@75
|
1611
|
c@97
|
1612 static FinishResponse
|
c@75
|
1613 toRpcResponse_Finish(json11::Json j,
|
c@97
|
1614 const PluginHandleMapper &pmapper,
|
c@97
|
1615 BufferSerialisation &serialisation, std::string &err) {
|
c@75
|
1616
|
c@97
|
1617 FinishResponse resp;
|
c@75
|
1618 if (successful(j, err) && !failed(err)) {
|
c@75
|
1619 auto jc = j["result"];
|
c@75
|
1620 auto h = jc["handle"].int_value();
|
c@75
|
1621 resp.plugin = pmapper.handleToPlugin(h);
|
c@75
|
1622 resp.features = toFeatureSet(jc["features"],
|
c@75
|
1623 *pmapper.handleToOutputIdMapper(h),
|
c@75
|
1624 serialisation, err);
|
c@75
|
1625 }
|
c@75
|
1626 return resp;
|
c@75
|
1627 }
|
c@75
|
1628 };
|
c@75
|
1629
|
c@75
|
1630 }
|
c@75
|
1631
|
c@75
|
1632 #endif
|