annotate vamp-json/VampJson.h @ 180:bd543e74a9bf

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