Mercurial > hg > piper-vamp-js
comparison VamPipePluginLibrary.cpp @ 99:dfd107ef991f
Replace exceptions throughout the JSON-handling and adapter code with string-arg error handling. No longer need exception handling enabled in Emscripten (with its consequent runtime overhead - though we still need to check whether this error handling regime is actually faster).
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Tue, 20 Sep 2016 16:35:47 +0100 |
parents | 22a09aca4b4a |
children | 30028b3c95e4 |
comparison
equal
deleted
inserted
replaced
98:22a09aca4b4a | 99:dfd107ef991f |
---|---|
42 namespace vampipe { | 42 namespace vampipe { |
43 | 43 |
44 //!!! too many explicit namespaces here | 44 //!!! too many explicit namespaces here |
45 | 45 |
46 //!!! dup with vampipe-convert | 46 //!!! dup with vampipe-convert |
47 static Json | 47 Json |
48 convertRequestJson(string input) | 48 convertRequestJson(string input, string &err) |
49 { | 49 { |
50 string err; | |
51 Json j = Json::parse(input, err); | 50 Json j = Json::parse(input, err); |
52 if (err != "") { | 51 if (err != "") { |
53 throw VampJson::Failure("invalid json: " + err); | 52 err = "invalid json: " + err; |
53 return {}; | |
54 } | 54 } |
55 if (!j.is_object()) { | 55 if (!j.is_object()) { |
56 throw VampJson::Failure("object expected at top level"); | 56 err = "object expected at top level"; |
57 } | 57 } else if (!j["type"].is_string()) { |
58 if (!j["type"].is_string()) { | 58 err = "string expected for type field"; |
59 throw VampJson::Failure("string expected for type field"); | 59 } else if (!j["content"].is_null() && !j["content"].is_object()) { |
60 } | 60 err = "object expected for content field"; |
61 if (!j["content"].is_null() && !j["content"].is_object()) { | |
62 throw VampJson::Failure("object expected for content field"); | |
63 } | 61 } |
64 return j; | 62 return j; |
65 } | 63 } |
66 | 64 |
67 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterInterface *> pp) : | 65 VamPipePluginLibrary::VamPipePluginLibrary(vector<VamPipeAdapterInterface *> pp) : |
82 } | 80 } |
83 return resp; | 81 return resp; |
84 } | 82 } |
85 | 83 |
86 Vamp::HostExt::LoadResponse | 84 Vamp::HostExt::LoadResponse |
87 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req) const | 85 VamPipePluginLibrary::loadPlugin(Vamp::HostExt::LoadRequest req, string &err) const |
88 { | 86 { |
89 string key = req.pluginKey; | 87 string key = req.pluginKey; |
90 if (m_adapters.find(key) != m_adapters.end()) { | 88 if (m_adapters.find(key) != m_adapters.end()) { |
91 return m_adapters.at(key)->loadPlugin(req); | 89 auto resp = m_adapters.at(key)->loadPlugin(req); |
90 if (!resp.plugin) { | |
91 // This should not actually happen -- the load call here | |
92 // is just an object construction, not a dynamic load. But | |
93 // report it if it does... | |
94 err = "failed to construct plugin with key " + key; | |
95 } | |
96 return resp; | |
92 } else { | 97 } else { |
93 throw runtime_error("no adapter for plugin key " + key); | 98 err = "no adapter for plugin key " + key; |
99 return {}; | |
94 } | 100 } |
95 } | 101 } |
96 | 102 |
97 Vamp::HostExt::ConfigurationResponse | 103 Vamp::HostExt::ConfigurationResponse |
98 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req) const | 104 VamPipePluginLibrary::configurePlugin(Vamp::HostExt::ConfigurationRequest req, |
105 string &err) const | |
99 { | 106 { |
100 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i = | 107 for (Vamp::HostExt::PluginConfiguration::ParameterMap::const_iterator i = |
101 req.configuration.parameterValues.begin(); | 108 req.configuration.parameterValues.begin(); |
102 i != req.configuration.parameterValues.end(); ++i) { | 109 i != req.configuration.parameterValues.end(); ++i) { |
103 req.plugin->setParameter(i->first, i->second); | 110 req.plugin->setParameter(i->first, i->second); |
113 | 120 |
114 if (req.plugin->initialise(req.configuration.channelCount, | 121 if (req.plugin->initialise(req.configuration.channelCount, |
115 req.configuration.stepSize, | 122 req.configuration.stepSize, |
116 req.configuration.blockSize)) { | 123 req.configuration.blockSize)) { |
117 response.outputs = req.plugin->getOutputDescriptors(); | 124 response.outputs = req.plugin->getOutputDescriptors(); |
125 } else { | |
126 err = "configuration failed (wrong channel count, step size, block size?)"; | |
118 } | 127 } |
119 | 128 |
120 return response; | 129 return response; |
121 } | 130 } |
122 | 131 |
124 VamPipePluginLibrary::processRawImpl(int pluginHandle, | 133 VamPipePluginLibrary::processRawImpl(int pluginHandle, |
125 const float *const *inputBuffers, | 134 const float *const *inputBuffers, |
126 int sec, | 135 int sec, |
127 int nsec) | 136 int nsec) |
128 { | 137 { |
129 try { | 138 Vamp::Plugin *plugin = m_mapper.handleToPlugin(pluginHandle); |
130 if (!m_mapper.isConfigured(pluginHandle)) { | 139 if (!plugin) { |
131 throw runtime_error("plugin has not been configured"); | 140 return VampJson::fromError("unknown plugin handle", RRType::Process) |
132 } | |
133 | |
134 Vamp::Plugin *plugin = m_mapper.handleToPlugin(pluginHandle); | |
135 Vamp::RealTime timestamp(sec, nsec); | |
136 | |
137 Vamp::HostExt::ProcessResponse resp; | |
138 resp.plugin = plugin; | |
139 resp.features = plugin->process(inputBuffers, timestamp); | |
140 | |
141 m_useBase64 = true; | |
142 | |
143 return VampJson::fromVampResponse_Process | |
144 (resp, m_mapper, | |
145 VampJson::BufferSerialisation::Base64) | |
146 .dump(); | 141 .dump(); |
147 | 142 } |
148 } catch (const std::exception &e) { | 143 |
149 return VampJson::fromException(e, RRType::Process) | 144 if (!m_mapper.isConfigured(pluginHandle)) { |
145 return VampJson::fromError("plugin has not been configured", RRType::Process) | |
150 .dump(); | 146 .dump(); |
151 } | 147 } |
148 | |
149 Vamp::RealTime timestamp(sec, nsec); | |
150 | |
151 Vamp::HostExt::ProcessResponse resp; | |
152 resp.plugin = plugin; | |
153 resp.features = plugin->process(inputBuffers, timestamp); | |
154 | |
155 m_useBase64 = true; | |
156 | |
157 return VampJson::fromVampResponse_Process | |
158 (resp, m_mapper, | |
159 VampJson::BufferSerialisation::Base64) | |
160 .dump(); | |
152 } | 161 } |
153 | 162 |
154 string | 163 string |
155 VamPipePluginLibrary::requestJsonImpl(string req) | 164 VamPipePluginLibrary::requestJsonImpl(string req) |
156 { | 165 { |
157 Json j = convertRequestJson(req); | 166 string err; |
158 | 167 |
159 RRType type; | 168 Json j = convertRequestJson(req, err); |
160 try { | 169 if (err != "") { |
161 type = VampJson::getRequestResponseType(j); | 170 return VampJson::fromError(err, RRType::NotValid).dump(); |
162 } catch (const std::exception &e) { | 171 } |
163 return VampJson::fromException(e, RRType::NotValid) | 172 |
164 .dump(); | 173 RRType type = VampJson::getRequestResponseType(j, err); |
174 if (err != "") { | |
175 return VampJson::fromError(err, RRType::NotValid).dump(); | |
165 } | 176 } |
166 | 177 |
167 VampJson::BufferSerialisation serialisation = | 178 VampJson::BufferSerialisation serialisation = |
168 (m_useBase64 ? | 179 (m_useBase64 ? |
169 VampJson::BufferSerialisation::Base64 : | 180 VampJson::BufferSerialisation::Base64 : |
170 VampJson::BufferSerialisation::Text); | 181 VampJson::BufferSerialisation::Text); |
171 | 182 |
172 Json rj; | 183 Json rj; |
173 | 184 |
174 try { | 185 switch (type) { |
175 switch (type) { | 186 |
176 | 187 case RRType::List: |
177 case RRType::List: | 188 rj = VampJson::fromVampResponse_List(listPluginData()); |
178 rj = VampJson::fromVampResponse_List(listPluginData()); | 189 break; |
179 break; | 190 |
180 | 191 case RRType::Load: |
181 case RRType::Load: | 192 { |
182 { | 193 auto req = VampJson::toVampRequest_Load(j, err); |
183 auto req = VampJson::toVampRequest_Load(j); | 194 if (err != "") { |
184 auto resp = loadPlugin(req); | 195 rj = VampJson::fromError(err, type); |
185 if (resp.plugin) { | 196 } else { |
197 auto resp = loadPlugin(req, err); | |
198 if (err != "") { | |
199 rj = VampJson::fromError(err, type); | |
200 } else { | |
186 m_mapper.addPlugin(resp.plugin); | 201 m_mapper.addPlugin(resp.plugin); |
202 rj = VampJson::fromVampResponse_Load(resp, m_mapper); | |
187 } | 203 } |
188 rj = VampJson::fromVampResponse_Load(resp, m_mapper); | 204 } |
189 break; | 205 break; |
190 } | 206 } |
191 | 207 |
192 case RRType::Configure: | 208 case RRType::Configure: |
193 { | 209 { |
194 auto req = VampJson::toVampRequest_Configure(j, m_mapper); | 210 auto req = VampJson::toVampRequest_Configure(j, m_mapper, err); |
211 if (err != "") { | |
212 rj = VampJson::fromError(err, type); | |
213 } else { | |
195 auto h = m_mapper.pluginToHandle(req.plugin); | 214 auto h = m_mapper.pluginToHandle(req.plugin); |
196 if (m_mapper.isConfigured(h)) { | 215 if (h == m_mapper.INVALID_HANDLE) { |
197 throw runtime_error("plugin has already been configured"); | 216 rj = VampJson::fromError("unknown or invalid plugin handle", type); |
217 } else if (m_mapper.isConfigured(h)) { | |
218 rj = VampJson::fromError("plugin has already been configured", type); | |
219 } else { | |
220 auto resp = configurePlugin(req, err); | |
221 if (err != "") { | |
222 rj = VampJson::fromError(err, type); | |
223 } else { | |
224 m_mapper.markConfigured(h, | |
225 req.configuration.channelCount, | |
226 req.configuration.blockSize); | |
227 rj = VampJson::fromVampResponse_Configure(resp, m_mapper); | |
228 } | |
198 } | 229 } |
199 | 230 } |
200 auto resp = configurePlugin(req); | 231 break; |
201 if (!resp.outputs.empty()) { | 232 } |
202 m_mapper.markConfigured(h, | 233 |
203 req.configuration.channelCount, | 234 case RRType::Process: |
204 req.configuration.blockSize); | 235 { |
236 VampJson::BufferSerialisation serialisation; | |
237 | |
238 auto req = VampJson::toVampRequest_Process(j, m_mapper, | |
239 serialisation, err); | |
240 if (err != "") { | |
241 rj = VampJson::fromError(err, type); | |
242 } else { | |
243 auto h = m_mapper.pluginToHandle(req.plugin); | |
244 int channels = int(req.inputBuffers.size()); | |
245 if (h == m_mapper.INVALID_HANDLE) { | |
246 rj = VampJson::fromError("unknown or invalid plugin handle", type); | |
247 } else if (!m_mapper.isConfigured(h)) { | |
248 rj = VampJson::fromError("plugin has not been configured", type); | |
249 } else if (channels != m_mapper.getChannelCount(h)) { | |
250 rj = VampJson::fromError("wrong number of channels supplied", type); | |
251 } else { | |
252 | |
253 if (serialisation == VampJson::BufferSerialisation::Base64) { | |
254 m_useBase64 = true; | |
255 } | |
256 | |
257 size_t blockSize = m_mapper.getBlockSize(h); | |
258 | |
259 const float **fbuffers = new const float *[channels]; | |
260 for (int i = 0; i < channels; ++i) { | |
261 if (req.inputBuffers[i].size() != blockSize) { | |
262 delete[] fbuffers; | |
263 fbuffers = 0; | |
264 rj = VampJson::fromError("wrong block size supplied", type); | |
265 break; | |
266 } | |
267 fbuffers[i] = req.inputBuffers[i].data(); | |
268 } | |
269 | |
270 if (fbuffers) { | |
271 Vamp::HostExt::ProcessResponse resp; | |
272 resp.plugin = req.plugin; | |
273 resp.features = req.plugin->process(fbuffers, req.timestamp); | |
274 delete[] fbuffers; | |
275 rj = VampJson::fromVampResponse_Process | |
276 (resp, m_mapper, serialisation); | |
277 } | |
205 } | 278 } |
206 | 279 } |
207 rj = VampJson::fromVampResponse_Configure(resp, m_mapper); | 280 break; |
208 break; | 281 } |
209 } | 282 |
210 | 283 case RRType::Finish: |
211 case RRType::Process: | 284 { |
212 { | 285 auto req = VampJson::toVampRequest_Finish(j, m_mapper, err); |
213 VampJson::BufferSerialisation serialisation; | 286 if (err != "") { |
214 | 287 rj = VampJson::fromError(err, type); |
215 auto req = VampJson::toVampRequest_Process(j, m_mapper, | 288 } else { |
216 serialisation); | |
217 | |
218 auto h = m_mapper.pluginToHandle(req.plugin); | 289 auto h = m_mapper.pluginToHandle(req.plugin); |
219 if (!m_mapper.isConfigured(h)) { | 290 if (h == m_mapper.INVALID_HANDLE) { |
220 throw runtime_error("plugin has not been configured"); | 291 rj = VampJson::fromError("unknown or invalid plugin handle", type); |
292 } else if (!m_mapper.isConfigured(h)) { | |
293 rj = VampJson::fromError("plugin has not been configured", type); | |
294 } else { | |
295 | |
296 Vamp::HostExt::ProcessResponse resp; | |
297 resp.plugin = req.plugin; | |
298 resp.features = req.plugin->getRemainingFeatures(); | |
299 | |
300 rj = VampJson::fromVampResponse_Finish | |
301 (resp, m_mapper, serialisation); | |
302 | |
303 m_mapper.removePlugin(h); | |
304 delete req.plugin; | |
221 } | 305 } |
222 | 306 } |
223 int channels = int(req.inputBuffers.size()); | 307 break; |
224 if (channels != m_mapper.getChannelCount(h)) { | 308 } |
225 throw runtime_error("wrong number of channels supplied to process"); | 309 |
226 } | 310 case RRType::NotValid: |
227 | 311 rj = VampJson::fromError("invalid request", type); |
228 if (serialisation == VampJson::BufferSerialisation::Base64) { | 312 break; |
229 m_useBase64 = true; | |
230 } | |
231 | |
232 const float **fbuffers = new const float *[channels]; | |
233 for (int i = 0; i < channels; ++i) { | |
234 if (int(req.inputBuffers[i].size()) != m_mapper.getBlockSize(h)) { | |
235 delete[] fbuffers; | |
236 throw runtime_error("wrong block size supplied to process"); | |
237 } | |
238 fbuffers[i] = req.inputBuffers[i].data(); | |
239 } | |
240 | |
241 Vamp::HostExt::ProcessResponse resp; | |
242 resp.plugin = req.plugin; | |
243 resp.features = req.plugin->process(fbuffers, req.timestamp); | |
244 delete[] fbuffers; | |
245 | |
246 rj = VampJson::fromVampResponse_Process(resp, m_mapper, serialisation); | |
247 break; | |
248 } | |
249 | |
250 case RRType::Finish: | |
251 { | |
252 auto req = VampJson::toVampRequest_Finish(j, m_mapper); | |
253 auto h = m_mapper.pluginToHandle(req.plugin); | |
254 if (!m_mapper.isConfigured(h)) { | |
255 throw runtime_error("plugin has not been configured"); | |
256 } | |
257 | |
258 Vamp::HostExt::ProcessResponse resp; | |
259 resp.plugin = req.plugin; | |
260 resp.features = req.plugin->getRemainingFeatures(); | |
261 | |
262 rj = VampJson::fromVampResponse_Finish(resp, m_mapper, serialisation); | |
263 | |
264 m_mapper.removePlugin(h); | |
265 delete req.plugin; | |
266 break; | |
267 } | |
268 | |
269 case RRType::NotValid: | |
270 rj = VampJson::fromError("invalid request", type); | |
271 break; | |
272 } | |
273 | |
274 } catch (const std::exception &e) { | |
275 rj = VampJson::fromException(e, type); | |
276 } | 313 } |
277 | 314 |
278 return rj.dump(); | 315 return rj.dump(); |
279 } | 316 } |
280 | 317 |