Step 4 – Integrate the AudioTrust+ Extractors (~2 hours )  Step 4 – Let’s start again from scratch! (after the third time it’s going to work) 

NOTE: Deleted text means that we did it during the first integration attempt with the old platform versions, due to the limitations of the previous API. Don’t try this at home!


We finally had a proper design, a workflow description, and a RDF annotation model: We were ready to start integrating the components.

During the integration, we could leverage several advantages that the MICO platform v2 has introduced for developers: In comparison to the first version, code is much easier to write and maintain — the sequence of action to be performed is clear, and naming of API functions is straightforward. Moreover, in platform v1 there was no distinction between a new part created, its RDF annotations, and the binary data associated with it, because everything was encapsulated in a single object. This has been significantly improved as well.

The two sections illustrate the big step forward which the project has taken within the final project phase – be sure to check them out… and in any case, please stay tuned for the next blog!

AudioTrust+ meets MICO platform v1 (and gets a huge headache)

This is an example — yet pretty accurate! — source code of the “call” function to be implemented by a MICO extractor compatible with the MICO platform v1. We marked with the keyword “FIXME” every problematic point of the sourcecode.

//FIXME:
//no way of checking if the input wav file is there or not!?
 
// retrieve the content part identified by the object URI
std::shared_ptr<Content> inputContent(ci.getContentPart(object));
 
// check if the URI correspond to a real content part
if(inputContent != nullptr) {
//retrive the  wav file input stream
std::shared_ptr<std::istream> wavInputFile(inputContent->getInputStream());
 
//process the file...
//... using the parameter with a value fixed during the cmd line call!?
//FIXME:
//the parameter should be chosen at runtime!!!
m_detector->process(wavInputFile,outXmlFileName,param1SetupAtStartup);
 
 
//Instantiate an output content part
std::shared_ptr<Content> outputContent(ci.createContentPart());
outputContent->setRelation(DC::creator, getServiceID());
outputContent->setProperty(DC::created, getTimestamp());
 
//FIXME:
//no description of the created part!?
 
//and set its provenance information
outputContent->setRelation(DC::source, object.stringValue());
outputContent->setRelation(DC::provenance, getServiceID());
 
 
//FIXME: 
//overriding the type of the RDF annotation, since it contains our xml file???
outputContent->setType("text/vnd.fhg-audiotamperingdetection-xml");
 
//load output file
std::ifstream iFileStream;
iFileStream.open(outputXmlFileName);
 
//get output stream for the content part
std::shared_ptr<std::ostream> outputStream(outputContent->getOutputStream());
 
//and copy all the content
auto buff = std::vector<char>(std::istreambuf_iterator<char>(iFileStream), std::istreambuf_iterator<char>());
for(uint i = 0;i < buff.size();++i){
(*outputStream) << buff[i];
}
iFileStream.close();
 
//notify broker that we created a new content part
//by calling the callback function passed as argument
resp(ci, txtContent->getURI());
}
else {
//notifying the broker that we failed...
//...by putting the input object URI in the response???
resp(ci, object);
//FIXME:
//how can we tell *what* exactly went wrong??
}
AudioTrust+ meets MICO platform v2

In the following, you can find instead an example source code — once again, pretty accurate! — for the “call” function to be implemented by a MICO extractor compatible with the MICO platform v2:

//retrieve the first input part:
pResource rInputPart = inputResources.front();
 
//check if the input wav file is there:
if(rInputPart ->hasAsset()) {
//retrive the  wav file input stream
std::shared_ptr<std::istream> wavInputFile(rInputPart->getAsset()->getInputStream());
 
//process the file...
//... using the input parameter chosen at runtime!
m_detector->process(wavInputFile,outXmlFileName,inputParams.at("param1"));
 
 
//Instantiate an output content part
pPart      outputPart = item->createPart(mico::persistence::model::URI(getServiceID()));
pResource  rOutputPart = std::dynamic_pointer_cast<Resource>(outputPart);
 
//describe it:
rOutputPart->setSyntacticalType("atp:TamperingDetectionXml");
rOutputPart->setSemanticType("Outcome of audio tampering detection in proprietary format");
 
//and set its provenance information
outputPart->addInput(rInputPart);
 
 
//create an asset for the output part, and set its format: 
pAsset outputAsset = rOutputPart->getAsset();
outputAsset->setFormat("text/vnd.fhg-audiotamperingdetection-xml");
 
//load output file
std::ifstream iFileStream;
iFileStream.open(outputXmlFileName);
 
//get output stream for the content part
std::shared_ptr<std::ostream> outputStream(outputAsset->getOutputStream());
 
//and copy all the content
auto buff = std::vector<char>(std::istreambuf_iterator<char>(iFileStream), std::istreambuf_iterator<char>());
for(uint i = 0;i < buff.size();++i){
(*outputStream) << buff[i];
}
iFileStream.close();
 
//notify broker that we created a new content part
resp.sendNew(item, rOutputPart->getURI());
}
else {
//notifying the broker that we failed, since there was no asset to be processed
resp.sendErrorMessage(item, ErrorCodes::MISSING_ASSET,"AudioTrust+ Detector: MISSING ASSET","No asset found for part at at " + rInputPart->getURI().stringValue());
}
Assessment of the MICO platform API v2

In our opinion, the quality of the code tremendously increased by using the MICO platform v2:

  1. It is more readable, to the point that many of the comments became almost unnecessary
  2. There is a clear distinction between binary data (Asset) and rdf annotations (SemanticType and SyntacticType of the output part)
  3. It is shorter, despite performing more actions than before
  4. We are able to retrieve a runtime input parameter, instead of fixing it during startup
  5. We are able to send a clear error message to the broker, in case of a fatal error

A second aspect, although more difficult to evaluate because we were more familiar with the API than when dealing with earlier platform versions, is that while the first implementation took more than one week, this second attempt only required 2 hours for integration!

We believe this also thanks to the API: Small details, e.g., writing “outputPart->addInput(rInputPart);” instead of “outputPart->setRelation(MMM:HasInput,rInputPart->getURI());” are extremely helpful, not only because the code is shorter, but also — and more importantly — because wrong code is detected at compile time, and simple instruments such as an IDE auto-completion become fully effective.

See you soon for the next blog!

mico-meets-audiotrustplus-logo

« 1, 2, 3, 4, 5, 6, 7 »