annotate VamPipePluginLibrary.cpp @ 110:2f621b00747e

Merge from branch jsonrpc
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 06 Oct 2016 14:33:12 +0100
parents 9d20eb251fbc
children 873ce3bfa776
rev   line source
c@69 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@69 2
c@69 3 /*
c@69 4 VamPipe
c@69 5
c@69 6 Centre for Digital Music, Queen Mary, University of London.
c@69 7 Copyright 2015-2016 QMUL.
c@69 8
c@69 9 Permission is hereby granted, free of charge, to any person
c@69 10 obtaining a copy of this software and associated documentation
c@69 11 files (the "Software"), to deal in the Software without
c@69 12 restriction, including without limitation the rights to use, copy,
c@69 13 modify, merge, publish, distribute, sublicense, and/or sell copies
c@69 14 of the Software, and to permit persons to whom the Software is
c@69 15 furnished to do so, subject to the following conditions:
c@69 16
c@69 17 The above copyright notice and this permission notice shall be
c@69 18 included in all copies or substantial portions of the Software.
c@69 19
c@69 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
c@69 21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
c@69 22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
c@69 23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
c@69 24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
c@69 25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
c@69 26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
c@69 27
c@69 28 Except as contained in this notice, the names of the Centre for
c@69 29 Digital Music; Queen Mary, University of London; and Chris Cannam
c@69 30 shall not be used in advertising or otherwise to promote the sale,
c@69 31 use or other dealings in this Software without prior written
c@69 32 authorization.
c@69 33 */
c@69 34
c@69 35 #include "VamPipePluginLibrary.h"
c@69 36 #include "VamPipeAdapter.h"
c@69 37 #include "json/VampJson.h"
c@69 38
c@69 39 using namespace std;
c@69 40 using namespace json11;
c@69 41
c@69 42 namespace vampipe {
c@69 43
c@69 44 //!!! too many explicit namespaces here
c@69 45
c@69 46 //!!! dup with vampipe-convert
c@99 47 Json
c@99 48 convertRequestJson(string input, string &err)
c@69 49 {
c@69 50 Json j = Json::parse(input, err);
c@69 51 if (err != "") {
c@99 52 err = "invalid json: " + err;
c@99 53 return {};
c@69 54 }
c@69 55 if (!j.is_object()) {
c@99 56 err = "object expected at top level";
c@69 57 }
c@69 58 return j;
c@69 59 }
c@69 60
c@88 61 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterInterface *> pp) :
c@81 62 m_useBase64(false)
c@69 63 {
c@88 64 for (VamPipeAdapterInterface *p: pp) {
c@69 65 string key = p->getStaticData().pluginKey;
c@69 66 m_adapters[key] = p;
c@69 67 }
c@69 68 }
c@69 69
c@94 70 Vamp::HostExt::ListResponse
c@69 71 VamPipePluginLibrary::listPluginData() const
c@69 72 {
c@94 73 Vamp::HostExt::ListResponse resp;
c@69 74 for (auto a: m_adapters) {
c@101 75 resp.plugins.push_back(a.second->getStaticData());
c@69 76 }
c@94 77 return resp;
c@69 78 }
c@69 79
c@69 80 Vamp::HostExt::LoadResponse
c@99 81 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req, string &err) const
c@69 82 {
c@69 83 string key = req.pluginKey;
c@69 84 if (m_adapters.find(key) != m_adapters.end()) {
c@99 85 auto resp = m_adapters.at(key)->loadPlugin(req);
c@99 86 if (!resp.plugin) {
c@99 87 // This should not actually happen -- the load call here
c@99 88 // is just an object construction, not a dynamic load. But
c@99 89 // report it if it does...
c@99 90 err = "failed to construct plugin with key " + key;
c@99 91 }
c@99 92 return resp;
c@69 93 } else {
c@99 94 err = "no adapter for plugin key " + key;
c@99 95 return {};
c@69 96 }
c@69 97 }
c@69 98
c@69 99 Vamp::HostExt::ConfigurationResponse
c@99 100 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req,
c@99 101 string &err) const
c@69 102 {
c@69 103 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i =
c@69 104 req.configuration.parameterValues.begin();
c@69 105 i != req.configuration.parameterValues.end(); ++i) {
c@69 106 req.plugin->setParameter(i->first, i->second);
c@69 107 }
c@69 108
c@69 109 if (req.configuration.currentProgram != "") {
c@69 110 req.plugin->selectProgram(req.configuration.currentProgram);
c@69 111 }
c@69 112
c@69 113 Vamp::HostExt::ConfigurationResponse response;
c@69 114
c@96 115 response.plugin = req.plugin;
c@96 116
c@69 117 if (req.plugin->initialise(req.configuration.channelCount,
c@69 118 req.configuration.stepSize,
c@69 119 req.configuration.blockSize)) {
c@69 120 response.outputs = req.plugin->getOutputDescriptors();
c@99 121 } else {
c@99 122 err = "configuration failed (wrong channel count, step size, block size?)";
c@69 123 }
c@69 124
c@69 125 return response;
c@69 126 }
c@69 127
c@69 128 string
c@109 129 VamPipePluginLibrary::processRawImpl(int handle,
c@83 130 const float *const *inputBuffers,
c@83 131 int sec,
c@83 132 int nsec)
c@82 133 {
c@109 134 Vamp::Plugin *plugin = m_mapper.handleToPlugin(handle);
c@99 135 if (!plugin) {
c@99 136 return VampJson::fromError("unknown plugin handle", RRType::Process)
c@98 137 .dump();
c@82 138 }
c@99 139
c@109 140 if (!m_mapper.isConfigured(handle)) {
c@99 141 return VampJson::fromError("plugin has not been configured", RRType::Process)
c@99 142 .dump();
c@99 143 }
c@99 144
c@99 145 Vamp::RealTime timestamp(sec, nsec);
c@99 146
c@99 147 Vamp::HostExt::ProcessResponse resp;
c@99 148 resp.plugin = plugin;
c@99 149 resp.features = plugin->process(inputBuffers, timestamp);
c@99 150
c@99 151 m_useBase64 = true;
c@99 152
c@109 153 return VampJson::fromRpcResponse_Process
c@99 154 (resp, m_mapper,
c@99 155 VampJson::BufferSerialisation::Base64)
c@99 156 .dump();
c@82 157 }
c@82 158
c@82 159 string
c@69 160 VamPipePluginLibrary::requestJsonImpl(string req)
c@69 161 {
c@99 162 string err;
c@99 163
c@99 164 Json j = convertRequestJson(req, err);
c@99 165 if (err != "") {
c@99 166 return VampJson::fromError(err, RRType::NotValid).dump();
c@99 167 }
c@99 168
c@99 169 RRType type = VampJson::getRequestResponseType(j, err);
c@99 170 if (err != "") {
c@99 171 return VampJson::fromError(err, RRType::NotValid).dump();
c@70 172 }
c@69 173
c@98 174 VampJson::BufferSerialisation serialisation =
c@98 175 (m_useBase64 ?
c@98 176 VampJson::BufferSerialisation::Base64 :
c@105 177 VampJson::BufferSerialisation::Array);
c@69 178
c@98 179 Json rj;
c@98 180
c@99 181 switch (type) {
c@69 182
c@99 183 case RRType::List:
c@109 184 rj = VampJson::fromRpcResponse_List(listPluginData());
c@99 185 break;
c@69 186
c@99 187 case RRType::Load:
c@99 188 {
c@109 189 auto req = VampJson::toRpcRequest_Load(j, err);
c@99 190 if (err != "") {
c@99 191 rj = VampJson::fromError(err, type);
c@99 192 } else {
c@99 193 auto resp = loadPlugin(req, err);
c@99 194 if (err != "") {
c@99 195 rj = VampJson::fromError(err, type);
c@99 196 } else {
c@98 197 m_mapper.addPlugin(resp.plugin);
c@109 198 rj = VampJson::fromRpcResponse_Load(resp, m_mapper);
c@98 199 }
c@92 200 }
c@99 201 break;
c@99 202 }
c@92 203
c@99 204 case RRType::Configure:
c@99 205 {
c@109 206 auto req = VampJson::toRpcRequest_Configure(j, m_mapper, err);
c@99 207 if (err != "") {
c@99 208 rj = VampJson::fromError(err, type);
c@99 209 } else {
c@98 210 auto h = m_mapper.pluginToHandle(req.plugin);
c@99 211 if (h == m_mapper.INVALID_HANDLE) {
c@99 212 rj = VampJson::fromError("unknown or invalid plugin handle", type);
c@99 213 } else if (m_mapper.isConfigured(h)) {
c@99 214 rj = VampJson::fromError("plugin has already been configured", type);
c@99 215 } else {
c@99 216 auto resp = configurePlugin(req, err);
c@99 217 if (err != "") {
c@99 218 rj = VampJson::fromError(err, type);
c@99 219 } else {
c@99 220 m_mapper.markConfigured(h,
c@99 221 req.configuration.channelCount,
c@99 222 req.configuration.blockSize);
c@109 223 rj = VampJson::fromRpcResponse_Configure(resp, m_mapper);
c@99 224 }
c@98 225 }
c@99 226 }
c@99 227 break;
c@99 228 }
c@69 229
c@99 230 case RRType::Process:
c@99 231 {
c@99 232 VampJson::BufferSerialisation serialisation;
c@99 233
c@109 234 auto req = VampJson::toRpcRequest_Process(j, m_mapper,
c@99 235 serialisation, err);
c@99 236 if (err != "") {
c@99 237 rj = VampJson::fromError(err, type);
c@99 238 } else {
c@99 239 auto h = m_mapper.pluginToHandle(req.plugin);
c@99 240 int channels = int(req.inputBuffers.size());
c@99 241 if (h == m_mapper.INVALID_HANDLE) {
c@99 242 rj = VampJson::fromError("unknown or invalid plugin handle", type);
c@99 243 } else if (!m_mapper.isConfigured(h)) {
c@99 244 rj = VampJson::fromError("plugin has not been configured", type);
c@99 245 } else if (channels != m_mapper.getChannelCount(h)) {
c@99 246 rj = VampJson::fromError("wrong number of channels supplied", type);
c@99 247 } else {
c@99 248
c@99 249 if (serialisation == VampJson::BufferSerialisation::Base64) {
c@99 250 m_useBase64 = true;
c@99 251 }
c@99 252
c@99 253 size_t blockSize = m_mapper.getBlockSize(h);
c@99 254
c@99 255 const float **fbuffers = new const float *[channels];
c@99 256 for (int i = 0; i < channels; ++i) {
c@99 257 if (req.inputBuffers[i].size() != blockSize) {
c@99 258 delete[] fbuffers;
c@99 259 fbuffers = 0;
c@99 260 rj = VampJson::fromError("wrong block size supplied", type);
c@99 261 break;
c@99 262 }
c@99 263 fbuffers[i] = req.inputBuffers[i].data();
c@99 264 }
c@99 265
c@99 266 if (fbuffers) {
c@99 267 Vamp::HostExt::ProcessResponse resp;
c@99 268 resp.plugin = req.plugin;
c@99 269 resp.features = req.plugin->process(fbuffers, req.timestamp);
c@99 270 delete[] fbuffers;
c@109 271 rj = VampJson::fromRpcResponse_Process
c@99 272 (resp, m_mapper, serialisation);
c@99 273 }
c@98 274 }
c@99 275 }
c@99 276 break;
c@99 277 }
c@98 278
c@99 279 case RRType::Finish:
c@99 280 {
c@109 281 auto req = VampJson::toRpcRequest_Finish(j, m_mapper, err);
c@99 282 if (err != "") {
c@99 283 rj = VampJson::fromError(err, type);
c@99 284 } else {
c@99 285 auto h = m_mapper.pluginToHandle(req.plugin);
c@99 286 if (h == m_mapper.INVALID_HANDLE) {
c@99 287 rj = VampJson::fromError("unknown or invalid plugin handle", type);
c@99 288 } else if (!m_mapper.isConfigured(h)) {
c@99 289 rj = VampJson::fromError("plugin has not been configured", type);
c@99 290 } else {
c@99 291
c@99 292 Vamp::HostExt::ProcessResponse resp;
c@99 293 resp.plugin = req.plugin;
c@99 294 resp.features = req.plugin->getRemainingFeatures();
c@99 295
c@109 296 rj = VampJson::fromRpcResponse_Finish
c@99 297 (resp, m_mapper, serialisation);
c@99 298
c@99 299 m_mapper.removePlugin(h);
c@99 300 delete req.plugin;
c@99 301 }
c@98 302 }
c@99 303 break;
c@99 304 }
c@98 305
c@99 306 case RRType::NotValid:
c@99 307 rj = VampJson::fromError("invalid request", type);
c@99 308 break;
c@69 309 }
c@98 310
c@98 311 return rj.dump();
c@69 312 }
c@69 313
c@69 314 }
c@69 315