MultiTransformer Context::transform()

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));
};