c@23: c@23: #include "VampJson.h" c@23: #include "VampnProto.h" c@23: c@23: #include c@23: #include c@23: #include c@23: c@23: using namespace std; c@23: using namespace json11; c@23: using namespace vampipe; c@23: c@23: // Accepting JSON objects with two fields, "type" and "payload". The c@23: // "type" string corresponds to the JSON schema filename c@23: // (e.g. "outputdescriptor") and the "payload" is the JSON object c@23: // encoded with that schema. c@23: c@23: Json c@23: json_input(string input) c@23: { c@23: string err; c@23: Json j = Json::parse(input, err); c@23: if (err != "") { c@23: throw VampJson::Failure("invalid json: " + err); c@23: } c@23: if (!j.is_object()) { c@23: throw VampJson::Failure("object expected at top level"); c@23: } c@23: if (!j["type"].is_string()) { c@23: throw VampJson::Failure("string expected for type field"); c@23: } c@23: if (!j["payload"].is_object()) { c@23: throw VampJson::Failure("object expected for payload field"); c@23: } c@23: return j; c@23: } c@23: c@23: class PreservingPluginHandleMapper : public PluginHandleMapper c@23: { c@23: public: c@23: PreservingPluginHandleMapper() : m_handle(0), m_plugin(0) { } c@23: c@23: virtual int32_t pluginToHandle(Vamp::Plugin *p) { c@23: if (p == m_plugin) return m_handle; c@23: else throw NotFound(); c@23: } c@23: c@23: virtual Vamp::Plugin *handleToPlugin(int32_t h) { c@23: m_handle = h; c@23: m_plugin = reinterpret_cast(h); c@23: return m_plugin; c@23: } c@23: c@23: private: c@23: int32_t m_handle; c@23: Vamp::Plugin *m_plugin; c@23: }; c@23: c@23: void c@23: handle_input(::capnp::MallocMessageBuilder &message, string input) c@23: { c@23: string err; c@23: c@23: Json j = json_input(input); c@23: string type = j["type"].string_value(); c@23: Json payload = j["payload"]; c@23: c@23: if (type == "configurationrequest") { c@23: auto req = message.initRoot(); c@23: PreservingPluginHandleMapper mapper; c@23: VampnProto::buildConfigurationRequest c@23: (req, VampJson::toConfigurationRequest(payload, mapper), mapper); c@23: c@23: } else if (type == "configurationresponse") { c@23: auto resp = message.initRoot(); c@23: VampnProto::buildConfigurationResponse c@23: (resp, VampJson::toConfigurationResponse(payload)); c@23: c@23: } else if (type == "feature") { c@23: auto f = message.initRoot(); c@23: VampnProto::buildFeature c@23: (f, VampJson::toFeature(payload)); c@23: c@23: } else if (type == "featureset") { c@23: auto fs = message.initRoot(); c@23: VampnProto::buildFeatureSet c@23: (fs, VampJson::toFeatureSet(payload)); c@23: c@23: } else if (type == "loadrequest") { c@23: auto req = message.initRoot(); c@23: VampnProto::buildLoadRequest c@23: (req, VampJson::toLoadRequest(payload)); c@23: c@23: } else if (type == "loadresponse") { c@23: auto resp = message.initRoot(); c@23: PreservingPluginHandleMapper mapper; c@23: VampnProto::buildLoadResponse c@23: (resp, VampJson::toLoadResponse(payload, mapper), mapper); c@23: c@23: } else if (type == "outputdescriptor") { c@23: auto od = message.initRoot(); c@23: VampnProto::buildOutputDescriptor c@23: (od, VampJson::toOutputDescriptor(payload)); c@23: c@23: } else if (type == "parameterdescriptor") { c@23: auto pd = message.initRoot(); c@23: VampnProto::buildParameterDescriptor c@23: (pd, VampJson::toParameterDescriptor(payload)); c@23: c@23: } else if (type == "pluginconfiguration") { c@23: auto pc = message.initRoot(); c@23: auto config = VampJson::toPluginConfiguration(payload); c@23: VampnProto::buildPluginConfiguration(pc, config); c@23: c@23: } else if (type == "pluginstaticdata") { c@23: auto pc = message.initRoot(); c@23: auto sd = VampJson::toPluginStaticData(payload); c@23: VampnProto::buildPluginStaticData(pc, sd); c@23: c@23: } else if (type == "processrequest") { c@23: auto p = message.initRoot(); c@23: PreservingPluginHandleMapper mapper; c@23: VampnProto::buildProcessRequest c@23: (p, VampJson::toProcessRequest(payload, mapper), mapper); c@23: c@23: } else if (type == "realtime") { c@23: auto b = message.initRoot(); c@23: VampnProto::buildRealTime c@23: (b, VampJson::toRealTime(payload)); c@23: c@23: } else { c@23: throw VampJson::Failure("unknown or unsupported JSON schema type " + c@23: type); c@23: } c@23: } c@23: c@23: void usage() c@23: { c@23: string myname = "vampipe-convert"; c@23: cerr << "\n" << myname << c@23: ": Convert Vamp request and response messages between formats\n\n" c@23: " Usage: " << myname << " -i -o \n\n" c@23: "Where and may be \"json\" or \"capnp\".\n" c@23: "Messages are read from stdin and written to stdout.\n" << endl; c@23: exit(2); c@23: } c@23: c@23: class RequestOrResponse c@23: { c@23: public: c@23: enum Type { c@23: List, Load, Configure, Process, Finish, Eof c@23: }; c@23: RequestOrResponse() : // nothing by default c@23: type(Eof), c@23: success(false), c@23: finishPlugin(0) { } c@23: c@23: Type type; c@23: bool success; c@23: string errorText; c@23: c@23: PreservingPluginHandleMapper mapper; c@23: c@23: Vamp::HostExt::LoadRequest loadRequest; c@23: Vamp::HostExt::LoadResponse loadResponse; c@23: Vamp::HostExt::ConfigurationRequest configurationRequest; c@23: Vamp::HostExt::ConfigurationResponse configurationResponse; c@23: Vamp::HostExt::ProcessRequest processRequest; c@23: Vamp::HostExt::ProcessResponse processResponse; c@23: Vamp::Plugin *finishPlugin; c@23: Vamp::HostExt::ProcessResponse finishResponse; c@23: c@23: }; c@23: c@23: RequestOrResponse c@23: readInputJson() c@23: { c@23: RequestOrResponse rr; c@23: string input; c@23: if (!getline(cin, input)) { c@23: rr.type = RequestOrResponse::Eof; c@23: return rr; c@23: } c@23: c@23: Json j = json_input(input); c@23: string type = j["type"].string_value(); c@23: c@23: if (type == "list") { c@23: rr.type = RequestOrResponse::List; c@23: c@23: } else if (type == "load") { c@23: //!!! ah, we need a way to know whether we're dealing with a request or response here c@23: rr.type = RequestOrResponse::Load; c@23: rr.loadRequest = VampJson::toLoadRequest(j["content"]); c@23: c@23: } else if (type == "configure") { c@23: rr.type = RequestOrResponse::Configure; c@23: rr.configurationRequest = c@23: VampJson::toConfigurationRequest(j["content"], rr.mapper); c@23: c@23: } else if (type == "process") { c@23: rr.type = RequestOrResponse::Process; c@23: rr.processRequest = c@23: VampJson::toProcessRequest(j["content"], rr.mapper); c@23: c@23: } else if (type == "finish") { c@23: rr.type = RequestOrResponse::Finish; c@23: //!!! VampJsonify c@23: rr.finishPlugin = rr.mapper.handleToPlugin(j["content"]["pluginHandle"].int_value()); c@23: c@23: } else { c@23: throw runtime_error("unknown or unexpected request/response type \"" + c@23: type + "\""); c@23: } c@23: c@23: return rr; c@23: } c@23: c@23: RequestOrResponse c@23: readInput(string format) c@23: { c@23: if (format == "json") { c@23: return readInputJson(); c@23: } else { c@23: throw runtime_error("unknown or unimplemented format \"" + format + "\""); c@23: } c@23: } c@23: c@23: void c@23: writeOutput(string format, const RequestOrResponse &rr) c@23: { c@23: throw runtime_error("writeOutput not implemented yet"); c@23: c@23: } c@23: c@23: int main(int argc, char **argv) c@23: { c@23: if (argc != 5) { c@23: usage(); c@23: } c@23: c@23: string informat, outformat; c@23: c@23: for (int i = 1; i + 1 < argc; ++i) { c@23: c@23: string arg = argv[i]; c@23: c@23: if (arg == "-i") { c@23: if (informat != "") usage(); c@23: else informat = argv[++i]; c@23: c@23: } else if (arg == "-o") { c@23: if (outformat != "") usage(); c@23: else outformat = argv[++i]; c@23: c@23: } else { c@23: usage(); c@23: } c@23: } c@23: c@23: if (informat == "" || outformat == "") { c@23: usage(); c@23: } c@23: c@23: while (true) { c@23: c@23: try { c@23: c@23: RequestOrResponse rr = readInput(informat); c@23: if (rr.type == RequestOrResponse::Eof) break; c@23: writeOutput(outformat, rr); c@23: c@23: } catch (std::exception &e) { c@23: cerr << "Error: " << e.what() << endl; c@23: exit(1); c@23: } c@23: } c@23: c@23: exit(0); c@23: } c@23: c@23: