annotate vamp-json/VampJson.h @ 116:d15cb1151d76

Add JSON support directly to the server. Had hoped to avoid this (using Capnp as canonical in the server and then converting externally as necessary) but it's just too useful for debugging purposes when bundled with client app
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 27 Oct 2016 11:39:41 +0100
parents 491a4bc10a01
children 2380d5865355
rev   line source
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.
c@75 7 Copyright 2015-2016 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@75 41
c@75 42 #include <json11/json11.hpp>
c@75 43 #include <base-n/include/basen.hpp>
c@75 44
c@75 45 #include <vamp-hostsdk/Plugin.h>
c@75 46 #include <vamp-hostsdk/PluginLoader.h>
c@97 47
c@97 48 #include "vamp-support/PluginStaticData.h"
c@97 49 #include "vamp-support/PluginConfiguration.h"
c@97 50 #include "vamp-support/RequestResponse.h"
c@75 51
c@75 52 #include "vamp-support/PluginHandleMapper.h"
c@75 53 #include "vamp-support/PluginOutputIdMapper.h"
c@75 54 #include "vamp-support/RequestResponseType.h"
c@75 55
c@97 56 namespace piper_vamp {
c@75 57
c@75 58 /**
c@75 59 * Convert the structures laid out in the Vamp SDK classes into JSON
c@75 60 * (and back again) following the schema in the vamp-json-schema
c@75 61 * project repo.
c@75 62 *
c@75 63 * Functions with names starting "from" convert from a Vamp SDK object
c@75 64 * to JSON output. Most of them return a json11::Json object, with a
c@75 65 * few exceptions for low-level utilities that return a string. These
c@75 66 * functions succeed all of the time.
c@75 67 *
c@75 68 * Functions with names starting "to" convert to a Vamp SDK object
c@75 69 * from JSON input. These functions all accept a json11::Json object
c@75 70 * as first argument, with a few exceptions for low-level utilities
c@75 71 * that accept a string. These functions all accept a string reference
c@75 72 * as a final argument and return an error string through it if the
c@75 73 * conversion fails. If conversion fails the return value is
c@75 74 * undefined, and any returned object may be incomplete or
c@75 75 * invalid. Callers should check for an empty error string (indicating
c@75 76 * success) before using the returned value.
c@75 77 */
c@75 78
c@75 79 class VampJson
c@75 80 {
c@75 81 public:
c@75 82 /** Serialisation format for arrays of floats (process input and
c@75 83 * feature values). Wherever such an array appears, it may
c@75 84 * alternatively be replaced by a single string containing a
c@75 85 * base-64 encoding of the IEEE float buffer. When parsing, if a
c@75 86 * string is found instead of an array in this case, it will be
c@75 87 * interpreted as a base-64 encoded buffer. Only array or base-64
c@75 88 * encoding may be provided, not both.
c@75 89 */
c@75 90 enum class BufferSerialisation {
c@75 91
c@75 92 /** Default JSON serialisation of values in array form. This
c@75 93 * is relatively slow to parse and serialise, and can take a
c@75 94 * lot of space.
c@75 95 */
c@75 96 Array,
c@75 97
c@75 98 /** Base64-encoded string of the raw data as packed
c@75 99 * little-endian IEEE 32-bit floats. Faster and more compact
c@75 100 * than the text encoding but more complicated to
c@75 101 * provide. Note that Base64 serialisations produced by this
c@75 102 * library do not including padding characters and so are not
c@75 103 * necessarily multiples of 4 characters long. You will need
c@75 104 * to pad them yourself if concatenating them or supplying to
c@75 105 * a consumer that expects padding.
c@75 106 */
c@75 107 Base64
c@75 108 };
c@75 109
c@75 110 static bool failed(const std::string &err) {
c@75 111 return err != "";
c@75 112 }
c@75 113
c@75 114 template <typename T>
c@75 115 static json11::Json
c@75 116 fromBasicDescriptor(const T &t) {
c@75 117 return json11::Json::object {
c@75 118 { "identifier", t.identifier },
c@75 119 { "name", t.name },
c@75 120 { "description", t.description }
c@75 121 };
c@75 122 }
c@75 123
c@75 124 template <typename T>
c@75 125 static void
c@75 126 toBasicDescriptor(json11::Json j, T &t, std::string &err) {
c@75 127 if (!j.is_object()) {
c@75 128 err = "object expected for basic descriptor content";
c@75 129 return;
c@75 130 }
c@75 131 if (!j["identifier"].is_string()) {
c@75 132 err = "string expected for identifier";
c@75 133 return;
c@75 134 }
c@75 135 t.identifier = j["identifier"].string_value();
c@75 136 t.name = j["name"].string_value();
c@75 137 t.description = j["description"].string_value();
c@75 138 }
c@75 139
c@75 140 template <typename T>
c@75 141 static json11::Json
c@75 142 fromValueExtents(const T &t) {
c@75 143 return json11::Json::object {
c@75 144 { "min", t.minValue },
c@75 145 { "max", t.maxValue }
c@75 146 };
c@75 147 }
c@75 148
c@75 149 template <typename T>
c@75 150 static bool
c@75 151 toValueExtents(json11::Json j, T &t, std::string &err) {
c@75 152 if (j["extents"].is_null()) {
c@75 153 return false;
c@75 154 } else if (j["extents"].is_object()) {
c@75 155 if (j["extents"]["min"].is_number() &&
c@75 156 j["extents"]["max"].is_number()) {
c@75 157 t.minValue = j["extents"]["min"].number_value();
c@75 158 t.maxValue = j["extents"]["max"].number_value();
c@75 159 return true;
c@75 160 } else {
c@75 161 err = "numbers expected for min and max";
c@75 162 return false;
c@75 163 }
c@75 164 } else {
c@75 165 err = "object expected for extents (if present)";
c@75 166 return false;
c@75 167 }
c@75 168 }
c@75 169
c@75 170 static json11::Json
c@75 171 fromRealTime(const Vamp::RealTime &r) {
c@75 172 return json11::Json::object {
c@75 173 { "s", r.sec },
c@75 174 { "n", r.nsec }
c@75 175 };
c@75 176 }
c@75 177
c@75 178 static Vamp::RealTime
c@75 179 toRealTime(json11::Json j, std::string &err) {
c@75 180 json11::Json sec = j["s"];
c@75 181 json11::Json nsec = j["n"];
c@75 182 if (!sec.is_number() || !nsec.is_number()) {
c@75 183 err = "invalid Vamp::RealTime object " + j.dump();
c@75 184 return {};
c@75 185 }
c@75 186 return Vamp::RealTime(sec.int_value(), nsec.int_value());
c@75 187 }
c@75 188
c@75 189 static std::string
c@75 190 fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType type) {
c@75 191 switch (type) {
c@75 192 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep:
c@75 193 return "OneSamplePerStep";
c@75 194 case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
c@75 195 return "FixedSampleRate";
c@75 196 case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
c@75 197 return "VariableSampleRate";
c@75 198 }
c@75 199 return "";
c@75 200 }
c@75 201
c@75 202 static Vamp::Plugin::OutputDescriptor::SampleType
c@75 203 toSampleType(std::string text, std::string &err) {
c@75 204 if (text == "OneSamplePerStep") {
c@75 205 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
c@75 206 } else if (text == "FixedSampleRate") {
c@75 207 return Vamp::Plugin::OutputDescriptor::FixedSampleRate;
c@75 208 } else if (text == "VariableSampleRate") {
c@75 209 return Vamp::Plugin::OutputDescriptor::VariableSampleRate;
c@75 210 } else {
c@75 211 err = "invalid sample type string: " + text;
c@75 212 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
c@75 213 }
c@75 214 }
c@75 215
c@75 216 static json11::Json
c@75 217 fromConfiguredOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) {
c@75 218 json11::Json::object jo {
c@75 219 { "unit", desc.unit },
c@75 220 { "sampleType", fromSampleType(desc.sampleType) },
c@75 221 { "sampleRate", desc.sampleRate },
c@75 222 { "hasDuration", desc.hasDuration }
c@75 223 };
c@75 224 if (desc.hasFixedBinCount) {
c@75 225 jo["binCount"] = int(desc.binCount);
c@75 226 jo["binNames"] = json11::Json::array
c@75 227 (desc.binNames.begin(), desc.binNames.end());
c@75 228 }
c@75 229 if (desc.hasKnownExtents) {
c@75 230 jo["extents"] = fromValueExtents(desc);
c@75 231 }
c@75 232 if (desc.isQuantized) {
c@75 233 jo["quantizeStep"] = desc.quantizeStep;
c@75 234 }
c@75 235 return json11::Json(jo);
c@75 236 }
c@75 237
c@75 238 static json11::Json
c@75 239 fromOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) {
c@75 240 json11::Json::object jo {
c@75 241 { "basic", fromBasicDescriptor(desc) },
c@75 242 { "configured", fromConfiguredOutputDescriptor(desc) }
c@75 243 };
c@75 244 return json11::Json(jo);
c@75 245 }
c@75 246
c@75 247 static Vamp::Plugin::OutputDescriptor
c@75 248 toConfiguredOutputDescriptor(json11::Json j, std::string &err) {
c@75 249
c@75 250 Vamp::Plugin::OutputDescriptor od;
c@75 251 if (!j.is_object()) {
c@75 252 err = "object expected for output descriptor";
c@75 253 return {};
c@75 254 }
c@75 255
c@75 256 od.unit = j["unit"].string_value();
c@75 257
c@75 258 od.sampleType = toSampleType(j["sampleType"].string_value(), err);
c@75 259 if (failed(err)) return {};
c@75 260
c@75 261 if (!j["sampleRate"].is_number()) {
c@75 262 err = "number expected for sample rate";
c@75 263 return {};
c@75 264 }
c@75 265 od.sampleRate = j["sampleRate"].number_value();
c@75 266 od.hasDuration = j["hasDuration"].bool_value();
c@75 267
c@75 268 if (j["binCount"].is_number() && j["binCount"].int_value() > 0) {
c@75 269 od.hasFixedBinCount = true;
c@75 270 od.binCount = j["binCount"].int_value();
c@75 271 for (auto &n: j["binNames"].array_items()) {
c@75 272 if (!n.is_string()) {
c@75 273 err = "string expected for bin name";
c@75 274 return {};
c@75 275 }
c@75 276 od.binNames.push_back(n.string_value());
c@75 277 }
c@75 278 } else {
c@75 279 od.hasFixedBinCount = false;
c@75 280 }
c@75 281
c@75 282 bool extentsPresent = toValueExtents(j, od, err);
c@75 283 if (failed(err)) return {};
c@75 284
c@75 285 od.hasKnownExtents = extentsPresent;
c@75 286
c@75 287 if (j["quantizeStep"].is_number()) {
c@75 288 od.isQuantized = true;
c@75 289 od.quantizeStep = j["quantizeStep"].number_value();
c@75 290 } else {
c@75 291 od.isQuantized = false;
c@75 292 }
c@75 293
c@75 294 return od;
c@75 295 }
c@75 296
c@75 297 static Vamp::Plugin::OutputDescriptor
c@75 298 toOutputDescriptor(json11::Json j, std::string &err) {
c@75 299
c@75 300 Vamp::Plugin::OutputDescriptor od;
c@75 301 if (!j.is_object()) {
c@75 302 err = "object expected for output descriptor";
c@75 303 return {};
c@75 304 }
c@75 305
c@75 306 od = toConfiguredOutputDescriptor(j, err);
c@75 307 if (failed(err)) return {};
c@75 308
c@75 309 toBasicDescriptor(j["basic"], od, err);
c@75 310 if (failed(err)) return {};
c@75 311
c@75 312 return od;
c@75 313 }
c@75 314
c@75 315 static json11::Json
c@75 316 fromParameterDescriptor(const Vamp::PluginBase::ParameterDescriptor &desc) {
c@75 317
c@75 318 json11::Json::object jo {
c@75 319 { "basic", fromBasicDescriptor(desc) },
c@75 320 { "unit", desc.unit },
c@75 321 { "extents", fromValueExtents(desc) },
c@75 322 { "defaultValue", desc.defaultValue },
c@75 323 { "valueNames", json11::Json::array
c@75 324 (desc.valueNames.begin(), desc.valueNames.end()) }
c@75 325 };
c@75 326 if (desc.isQuantized) {
c@75 327 jo["quantizeStep"] = desc.quantizeStep;
c@75 328 }
c@75 329 return json11::Json(jo);
c@75 330 }
c@75 331
c@75 332 static Vamp::PluginBase::ParameterDescriptor
c@75 333 toParameterDescriptor(json11::Json j, std::string &err) {
c@75 334
c@75 335 Vamp::PluginBase::ParameterDescriptor pd;
c@75 336 if (!j.is_object()) {
c@75 337 err = "object expected for parameter descriptor";
c@75 338 return {};
c@75 339 }
c@75 340
c@75 341 toBasicDescriptor(j["basic"], pd, err);
c@75 342 if (failed(err)) return {};
c@75 343
c@75 344 pd.unit = j["unit"].string_value();
c@75 345
c@75 346 bool extentsPresent = toValueExtents(j, pd, err);
c@75 347 if (failed(err)) return {};
c@75 348 if (!extentsPresent) {
c@75 349 err = "extents must be present in parameter descriptor";
c@75 350 return {};
c@75 351 }
c@75 352
c@75 353 if (!j["defaultValue"].is_number()) {
c@75 354 err = "number expected for default value";
c@75 355 return {};
c@75 356 }
c@75 357
c@75 358 pd.defaultValue = j["defaultValue"].number_value();
c@75 359
c@75 360 pd.valueNames.clear();
c@75 361 for (auto &n: j["valueNames"].array_items()) {
c@75 362 if (!n.is_string()) {
c@75 363 err = "string expected for value name";
c@75 364 return {};
c@75 365 }
c@75 366 pd.valueNames.push_back(n.string_value());
c@75 367 }
c@75 368
c@75 369 if (j["quantizeStep"].is_number()) {
c@75 370 pd.isQuantized = true;
c@75 371 pd.quantizeStep = j["quantizeStep"].number_value();
c@75 372 } else {
c@75 373 pd.isQuantized = false;
c@75 374 }
c@75 375
c@75 376 return pd;
c@75 377 }
c@75 378
c@75 379 static std::string
c@75 380 fromFloatBuffer(const float *buffer, size_t nfloats) {
c@75 381 // must use char pointers, otherwise the converter will only
c@75 382 // encode every 4th byte (as it will count up in float* steps)
c@75 383 const char *start = reinterpret_cast<const char *>(buffer);
c@75 384 const char *end = reinterpret_cast<const char *>(buffer + nfloats);
c@75 385 std::string encoded;
c@75 386 bn::encode_b64(start, end, back_inserter(encoded));
c@75 387 return encoded;
c@75 388 }
c@75 389
c@75 390 static std::vector<float>
c@75 391 toFloatBuffer(std::string encoded, std::string & /* err */) {
c@75 392 std::string decoded;
c@75 393 bn::decode_b64(encoded.begin(), encoded.end(), back_inserter(decoded));
c@75 394 const float *buffer = reinterpret_cast<const float *>(decoded.c_str());
c@75 395 size_t n = decoded.size() / sizeof(float);
c@75 396 return std::vector<float>(buffer, buffer + n);
c@75 397 }
c@75 398
c@75 399 static json11::Json
c@75 400 fromFeature(const Vamp::Plugin::Feature &f,
c@75 401 BufferSerialisation serialisation) {
c@75 402
c@75 403 json11::Json::object jo;
c@75 404 if (f.values.size() > 0) {
c@75 405 if (serialisation == BufferSerialisation::Array) {
c@75 406 jo["featureValues"] = json11::Json::array(f.values.begin(),
c@75 407 f.values.end());
c@75 408 } else {
c@75 409 jo["featureValues"] = fromFloatBuffer(f.values.data(),
c@75 410 f.values.size());
c@75 411 }
c@75 412 }
c@75 413 if (f.label != "") {
c@75 414 jo["label"] = f.label;
c@75 415 }
c@75 416 if (f.hasTimestamp) {
c@75 417 jo["timestamp"] = fromRealTime(f.timestamp);
c@75 418 }
c@75 419 if (f.hasDuration) {
c@75 420 jo["duration"] = fromRealTime(f.duration);
c@75 421 }
c@75 422 return json11::Json(jo);
c@75 423 }
c@75 424
c@75 425 static Vamp::Plugin::Feature
c@75 426 toFeature(json11::Json j, BufferSerialisation &serialisation, std::string &err) {
c@75 427
c@75 428 Vamp::Plugin::Feature f;
c@75 429 if (!j.is_object()) {
c@75 430 err = "object expected for feature";
c@75 431 return {};
c@75 432 }
c@75 433 if (j["timestamp"].is_object()) {
c@75 434 f.timestamp = toRealTime(j["timestamp"], err);
c@75 435 if (failed(err)) return {};
c@75 436 f.hasTimestamp = true;
c@75 437 }
c@75 438 if (j["duration"].is_object()) {
c@75 439 f.duration = toRealTime(j["duration"], err);
c@75 440 if (failed(err)) return {};
c@75 441 f.hasDuration = true;
c@75 442 }
c@75 443 if (j["featureValues"].is_string()) {
c@75 444 f.values = toFloatBuffer(j["featureValues"].string_value(), err);
c@75 445 if (failed(err)) return {};
c@75 446 serialisation = BufferSerialisation::Base64;
c@75 447 } else if (j["featureValues"].is_array()) {
c@75 448 for (auto v : j["featureValues"].array_items()) {
c@75 449 f.values.push_back(v.number_value());
c@75 450 }
c@75 451 serialisation = BufferSerialisation::Array;
c@75 452 }
c@75 453 f.label = j["label"].string_value();
c@75 454 return f;
c@75 455 }
c@75 456
c@75 457 static json11::Json
c@75 458 fromFeatureSet(const Vamp::Plugin::FeatureSet &fs,
c@75 459 const PluginOutputIdMapper &omapper,
c@75 460 BufferSerialisation serialisation) {
c@75 461
c@75 462 json11::Json::object jo;
c@75 463 for (const auto &fsi : fs) {
c@75 464 std::vector<json11::Json> fj;
c@75 465 for (const Vamp::Plugin::Feature &f: fsi.second) {
c@75 466 fj.push_back(fromFeature(f, serialisation));
c@75 467 }
c@75 468 jo[omapper.indexToId(fsi.first)] = fj;
c@75 469 }
c@75 470 return json11::Json(jo);
c@75 471 }
c@75 472
c@75 473 static Vamp::Plugin::FeatureList
c@75 474 toFeatureList(json11::Json j,
c@75 475 BufferSerialisation &serialisation, std::string &err) {
c@75 476
c@75 477 Vamp::Plugin::FeatureList fl;
c@75 478 if (!j.is_array()) {
c@75 479 err = "array expected for feature list";
c@75 480 return {};
c@75 481 }
c@75 482 for (const json11::Json &fj : j.array_items()) {
c@75 483 fl.push_back(toFeature(fj, serialisation, err));
c@75 484 if (failed(err)) return {};
c@75 485 }
c@75 486 return fl;
c@75 487 }
c@75 488
c@75 489 static Vamp::Plugin::FeatureSet
c@75 490 toFeatureSet(json11::Json j,
c@75 491 const PluginOutputIdMapper &omapper,
c@75 492 BufferSerialisation &serialisation,
c@75 493 std::string &err) {
c@75 494
c@75 495 Vamp::Plugin::FeatureSet fs;
c@75 496 if (!j.is_object()) {
c@75 497 err = "object expected for feature set";
c@75 498 return {};
c@75 499 }
c@75 500 for (auto &entry : j.object_items()) {
c@75 501 int n = omapper.idToIndex(entry.first);
c@75 502 if (fs.find(n) != fs.end()) {
c@75 503 err = "duplicate numerical index for output";
c@75 504 return {};
c@75 505 }
c@75 506 fs[n] = toFeatureList(entry.second, serialisation, err);
c@75 507 if (failed(err)) return {};
c@75 508 }
c@75 509 return fs;
c@75 510 }
c@75 511
c@75 512 static std::string
c@75 513 fromInputDomain(Vamp::Plugin::InputDomain domain) {
c@75 514
c@75 515 switch (domain) {
c@75 516 case Vamp::Plugin::TimeDomain:
c@75 517 return "TimeDomain";
c@75 518 case Vamp::Plugin::FrequencyDomain:
c@75 519 return "FrequencyDomain";
c@75 520 }
c@75 521 return "";
c@75 522 }
c@75 523
c@75 524 static Vamp::Plugin::InputDomain
c@75 525 toInputDomain(std::string text, std::string &err) {
c@75 526
c@75 527 if (text == "TimeDomain") {
c@75 528 return Vamp::Plugin::TimeDomain;
c@75 529 } else if (text == "FrequencyDomain") {
c@75 530 return Vamp::Plugin::FrequencyDomain;
c@75 531 } else {
c@75 532 err = "invalid input domain string: " + text;
c@75 533 return {};
c@75 534 }
c@75 535 }
c@75 536
c@75 537 static json11::Json
c@97 538 fromPluginStaticData(const PluginStaticData &d) {
c@75 539
c@75 540 json11::Json::object jo;
c@75 541 jo["key"] = d.pluginKey;
c@75 542 jo["basic"] = fromBasicDescriptor(d.basic);
c@75 543 jo["maker"] = d.maker;
c@75 544 jo["copyright"] = d.copyright;
c@75 545 jo["version"] = d.pluginVersion;
c@75 546
c@75 547 json11::Json::array cat;
c@75 548 for (const std::string &c: d.category) cat.push_back(c);
c@75 549 jo["category"] = cat;
c@75 550
c@105 551 jo["minChannelCount"] = int(d.minChannelCount);
c@105 552 jo["maxChannelCount"] = int(d.maxChannelCount);
c@75 553
c@75 554 json11::Json::array params;
c@75 555 Vamp::PluginBase::ParameterList vparams = d.parameters;
c@75 556 for (auto &p: vparams) params.push_back(fromParameterDescriptor(p));
c@75 557 jo["parameters"] = params;
c@75 558
c@75 559 json11::Json::array progs;
c@75 560 Vamp::PluginBase::ProgramList vprogs = d.programs;
c@75 561 for (auto &p: vprogs) progs.push_back(p);
c@75 562 jo["programs"] = progs;
c@75 563
c@75 564 jo["inputDomain"] = fromInputDomain(d.inputDomain);
c@75 565
c@75 566 json11::Json::array outinfo;
c@75 567 auto vouts = d.basicOutputInfo;
c@75 568 for (auto &o: vouts) outinfo.push_back(fromBasicDescriptor(o));
c@75 569 jo["basicOutputInfo"] = outinfo;
c@75 570
c@75 571 return json11::Json(jo);
c@75 572 }
c@75 573
c@97 574 static PluginStaticData
c@75 575 toPluginStaticData(json11::Json j, std::string &err) {
c@75 576
c@75 577 if (!j.has_shape({
c@75 578 { "key", json11::Json::STRING },
c@75 579 { "version", json11::Json::NUMBER },
c@75 580 { "minChannelCount", json11::Json::NUMBER },
c@75 581 { "maxChannelCount", json11::Json::NUMBER },
c@75 582 { "inputDomain", json11::Json::STRING }}, err)) {
c@75 583
c@75 584 err = "malformed plugin static data: " + err;
c@75 585
c@75 586 } else if (!j["basicOutputInfo"].is_array()) {
c@75 587
c@75 588 err = "array expected for basic output info";
c@75 589
c@75 590 } else if (!j["maker"].is_null() &&
c@75 591 !j["maker"].is_string()) {
c@75 592
c@75 593 err = "string expected for maker";
c@75 594
c@75 595 } else if (!j["copyright"].is_null() &&
c@75 596 !j["copyright"].is_string()) {
c@75 597 err = "string expected for copyright";
c@75 598
c@75 599 } else if (!j["category"].is_null() &&
c@75 600 !j["category"].is_array()) {
c@75 601
c@75 602 err = "array expected for category";
c@75 603
c@75 604 } else if (!j["parameters"].is_null() &&
c@75 605 !j["parameters"].is_array()) {
c@75 606
c@75 607 err = "array expected for parameters";
c@75 608
c@75 609 } else if (!j["programs"].is_null() &&
c@75 610 !j["programs"].is_array()) {
c@75 611
c@75 612 err = "array expected for programs";
c@75 613
c@75 614 } else if (!j["inputDomain"].is_null() &&
c@75 615 !j["inputDomain"].is_string()) {
c@75 616
c@75 617 err = "string expected for inputDomain";
c@75 618
c@75 619 } else if (!j["basicOutputInfo"].is_null() &&
c@75 620 !j["basicOutputInfo"].is_array()) {
c@75 621
c@75 622 err = "array expected for basicOutputInfo";
c@75 623
c@75 624 } else {
c@75 625
c@97 626 PluginStaticData psd;
c@75 627
c@75 628 psd.pluginKey = j["key"].string_value();
c@75 629
c@75 630 toBasicDescriptor(j["basic"], psd.basic, err);
c@75 631 if (failed(err)) return {};
c@75 632
c@75 633 psd.maker = j["maker"].string_value();
c@75 634 psd.copyright = j["copyright"].string_value();
c@75 635 psd.pluginVersion = j["version"].int_value();
c@75 636
c@75 637 for (const auto &c : j["category"].array_items()) {
c@75 638 if (!c.is_string()) {
c@75 639 err = "strings expected in category array";
c@75 640 return {};
c@75 641 }
c@75 642 psd.category.push_back(c.string_value());
c@75 643 }
c@75 644
c@75 645 psd.minChannelCount = j["minChannelCount"].int_value();
c@75 646 psd.maxChannelCount = j["maxChannelCount"].int_value();
c@75 647
c@75 648 for (const auto &p : j["parameters"].array_items()) {
c@75 649 auto pd = toParameterDescriptor(p, err);
c@75 650 if (failed(err)) return {};
c@75 651 psd.parameters.push_back(pd);
c@75 652 }
c@75 653
c@75 654 for (const auto &p : j["programs"].array_items()) {
c@75 655 if (!p.is_string()) {
c@75 656 err = "strings expected in programs array";
c@75 657 return {};
c@75 658 }
c@75 659 psd.programs.push_back(p.string_value());
c@75 660 }
c@75 661
c@75 662 psd.inputDomain = toInputDomain(j["inputDomain"].string_value(), err);
c@75 663 if (failed(err)) return {};
c@75 664
c@75 665 for (const auto &bo : j["basicOutputInfo"].array_items()) {
c@97 666 PluginStaticData::Basic b;
c@75 667 toBasicDescriptor(bo, b, err);
c@75 668 if (failed(err)) return {};
c@75 669 psd.basicOutputInfo.push_back(b);
c@75 670 }
c@75 671
c@75 672 return psd;
c@75 673 }
c@75 674
c@75 675 // fallthrough error case
c@75 676 return {};
c@75 677 }
c@75 678
c@75 679 static json11::Json
c@97 680 fromPluginConfiguration(const PluginConfiguration &c) {
c@75 681
c@75 682 json11::Json::object jo;
c@75 683
c@75 684 json11::Json::object paramValues;
c@75 685 for (auto &vp: c.parameterValues) {
c@75 686 paramValues[vp.first] = vp.second;
c@75 687 }
c@75 688 jo["parameterValues"] = paramValues;
c@75 689
c@75 690 if (c.currentProgram != "") {
c@75 691 jo["currentProgram"] = c.currentProgram;
c@75 692 }
c@75 693
c@75 694 jo["channelCount"] = c.channelCount;
c@75 695 jo["stepSize"] = c.stepSize;
c@75 696 jo["blockSize"] = c.blockSize;
c@75 697
c@75 698 return json11::Json(jo);
c@75 699 }
c@75 700
c@97 701 static PluginConfiguration
c@75 702 toPluginConfiguration(json11::Json j, std::string &err) {
c@75 703
c@75 704 if (!j.has_shape({
c@75 705 { "channelCount", json11::Json::NUMBER },
c@75 706 { "stepSize", json11::Json::NUMBER },
c@75 707 { "blockSize", json11::Json::NUMBER } }, err)) {
c@75 708 err = "malformed plugin configuration: " + err;
c@75 709 return {};
c@75 710 }
c@75 711
c@75 712 if (!j["parameterValues"].is_null() &&
c@75 713 !j["parameterValues"].is_object()) {
c@75 714 err = "object expected for parameter values";
c@75 715 return {};
c@75 716 }
c@75 717
c@75 718 for (auto &pv : j["parameterValues"].object_items()) {
c@75 719 if (!pv.second.is_number()) {
c@75 720 err = "number expected for parameter value";
c@75 721 return {};
c@75 722 }
c@75 723 }
c@75 724
c@75 725 if (!j["currentProgram"].is_null() &&
c@75 726 !j["currentProgram"].is_string()) {
c@75 727 err = "string expected for program name";
c@75 728 return {};
c@75 729 }
c@75 730
c@97 731 PluginConfiguration config;
c@75 732
c@75 733 config.channelCount = j["channelCount"].number_value();
c@75 734 config.stepSize = j["stepSize"].number_value();
c@75 735 config.blockSize = j["blockSize"].number_value();
c@75 736
c@75 737 for (auto &pv : j["parameterValues"].object_items()) {
c@75 738 config.parameterValues[pv.first] = pv.second.number_value();
c@75 739 }
c@75 740
c@75 741 if (j["currentProgram"].is_string()) {
c@75 742 config.currentProgram = j["currentProgram"].string_value();
c@75 743 }
c@75 744
c@75 745 return config;
c@75 746 }
c@75 747
c@75 748 static json11::Json
c@75 749 fromAdapterFlags(int flags) {
c@75 750
c@75 751 json11::Json::array arr;
c@75 752
c@75 753 if (flags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) {
c@75 754 arr.push_back("AdaptInputDomain");
c@75 755 }
c@75 756 if (flags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) {
c@75 757 arr.push_back("AdaptChannelCount");
c@75 758 }
c@75 759 if (flags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) {
c@75 760 arr.push_back("AdaptBufferSize");
c@75 761 }
c@75 762
c@75 763 return json11::Json(arr);
c@75 764 }
c@75 765
c@75 766 static Vamp::HostExt::PluginLoader::AdapterFlags
c@75 767 toAdapterFlags(json11::Json j, std::string &err) {
c@75 768
c@75 769 int flags = 0x0;
c@75 770
c@75 771 if (!j.is_array()) {
c@75 772
c@75 773 err = "array expected for adapter flags";
c@75 774
c@75 775 } else {
c@75 776
c@75 777 for (auto &jj: j.array_items()) {
c@75 778 if (!jj.is_string()) {
c@75 779 err = "string expected for adapter flag";
c@75 780 break;
c@75 781 }
c@75 782 std::string text = jj.string_value();
c@75 783 if (text == "AdaptInputDomain") {
c@75 784 flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN;
c@75 785 } else if (text == "AdaptChannelCount") {
c@75 786 flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT;
c@75 787 } else if (text == "AdaptBufferSize") {
c@75 788 flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE;
c@75 789 } else if (text == "AdaptAllSafe") {
c@75 790 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE;
c@75 791 } else if (text == "AdaptAll") {
c@75 792 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL;
c@75 793 } else {
c@75 794 err = "invalid adapter flag string: " + text;
c@75 795 break;
c@75 796 }
c@75 797 }
c@75 798 }
c@75 799
c@75 800 return Vamp::HostExt::PluginLoader::AdapterFlags(flags);
c@75 801 }
c@75 802
c@75 803 static json11::Json
c@97 804 fromLoadRequest(const LoadRequest &req) {
c@75 805
c@75 806 json11::Json::object jo;
c@75 807 jo["key"] = req.pluginKey;
c@75 808 jo["inputSampleRate"] = req.inputSampleRate;
c@75 809 jo["adapterFlags"] = fromAdapterFlags(req.adapterFlags);
c@75 810 return json11::Json(jo);
c@75 811 }
c@75 812
c@97 813 static LoadRequest
c@75 814 toLoadRequest(json11::Json j, std::string &err) {
c@75 815
c@75 816 if (!j.has_shape({
c@75 817 { "key", json11::Json::STRING },
c@75 818 { "inputSampleRate", json11::Json::NUMBER } }, err)) {
c@75 819 err = "malformed load request: " + err;
c@75 820 return {};
c@75 821 }
c@75 822
c@97 823 LoadRequest req;
c@75 824 req.pluginKey = j["key"].string_value();
c@75 825 req.inputSampleRate = j["inputSampleRate"].number_value();
c@75 826 if (!j["adapterFlags"].is_null()) {
c@75 827 req.adapterFlags = toAdapterFlags(j["adapterFlags"], err);
c@75 828 if (failed(err)) return {};
c@75 829 }
c@75 830 return req;
c@75 831 }
c@75 832
c@75 833 static json11::Json
c@97 834 fromLoadResponse(const LoadResponse &resp,
c@75 835 const PluginHandleMapper &pmapper) {
c@75 836
c@75 837 json11::Json::object jo;
c@75 838 jo["handle"] = double(pmapper.pluginToHandle(resp.plugin));
c@75 839 jo["staticData"] = fromPluginStaticData(resp.staticData);
c@75 840 jo["defaultConfiguration"] =
c@75 841 fromPluginConfiguration(resp.defaultConfiguration);
c@75 842 return json11::Json(jo);
c@75 843 }
c@75 844
c@97 845 static LoadResponse
c@75 846 toLoadResponse(json11::Json j,
c@75 847 const PluginHandleMapper &pmapper, std::string &err) {
c@75 848
c@75 849 if (!j.has_shape({
c@75 850 { "handle", json11::Json::NUMBER },
c@75 851 { "staticData", json11::Json::OBJECT },
c@75 852 { "defaultConfiguration", json11::Json::OBJECT } }, err)) {
c@75 853 err = "malformed load response: " + err;
c@75 854 return {};
c@75 855 }
c@75 856
c@97 857 LoadResponse resp;
c@75 858 resp.plugin = pmapper.handleToPlugin(j["handle"].int_value());
c@75 859 resp.staticData = toPluginStaticData(j["staticData"], err);
c@75 860 if (failed(err)) return {};
c@75 861 resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"],
c@75 862 err);
c@75 863 if (failed(err)) return {};
c@75 864 return resp;
c@75 865 }
c@75 866
c@75 867 static json11::Json
c@97 868 fromConfigurationRequest(const ConfigurationRequest &cr,
c@75 869 const PluginHandleMapper &pmapper) {
c@75 870
c@75 871 json11::Json::object jo;
c@75 872
c@86 873 jo["handle"] = double(pmapper.pluginToHandle(cr.plugin));
c@75 874 jo["configuration"] = fromPluginConfiguration(cr.configuration);
c@75 875
c@75 876 return json11::Json(jo);
c@75 877 }
c@75 878
c@97 879 static ConfigurationRequest
c@75 880 toConfigurationRequest(json11::Json j,
c@75 881 const PluginHandleMapper &pmapper, std::string &err) {
c@75 882
c@75 883 if (!j.has_shape({
c@75 884 { "handle", json11::Json::NUMBER },
c@75 885 { "configuration", json11::Json::OBJECT } }, err)) {
c@75 886 err = "malformed configuration request: " + err;
c@75 887 return {};
c@75 888 }
c@75 889
c@97 890 ConfigurationRequest cr;
c@75 891 cr.plugin = pmapper.handleToPlugin(j["handle"].int_value());
c@75 892 cr.configuration = toPluginConfiguration(j["configuration"], err);
c@75 893 if (failed(err)) return {};
c@75 894 return cr;
c@75 895 }
c@75 896
c@75 897 static json11::Json
c@97 898 fromConfigurationResponse(const ConfigurationResponse &cr,
c@75 899 const PluginHandleMapper &pmapper) {
c@75 900
c@75 901 json11::Json::object jo;
c@75 902
c@86 903 jo["handle"] = double(pmapper.pluginToHandle(cr.plugin));
c@75 904
c@75 905 json11::Json::array outs;
c@75 906 for (auto &d: cr.outputs) {
c@75 907 outs.push_back(fromOutputDescriptor(d));
c@75 908 }
c@75 909 jo["outputList"] = outs;
c@75 910
c@75 911 return json11::Json(jo);
c@75 912 }
c@75 913
c@97 914 static ConfigurationResponse
c@75 915 toConfigurationResponse(json11::Json j,
c@75 916 const PluginHandleMapper &pmapper, std::string &err) {
c@75 917
c@97 918 ConfigurationResponse cr;
c@75 919
c@75 920 cr.plugin = pmapper.handleToPlugin(j["handle"].int_value());
c@75 921
c@75 922 if (!j["outputList"].is_array()) {
c@75 923 err = "array expected for output list";
c@75 924 return {};
c@75 925 }
c@75 926
c@75 927 for (const auto &o: j["outputList"].array_items()) {
c@75 928 cr.outputs.push_back(toOutputDescriptor(o, err));
c@75 929 if (failed(err)) return {};
c@75 930 }
c@75 931
c@75 932 return cr;
c@75 933 }
c@75 934
c@75 935 static json11::Json
c@97 936 fromProcessRequest(const ProcessRequest &r,
c@75 937 const PluginHandleMapper &pmapper,
c@75 938 BufferSerialisation serialisation) {
c@75 939
c@75 940 json11::Json::object jo;
c@86 941 jo["handle"] = double(pmapper.pluginToHandle(r.plugin));
c@75 942
c@75 943 json11::Json::object io;
c@75 944 io["timestamp"] = fromRealTime(r.timestamp);
c@75 945
c@75 946 json11::Json::array chans;
c@75 947 for (size_t i = 0; i < r.inputBuffers.size(); ++i) {
c@75 948 if (serialisation == BufferSerialisation::Array) {
c@75 949 chans.push_back(json11::Json::array(r.inputBuffers[i].begin(),
c@75 950 r.inputBuffers[i].end()));
c@75 951 } else {
c@75 952 chans.push_back(fromFloatBuffer(r.inputBuffers[i].data(),
c@75 953 r.inputBuffers[i].size()));
c@75 954 }
c@75 955 }
c@75 956 io["inputBuffers"] = chans;
c@75 957
c@75 958 jo["processInput"] = io;
c@75 959 return json11::Json(jo);
c@75 960 }
c@75 961
c@97 962 static ProcessRequest
c@75 963 toProcessRequest(json11::Json j,
c@75 964 const PluginHandleMapper &pmapper,
c@75 965 BufferSerialisation &serialisation, std::string &err) {
c@75 966
c@75 967 if (!j.has_shape({
c@75 968 { "handle", json11::Json::NUMBER },
c@75 969 { "processInput", json11::Json::OBJECT } }, err)) {
c@75 970 err = "malformed process request: " + err;
c@75 971 return {};
c@75 972 }
c@75 973
c@75 974 auto input = j["processInput"];
c@75 975
c@75 976 if (!input.has_shape({
c@75 977 { "timestamp", json11::Json::OBJECT },
c@75 978 { "inputBuffers", json11::Json::ARRAY } }, err)) {
c@75 979 err = "malformed process request: " + err;
c@75 980 return {};
c@75 981 }
c@75 982
c@97 983 ProcessRequest r;
c@75 984 r.plugin = pmapper.handleToPlugin(j["handle"].int_value());
c@75 985
c@75 986 r.timestamp = toRealTime(input["timestamp"], err);
c@75 987 if (failed(err)) return {};
c@75 988
c@75 989 for (const auto &a: input["inputBuffers"].array_items()) {
c@75 990
c@75 991 if (a.is_string()) {
c@75 992 std::vector<float> buf = toFloatBuffer(a.string_value(),
c@75 993 err);
c@75 994 if (failed(err)) return {};
c@75 995 r.inputBuffers.push_back(buf);
c@75 996 serialisation = BufferSerialisation::Base64;
c@75 997
c@75 998 } else if (a.is_array()) {
c@75 999 std::vector<float> buf;
c@75 1000 for (auto v : a.array_items()) {
c@75 1001 buf.push_back(v.number_value());
c@75 1002 }
c@75 1003 r.inputBuffers.push_back(buf);
c@75 1004 serialisation = BufferSerialisation::Array;
c@75 1005
c@75 1006 } else {
c@75 1007 err = "expected arrays or strings in inputBuffers array";
c@75 1008 return {};
c@75 1009 }
c@75 1010 }
c@75 1011
c@75 1012 return r;
c@75 1013 }
c@75 1014
c@75 1015 private: // go private briefly for a couple of helper functions
c@75 1016
c@75 1017 static void
c@75 1018 checkTypeField(json11::Json j, std::string expected, std::string &err) {
c@75 1019 if (!j["method"].is_string()) {
c@75 1020 err = "string expected for method";
c@75 1021 return;
c@75 1022 }
c@75 1023 if (j["method"].string_value() != expected) {
c@75 1024 err = "expected value \"" + expected + "\" for type";
c@75 1025 return;
c@75 1026 }
c@75 1027 }
c@75 1028
c@75 1029 static bool
c@75 1030 successful(json11::Json j, std::string &err) {
c@75 1031 if (!j["success"].is_bool()) {
c@75 1032 err = "bool expected for success";
c@75 1033 return false;
c@75 1034 }
c@75 1035 return j["success"].bool_value();
c@75 1036 }
c@75 1037
c@75 1038 static void
c@75 1039 markRPC(json11::Json::object &jo) {
c@75 1040 jo["jsonrpc"] = "2.0";
c@75 1041 }
c@75 1042
c@75 1043 static void
c@75 1044 addId(json11::Json::object &jo, const json11::Json &id) {
c@75 1045 if (!id.is_null()) {
c@75 1046 jo["id"] = id;
c@75 1047 }
c@75 1048 }
c@75 1049
c@75 1050 public:
c@75 1051
c@75 1052 static json11::Json
c@75 1053 fromRpcRequest_List(const json11::Json &id) {
c@75 1054
c@75 1055 json11::Json::object jo;
c@75 1056 markRPC(jo);
c@75 1057
c@75 1058 jo["method"] = "list";
c@75 1059 addId(jo, id);
c@75 1060 return json11::Json(jo);
c@75 1061 }
c@75 1062
c@75 1063 static json11::Json
c@97 1064 fromRpcResponse_List(const ListResponse &resp,
c@75 1065 const json11::Json &id) {
c@75 1066
c@75 1067 json11::Json::object jo;
c@75 1068 markRPC(jo);
c@75 1069
c@75 1070 json11::Json::array arr;
c@75 1071 for (const auto &a: resp.available) {
c@75 1072 arr.push_back(fromPluginStaticData(a));
c@75 1073 }
c@75 1074 json11::Json::object po;
c@75 1075 po["available"] = arr;
c@75 1076
c@75 1077 jo["method"] = "list";
c@75 1078 jo["result"] = po;
c@75 1079 addId(jo, id);
c@75 1080 return json11::Json(jo);
c@75 1081 }
c@75 1082
c@75 1083 static json11::Json
c@97 1084 fromRpcRequest_Load(const LoadRequest &req,
c@75 1085 const json11::Json &id) {
c@75 1086
c@75 1087 json11::Json::object jo;
c@75 1088 markRPC(jo);
c@75 1089
c@75 1090 jo["method"] = "load";
c@75 1091 jo["params"] = fromLoadRequest(req);
c@75 1092 addId(jo, id);
c@75 1093 return json11::Json(jo);
c@75 1094 }
c@75 1095
c@75 1096 static json11::Json
c@97 1097 fromRpcResponse_Load(const LoadResponse &resp,
c@75 1098 const PluginHandleMapper &pmapper,
c@75 1099 const json11::Json &id) {
c@75 1100
c@75 1101 if (resp.plugin) {
c@75 1102
c@75 1103 json11::Json::object jo;
c@75 1104 markRPC(jo);
c@75 1105
c@75 1106 jo["method"] = "load";
c@75 1107 jo["result"] = fromLoadResponse(resp, pmapper);
c@75 1108 addId(jo, id);
c@75 1109 return json11::Json(jo);
c@75 1110
c@75 1111 } else {
c@75 1112 return fromError("Failed to load plugin", RRType::Load, id);
c@75 1113 }
c@75 1114 }
c@75 1115
c@75 1116 static json11::Json
c@97 1117 fromRpcRequest_Configure(const ConfigurationRequest &req,
c@75 1118 const PluginHandleMapper &pmapper,
c@75 1119 const json11::Json &id) {
c@75 1120
c@75 1121 json11::Json::object jo;
c@75 1122 markRPC(jo);
c@75 1123
c@75 1124 jo["method"] = "configure";
c@75 1125 jo["params"] = fromConfigurationRequest(req, pmapper);
c@75 1126 addId(jo, id);
c@75 1127 return json11::Json(jo);
c@75 1128 }
c@75 1129
c@75 1130 static json11::Json
c@97 1131 fromRpcResponse_Configure(const ConfigurationResponse &resp,
c@75 1132 const PluginHandleMapper &pmapper,
c@75 1133 const json11::Json &id) {
c@75 1134
c@75 1135 if (!resp.outputs.empty()) {
c@75 1136
c@75 1137 json11::Json::object jo;
c@75 1138 markRPC(jo);
c@75 1139
c@75 1140 jo["method"] = "configure";
c@75 1141 jo["result"] = fromConfigurationResponse(resp, pmapper);
c@75 1142 addId(jo, id);
c@75 1143 return json11::Json(jo);
c@75 1144
c@75 1145 } else {
c@75 1146 return fromError("Failed to configure plugin", RRType::Configure, id);
c@75 1147 }
c@75 1148 }
c@75 1149
c@75 1150 static json11::Json
c@97 1151 fromRpcRequest_Process(const ProcessRequest &req,
c@75 1152 const PluginHandleMapper &pmapper,
c@75 1153 BufferSerialisation serialisation,
c@75 1154 const json11::Json &id) {
c@75 1155
c@75 1156 json11::Json::object jo;
c@75 1157 markRPC(jo);
c@75 1158
c@75 1159 jo["method"] = "process";
c@75 1160 jo["params"] = fromProcessRequest(req, pmapper, serialisation);
c@75 1161 addId(jo, id);
c@75 1162 return json11::Json(jo);
c@75 1163 }
c@75 1164
c@75 1165 static json11::Json
c@97 1166 fromRpcResponse_Process(const ProcessResponse &resp,
c@75 1167 const PluginHandleMapper &pmapper,
c@75 1168 BufferSerialisation serialisation,
c@75 1169 const json11::Json &id) {
c@75 1170
c@75 1171 json11::Json::object jo;
c@75 1172 markRPC(jo);
c@75 1173
c@75 1174 json11::Json::object po;
c@86 1175 po["handle"] = double(pmapper.pluginToHandle(resp.plugin));
c@75 1176 po["features"] = fromFeatureSet(resp.features,
c@75 1177 *pmapper.pluginToOutputIdMapper(resp.plugin),
c@75 1178 serialisation);
c@75 1179 jo["method"] = "process";
c@75 1180 jo["result"] = po;
c@75 1181 addId(jo, id);
c@75 1182 return json11::Json(jo);
c@75 1183 }
c@75 1184
c@75 1185 static json11::Json
c@97 1186 fromRpcRequest_Finish(const FinishRequest &req,
c@75 1187 const PluginHandleMapper &pmapper,
c@75 1188 const json11::Json &id) {
c@75 1189
c@75 1190 json11::Json::object jo;
c@75 1191 markRPC(jo);
c@75 1192
c@75 1193 json11::Json::object fo;
c@86 1194 fo["handle"] = double(pmapper.pluginToHandle(req.plugin));
c@75 1195
c@75 1196 jo["method"] = "finish";
c@75 1197 jo["params"] = fo;
c@75 1198 addId(jo, id);
c@75 1199 return json11::Json(jo);
c@75 1200 }
c@75 1201
c@75 1202 static json11::Json
c@97 1203 fromRpcResponse_Finish(const FinishResponse &resp,
c@75 1204 const PluginHandleMapper &pmapper,
c@75 1205 BufferSerialisation serialisation,
c@75 1206 const json11::Json &id) {
c@75 1207
c@75 1208 json11::Json::object jo;
c@75 1209 markRPC(jo);
c@75 1210
c@75 1211 json11::Json::object po;
c@86 1212 po["handle"] = double(pmapper.pluginToHandle(resp.plugin));
c@75 1213 po["features"] = fromFeatureSet(resp.features,
c@75 1214 *pmapper.pluginToOutputIdMapper(resp.plugin),
c@75 1215 serialisation);
c@75 1216 jo["method"] = "finish";
c@75 1217 jo["result"] = po;
c@75 1218 addId(jo, id);
c@75 1219 return json11::Json(jo);
c@75 1220 }
c@75 1221
c@75 1222 static json11::Json
c@75 1223 fromError(std::string errorText,
c@75 1224 RRType responseType,
c@75 1225 const json11::Json &id) {
c@75 1226
c@75 1227 json11::Json::object jo;
c@75 1228 markRPC(jo);
c@75 1229
c@75 1230 std::string type;
c@75 1231
c@75 1232 if (responseType == RRType::List) type = "list";
c@75 1233 else if (responseType == RRType::Load) type = "load";
c@75 1234 else if (responseType == RRType::Configure) type = "configure";
c@75 1235 else if (responseType == RRType::Process) type = "process";
c@75 1236 else if (responseType == RRType::Finish) type = "finish";
c@75 1237 else type = "invalid";
c@75 1238
c@75 1239 json11::Json::object eo;
c@75 1240 eo["code"] = 0;
c@75 1241 eo["message"] =
c@75 1242 std::string("error in ") + type + " request: " + errorText;
c@75 1243
c@75 1244 jo["method"] = type;
c@75 1245 jo["error"] = eo;
c@75 1246 addId(jo, id);
c@75 1247 return json11::Json(jo);
c@75 1248 }
c@75 1249
c@75 1250 static RRType
c@75 1251 getRequestResponseType(json11::Json j, std::string &err) {
c@75 1252
c@75 1253 if (!j["method"].is_string()) {
c@75 1254 err = "string expected for method";
c@75 1255 return RRType::NotValid;
c@75 1256 }
c@75 1257
c@75 1258 std::string type = j["method"].string_value();
c@75 1259
c@75 1260 if (type == "list") return RRType::List;
c@75 1261 else if (type == "load") return RRType::Load;
c@75 1262 else if (type == "configure") return RRType::Configure;
c@75 1263 else if (type == "process") return RRType::Process;
c@75 1264 else if (type == "finish") return RRType::Finish;
c@75 1265 else if (type == "invalid") return RRType::NotValid;
c@75 1266 else {
c@75 1267 err = "unknown or unexpected request/response type \"" + type + "\"";
c@75 1268 return RRType::NotValid;
c@75 1269 }
c@75 1270 }
c@75 1271
c@75 1272 static void
c@75 1273 toRpcRequest_List(json11::Json j, std::string &err) {
c@75 1274 checkTypeField(j, "list", err);
c@75 1275 }
c@75 1276
c@97 1277 static ListResponse
c@75 1278 toRpcResponse_List(json11::Json j, std::string &err) {
c@75 1279
c@97 1280 ListResponse resp;
c@75 1281 if (successful(j, err) && !failed(err)) {
c@75 1282 for (const auto &a: j["result"]["available"].array_items()) {
c@75 1283 resp.available.push_back(toPluginStaticData(a, err));
c@75 1284 if (failed(err)) return {};
c@75 1285 }
c@75 1286 }
c@75 1287
c@75 1288 return resp;
c@75 1289 }
c@75 1290
c@97 1291 static LoadRequest
c@75 1292 toRpcRequest_Load(json11::Json j, std::string &err) {
c@75 1293
c@75 1294 checkTypeField(j, "load", err);
c@75 1295 if (failed(err)) return {};
c@75 1296 return toLoadRequest(j["params"], err);
c@75 1297 }
c@75 1298
c@97 1299 static LoadResponse
c@75 1300 toRpcResponse_Load(json11::Json j,
c@75 1301 const PluginHandleMapper &pmapper,
c@75 1302 std::string &err) {
c@75 1303
c@97 1304 LoadResponse resp;
c@75 1305 if (successful(j, err) && !failed(err)) {
c@75 1306 resp = toLoadResponse(j["result"], pmapper, err);
c@75 1307 }
c@75 1308 return resp;
c@75 1309 }
c@75 1310
c@97 1311 static ConfigurationRequest
c@75 1312 toRpcRequest_Configure(json11::Json j,
c@75 1313 const PluginHandleMapper &pmapper,
c@75 1314 std::string &err) {
c@75 1315
c@75 1316 checkTypeField(j, "configure", err);
c@75 1317 if (failed(err)) return {};
c@75 1318 return toConfigurationRequest(j["params"], pmapper, err);
c@75 1319 }
c@75 1320
c@97 1321 static ConfigurationResponse
c@75 1322 toRpcResponse_Configure(json11::Json j,
c@75 1323 const PluginHandleMapper &pmapper,
c@75 1324 std::string &err) {
c@75 1325
c@97 1326 ConfigurationResponse resp;
c@75 1327 if (successful(j, err) && !failed(err)) {
c@75 1328 resp = toConfigurationResponse(j["result"], pmapper, err);
c@75 1329 }
c@75 1330 return resp;
c@75 1331 }
c@75 1332
c@97 1333 static ProcessRequest
c@75 1334 toRpcRequest_Process(json11::Json j, const PluginHandleMapper &pmapper,
c@75 1335 BufferSerialisation &serialisation, std::string &err) {
c@75 1336
c@75 1337 checkTypeField(j, "process", err);
c@75 1338 if (failed(err)) return {};
c@75 1339 return toProcessRequest(j["params"], pmapper, serialisation, err);
c@75 1340 }
c@75 1341
c@97 1342 static ProcessResponse
c@75 1343 toRpcResponse_Process(json11::Json j,
c@75 1344 const PluginHandleMapper &pmapper,
c@75 1345 BufferSerialisation &serialisation, std::string &err) {
c@75 1346
c@97 1347 ProcessResponse resp;
c@75 1348 if (successful(j, err) && !failed(err)) {
c@75 1349 auto jc = j["result"];
c@75 1350 auto h = jc["handle"].int_value();
c@75 1351 resp.plugin = pmapper.handleToPlugin(h);
c@75 1352 resp.features = toFeatureSet(jc["features"],
c@75 1353 *pmapper.handleToOutputIdMapper(h),
c@75 1354 serialisation, err);
c@75 1355 }
c@75 1356 return resp;
c@75 1357 }
c@75 1358
c@97 1359 static FinishRequest
c@75 1360 toRpcRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper,
c@75 1361 std::string &err) {
c@75 1362
c@75 1363 checkTypeField(j, "finish", err);
c@75 1364 if (failed(err)) return {};
c@97 1365 FinishRequest req;
c@75 1366 req.plugin = pmapper.handleToPlugin
c@75 1367 (j["params"]["handle"].int_value());
c@75 1368 return req;
c@75 1369 }
c@75 1370
c@97 1371 static FinishResponse
c@75 1372 toRpcResponse_Finish(json11::Json j,
c@97 1373 const PluginHandleMapper &pmapper,
c@97 1374 BufferSerialisation &serialisation, std::string &err) {
c@75 1375
c@97 1376 FinishResponse resp;
c@75 1377 if (successful(j, err) && !failed(err)) {
c@75 1378 auto jc = j["result"];
c@75 1379 auto h = jc["handle"].int_value();
c@75 1380 resp.plugin = pmapper.handleToPlugin(h);
c@75 1381 resp.features = toFeatureSet(jc["features"],
c@75 1382 *pmapper.handleToOutputIdMapper(h),
c@75 1383 serialisation, err);
c@75 1384 }
c@75 1385 return resp;
c@75 1386 }
c@75 1387 };
c@75 1388
c@75 1389 }
c@75 1390
c@75 1391 #endif