comparison vamp-client/client.cpp @ 84:db9a6ab618bc

Client builds; does not run
author Chris Cannam <c.cannam@qmul.ac.uk>
date Wed, 12 Oct 2016 11:59:57 +0100
parents 154e94ea84d4
children 1b7c11bc5a88
comparison
equal deleted inserted replaced
83:154e94ea84d4 84:db9a6ab618bc
57 delete m_process; 57 delete m_process;
58 } 58 }
59 } 59 }
60 60
61 //!!! obviously, factor out all repetitive guff 61 //!!! obviously, factor out all repetitive guff
62 62
63 Vamp::Plugin * 63 Vamp::Plugin *
64 load(std::string key, float inputSampleRate, int adapterFlags) { 64 load(std::string key, float inputSampleRate, int adapterFlags) {
65 65
66 if (!m_process) { 66 if (!m_process) {
67 throw std::runtime_error("Piper server failed to start"); 67 throw std::runtime_error("Piper server failed to start");
70 Vamp::HostExt::LoadRequest request; 70 Vamp::HostExt::LoadRequest request;
71 request.pluginKey = key; 71 request.pluginKey = key;
72 request.inputSampleRate = inputSampleRate; 72 request.inputSampleRate = inputSampleRate;
73 request.adapterFlags = adapterFlags; 73 request.adapterFlags = adapterFlags;
74 74
75 ::capnp::MallocMessageBuilder message; 75 capnp::MallocMessageBuilder message;
76 RpcRequest::Builder builder = message.initRoot<RpcRequest>(); 76 RpcRequest::Builder builder = message.initRoot<RpcRequest>();
77 77
78 VampnProto::buildRpcRequest_Load(builder, request); 78 VampnProto::buildRpcRequest_Load(builder, request);
79 ReqId id = getId(); 79 ReqId id = getId();
80 builder.getId().setNumber(id); 80 builder.getId().setNumber(id);
81 81
82 auto arr = messageToFlatArray(message); 82 auto arr = messageToFlatArray(message);
83 m_process->write(arr.asChars().begin(), arr.asChars().size()); 83 m_process->write(arr.asChars().begin(), arr.asChars().size());
84 84
85 ///.... read... 85 //!!! ... --> will also need some way to kill this process
86 //!!! (from another thread)
87
88 QByteArray buffer = readResponseBuffer();
89 capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
90 RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
91
92 //!!! handle (explicit) error case
93
94 checkResponseType(reader, RpcResponse::Response::Which::LOAD, id);
95
96 const LoadResponse::Reader &lr = reader.getResponse().getLoad();
97
98 Vamp::HostExt::PluginStaticData psd;
99 Vamp::HostExt::PluginConfiguration defaultConfig;
100 VampnProto::readExtractorStaticData(psd, lr.getStaticData());
101 VampnProto::readConfiguration(defaultConfig, lr.getDefaultConfiguration());
102
103 Vamp::Plugin *plugin = new PiperStubPlugin(this,
104 inputSampleRate,
105 psd,
106 defaultConfig);
107
108 m_mapper.addPlugin(lr.getHandle(), plugin);
109
110 return plugin;
86 }; 111 };
87 112
88 virtual 113 virtual
89 Vamp::Plugin::OutputList 114 Vamp::Plugin::OutputList
90 configure(PiperStubPlugin *plugin, 115 configure(PiperStubPlugin *plugin,
96 121
97 Vamp::HostExt::ConfigurationRequest request; 122 Vamp::HostExt::ConfigurationRequest request;
98 request.plugin = plugin; 123 request.plugin = plugin;
99 request.configuration = config; 124 request.configuration = config;
100 125
101 ::capnp::MallocMessageBuilder message; 126 capnp::MallocMessageBuilder message;
102 RpcRequest::Builder builder = message.initRoot<RpcRequest>(); 127 RpcRequest::Builder builder = message.initRoot<RpcRequest>();
103 128
104 VampnProto::buildRpcRequest_Configure(builder, request, m_mapper); 129 VampnProto::buildRpcRequest_Configure(builder, request, m_mapper);
105 ReqId id = getId(); 130 ReqId id = getId();
106 builder.getId().setNumber(id); 131 builder.getId().setNumber(id);
107 132
108 //!!! now what? 133 auto arr = messageToFlatArray(message);
134 m_process->write(arr.asChars().begin(), arr.asChars().size());
135
136 QByteArray buffer = readResponseBuffer();
137 capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
138 RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
139
140 //!!! handle (explicit) error case
141
142 checkResponseType(reader, RpcResponse::Response::Which::CONFIGURE, id);
143
144 Vamp::HostExt::ConfigurationResponse cr;
145 VampnProto::readConfigurationResponse(cr,
146 reader.getResponse().getConfigure(),
147 m_mapper);
148
149 return cr.outputs;
109 }; 150 };
110
111 151
112 virtual 152 virtual
113 Vamp::Plugin::FeatureSet 153 Vamp::Plugin::FeatureSet
114 process(PiperStubPlugin *plugin, 154 process(PiperStubPlugin *plugin,
115 const float *const *inputBuffers, 155 std::vector<std::vector<float> > inputBuffers,
116 Vamp::RealTime timestamp) = 0; 156 Vamp::RealTime timestamp) {
157
158 if (!m_process) {
159 throw std::runtime_error("Piper server failed to start");
160 }
161
162 Vamp::HostExt::ProcessRequest request;
163 request.plugin = plugin;
164 request.inputBuffers = inputBuffers;
165 request.timestamp = timestamp;
166
167 capnp::MallocMessageBuilder message;
168 RpcRequest::Builder builder = message.initRoot<RpcRequest>();
169
170 VampnProto::buildRpcRequest_Process(builder, request, m_mapper);
171 ReqId id = getId();
172 builder.getId().setNumber(id);
173
174 auto arr = messageToFlatArray(message);
175 m_process->write(arr.asChars().begin(), arr.asChars().size());
176
177 QByteArray buffer = readResponseBuffer();
178 capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
179 RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
180
181 //!!! handle (explicit) error case
182
183 checkResponseType(reader, RpcResponse::Response::Which::PROCESS, id);
184
185 Vamp::HostExt::ProcessResponse pr;
186 VampnProto::readProcessResponse(pr,
187 reader.getResponse().getProcess(),
188 m_mapper);
189
190 return pr.features;
191 }
117 192
118 virtual Vamp::Plugin::FeatureSet 193 virtual Vamp::Plugin::FeatureSet
119 finish(PiperStubPlugin *plugin) = 0; 194 finish(PiperStubPlugin *plugin) {
195
196 if (!m_process) {
197 throw std::runtime_error("Piper server failed to start");
198 }
199
200 Vamp::HostExt::FinishRequest request;
201 request.plugin = plugin;
202
203 capnp::MallocMessageBuilder message;
204 RpcRequest::Builder builder = message.initRoot<RpcRequest>();
205
206 VampnProto::buildRpcRequest_Finish(builder, request, m_mapper);
207 ReqId id = getId();
208 builder.getId().setNumber(id);
209
210 auto arr = messageToFlatArray(message);
211 m_process->write(arr.asChars().begin(), arr.asChars().size());
212
213 QByteArray buffer = readResponseBuffer();
214 capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
215 RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
216
217 //!!! handle (explicit) error case
218
219 checkResponseType(reader, RpcResponse::Response::Which::FINISH, id);
220
221 Vamp::HostExt::ProcessResponse pr;
222 VampnProto::readFinishResponse(pr,
223 reader.getResponse().getFinish(),
224 m_mapper);
225
226 m_mapper.removePlugin(m_mapper.pluginToHandle(plugin));
227 delete plugin;
228
229 return pr.features;
230 }
120 231
121 private: 232 private:
122 QProcess *m_process; 233 QProcess *m_process;
123 AssignedPluginHandleMapper m_mapper; 234 AssignedPluginHandleMapper m_mapper;
124 int getId() { 235 ReqId getId() {
125 //!!! todo: mutex 236 //!!! todo: mutex
126 static ReqId m_nextId = 0; 237 static ReqId m_nextId = 0;
127 return m_nextId++; 238 return m_nextId++;
128 } 239 }
240
241 kj::ArrayPtr<const capnp::word>
242 toArrayPtr(QByteArray arr) {
243 size_t wordSize = sizeof(capnp::word);
244 capnp::word *dptr = reinterpret_cast<capnp::word *>(arr.data());
245 kj::ArrayPtr<const capnp::word> kptr(dptr, arr.size() / wordSize);
246 return kptr;
247 }
248
249 QByteArray
250 readResponseBuffer() {
251
252 QByteArray buffer;
253 size_t wordSize = sizeof(capnp::word);
254 bool complete = false;
255
256 while (!complete) {
257
258 m_process->waitForReadyRead(1000);
259 qint64 byteCount = m_process->bytesAvailable();
260 qint64 wordCount = byteCount / wordSize;
261
262 if (!wordCount) {
263 if (m_process->state() == QProcess::NotRunning) {
264 cerr << "ERROR: Subprocess exited: Load failed" << endl;
265 throw std::runtime_error("Piper server exited unexpectedly");
266 }
267 } else {
268 buffer.append(m_process->read(wordCount * wordSize));
269 size_t haveWords = buffer.size() / wordSize;
270 size_t expectedWords =
271 capnp::expectedSizeInWordsFromPrefix(toArrayPtr(buffer));
272
273 cerr << "haveWords = " << haveWords << ", expectedWords = " << expectedWords << endl;
274
275 if (haveWords >= expectedWords) {
276 if (haveWords > expectedWords) {
277 cerr << "WARNING: obtained more data than expected ("
278 << haveWords << " words, expected " << expectedWords
279 << ")" << endl;
280 }
281 complete = true;
282 }
283 }
284 }
285
286 return buffer;
287 }
288
289 void
290 checkResponseType(const RpcResponse::Reader &r,
291 RpcResponse::Response::Which type,
292 ReqId id) {
293
294 if (r.getResponse().which() != type) {
295 throw std::runtime_error("Wrong response type");
296 }
297 if (ReqId(r.getId().getNumber()) != id) {
298 throw std::runtime_error("Wrong response id");
299 }
300 }
129 }; 301 };
130 302
131 } 303 }
132 304
305 int main(int, char **)
306 {
307 piper::PiperClient client;
308 Vamp::Plugin *plugin = client.load("vamp-example-plugins:zerocrossing", 16, 0);
309 if (!plugin->initialise(1, 4, 4)) {
310 cerr << "initialisation failed" << endl;
311 } else {
312 std::vector<float> buf = { 1.0, -1.0, 1.0, -1.0 };
313 float *bd = buf.data();
314 Vamp::Plugin::FeatureSet features = plugin->process
315 (&bd, Vamp::RealTime::zeroTime);
316 cerr << "results for output 0:" << endl;
317 auto fl(features[0]);
318 for (const auto &f: fl) {
319 cerr << f.values[0] << endl;
320 }
321 }
322 delete plugin;
323 }
324