in Cthulhu/include/cthulhu/ContextImpl.h [467:588]
MultiTransformer Context::transform(
const std::vector<std::vector<StreamID>>& inputIDs,
const std::vector<std::vector<StreamID>>& outputIDs,
const std::function<void(T&...)>& sampleCallback,
const std::function<bool(U&...)>& configCallback,
MultiTransformerOptions options) const {
// Flatten StreamIDs
std::vector<StreamID> inputIDsFlat;
std::vector<StreamID> outputIDsFlat;
std::vector<unsigned long> groups(inputIDs.size() + outputIDs.size());
for (int groupIdx = 0; groupIdx < groups.size(); ++groupIdx) {
if (groupIdx < inputIDs.size()) {
std::vector<StreamID> inputIDsNS(inputIDs[groupIdx].size());
for (int elemIdx = 0; elemIdx < inputIDs[groupIdx].size(); ++elemIdx) {
inputIDsNS[elemIdx] = applyNamespace(inputIDs[groupIdx][elemIdx]);
}
groups[groupIdx] = inputIDs[groupIdx].size();
inputIDsFlat.insert(inputIDsFlat.end(), inputIDsNS.begin(), inputIDsNS.end());
} else {
int modIdx = groupIdx - inputIDs.size();
std::vector<StreamID> outputIDsNS(outputIDs[modIdx].size());
for (int elemIdx = 0; elemIdx < outputIDs[modIdx].size(); ++elemIdx) {
outputIDsNS[elemIdx] = applyNamespace(outputIDs[modIdx][elemIdx]);
}
groups[groupIdx] = outputIDs[modIdx].size();
outputIDsFlat.insert(outputIDsFlat.end(), outputIDsNS.begin(), outputIDsNS.end());
}
}
// Get Types
std::vector<uint32_t> allTypes(inputIDsFlat.size() + outputIDsFlat.size(), 0);
details::SampleTypesDynamic<T...>::getTypes(groups, 0, 0, allTypes);
std::vector<bool> basicStreams(allTypes.size());
for (size_t i = 0; i < basicStreams.size(); ++i) {
auto type = Framework::instance().typeRegistry()->findTypeID(allTypes[i]);
if (!type) {
auto str = "Attempted to lookup unregistered typeID: " + std::to_string(allTypes[i]);
XR_LOGCE("Cthulhu", "{}", str);
throw std::runtime_error(str);
}
basicStreams[i] = type->isBasic();
}
// Create Aligner
auto aligner = details::alignerFromOptions(options.alignerType, std::move(options.alignerPtr));
// Create Dispatcher
auto dispatcher = std::make_unique<Dispatcher>();
// Create Callbacks and Register in Aligner
std::function<void(
const std::vector<StreamID>&,
const std::vector<StreamSample>&,
std::vector<StreamSample>&,
T&...)>
callbackAppended = [sampleCallback](
const std::vector<StreamID>&,
const std::vector<StreamSample>&,
std::vector<StreamSample>&,
T&... args) -> void { sampleCallback(args...); };
AlignerSampleCallback cb = details::generateAlignerCallback<0>(
dispatcher.get(), 0, 0, inputIDsFlat, outputIDsFlat, groups, callbackAppended);
aligner->setCallback(cb);
if (configCallback != nullptr) {
std::function<bool(const std::vector<StreamConfig>&, std::vector<StreamConfig>&, U&...)>
configCallbackAppended = [configCallback](
const std::vector<StreamConfig>&,
std::vector<StreamConfig>&,
U&... args) -> bool { return configCallback(args...); };
AlignerConfigCallback ccb = details::generateAlignerConfigCallback<0>(
dispatcher.get(), 0, 0, outputIDsFlat.size(), groups, configCallbackAppended, basicStreams);
aligner->setConfigCallback(ccb);
}
// Get Input Streams from Registry and Load into Aligner
std::vector<StreamIDView> inputIDsVec;
inputIDsVec.reserve(inputIDsFlat.size());
std::vector<StreamIDView> outputIDsVec;
outputIDsVec.reserve(outputIDsFlat.size());
for (unsigned long i = 0; i < inputIDsFlat.size(); i++) {
StreamDescription desc{inputIDsFlat[i], allTypes[i]};
auto si = Framework::instance().streamRegistry()->registerStream(desc);
if (allTypes[i] != si->description().type()) {
// Type mismatch detected
XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", allTypes[i], si->description().type());
return MultiTransformer(inputIDsVec, outputIDsVec);
}
inputIDsVec.push_back(StreamIDView(si->description().id()));
aligner->registerConsumer(si, i);
}
// Get Output Streams from Registry and Load into Dispatcher
for (unsigned long i = 0; i < outputIDsFlat.size(); i++) {
StreamDescription desc{outputIDsFlat[i], allTypes[i + inputIDsFlat.size()]};
auto si = Framework::instance().streamRegistry()->registerStream(desc);
if (allTypes[i + inputIDsFlat.size()] != si->description().type()) {
// Type mismatch detected
XR_LOGCW(
"Cthulhu",
"Out Type mismatch detected [{}, {}]",
allTypes[i + inputIDsFlat.size()],
si->description().type());
return MultiTransformer(inputIDsVec, outputIDsVec);
}
outputIDsVec.push_back(StreamIDView(si->description().id()));
dispatcher->registerProducer(si);
}
aligner->finalize();
// Return Node
if (ctx_ == nullptr) {
const auto err = "Attempted to register multi transformer against null context";
XR_LOGCE("Cthulhu", "{}", err);
throw std::runtime_error(err);
}
ctx_->registerTransformer(inputIDsVec, outputIDsVec);
return MultiTransformer(inputIDsVec, outputIDsVec, std::move(aligner), std::move(dispatcher));
};