/**
 * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
 *
 * Do not edit this file as changes may cause incorrect behavior and will be lost
 * once the code is regenerated.
 *
 * @generated by codegen project: GenerateModuleH.js
 */

#pragma once

#include <ReactCommon/TurboModule.h>
#include <react/bridging/Bridging.h>

namespace facebook::react {


  
#pragma mark - NativeOpentokArchiveEvent

template <typename P0, typename P1, typename P2>
struct NativeOpentokArchiveEvent {
  P0 archiveId;
  P1 name;
  P2 sessionId;
  bool operator==(const NativeOpentokArchiveEvent &other) const {
    return archiveId == other.archiveId && name == other.name && sessionId == other.sessionId;
  }
};

template <typename T>
struct NativeOpentokArchiveEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.archiveId)>(rt, value.getProperty(rt, "archiveId"), jsInvoker),
      bridging::fromJs<decltype(types.name)>(rt, value.getProperty(rt, "name"), jsInvoker),
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String archiveIdToJs(jsi::Runtime &rt, decltype(types.archiveId) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "archiveId", bridging::toJs(rt, value.archiveId, jsInvoker));
    result.setProperty(rt, "name", bridging::toJs(rt, value.name, jsInvoker));
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokConnection

template <typename P0, typename P1, typename P2>
struct NativeOpentokConnection {
  P0 creationTime;
  P1 data;
  P2 connectionId;
  bool operator==(const NativeOpentokConnection &other) const {
    return creationTime == other.creationTime && data == other.data && connectionId == other.connectionId;
  }
};

template <typename T>
struct NativeOpentokConnectionBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.creationTime)>(rt, value.getProperty(rt, "creationTime"), jsInvoker),
      bridging::fromJs<decltype(types.data)>(rt, value.getProperty(rt, "data"), jsInvoker),
      bridging::fromJs<decltype(types.connectionId)>(rt, value.getProperty(rt, "connectionId"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String creationTimeToJs(jsi::Runtime &rt, decltype(types.creationTime) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String dataToJs(jsi::Runtime &rt, decltype(types.data) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String connectionIdToJs(jsi::Runtime &rt, decltype(types.connectionId) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "creationTime", bridging::toJs(rt, value.creationTime, jsInvoker));
    result.setProperty(rt, "data", bridging::toJs(rt, value.data, jsInvoker));
    result.setProperty(rt, "connectionId", bridging::toJs(rt, value.connectionId, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokConnectionEvent

template <typename P0, typename P1, typename P2, typename P3>
struct NativeOpentokConnectionEvent {
  P0 creationTime;
  P1 data;
  P2 connectionId;
  P3 sessionId;
  bool operator==(const NativeOpentokConnectionEvent &other) const {
    return creationTime == other.creationTime && data == other.data && connectionId == other.connectionId && sessionId == other.sessionId;
  }
};

template <typename T>
struct NativeOpentokConnectionEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.creationTime)>(rt, value.getProperty(rt, "creationTime"), jsInvoker),
      bridging::fromJs<decltype(types.data)>(rt, value.getProperty(rt, "data"), jsInvoker),
      bridging::fromJs<decltype(types.connectionId)>(rt, value.getProperty(rt, "connectionId"), jsInvoker),
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String creationTimeToJs(jsi::Runtime &rt, decltype(types.creationTime) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String dataToJs(jsi::Runtime &rt, decltype(types.data) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String connectionIdToJs(jsi::Runtime &rt, decltype(types.connectionId) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "creationTime", bridging::toJs(rt, value.creationTime, jsInvoker));
    result.setProperty(rt, "data", bridging::toJs(rt, value.data, jsInvoker));
    result.setProperty(rt, "connectionId", bridging::toJs(rt, value.connectionId, jsInvoker));
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    return result;
  }
};




#pragma mark - NativeOpentokIceConfig

template <typename P0, typename P1, typename P2, typename P3>
struct NativeOpentokIceConfig {
  P0 includeServers;
  P1 transportPolicy;
  P2 filterOutLanCandidates;
  P3 customServers;
  bool operator==(const NativeOpentokIceConfig &other) const {
    return includeServers == other.includeServers && transportPolicy == other.transportPolicy && filterOutLanCandidates == other.filterOutLanCandidates && customServers == other.customServers;
  }
};

template <typename T>
struct NativeOpentokIceConfigBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.includeServers)>(rt, value.getProperty(rt, "includeServers"), jsInvoker),
      bridging::fromJs<decltype(types.transportPolicy)>(rt, value.getProperty(rt, "transportPolicy"), jsInvoker),
      bridging::fromJs<decltype(types.filterOutLanCandidates)>(rt, value.getProperty(rt, "filterOutLanCandidates"), jsInvoker),
      bridging::fromJs<decltype(types.customServers)>(rt, value.getProperty(rt, "customServers"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String includeServersToJs(jsi::Runtime &rt, decltype(types.includeServers) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String transportPolicyToJs(jsi::Runtime &rt, decltype(types.transportPolicy) value) {
    return bridging::toJs(rt, value);
  }

  static bool filterOutLanCandidatesToJs(jsi::Runtime &rt, decltype(types.filterOutLanCandidates) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Array customServersToJs(jsi::Runtime &rt, decltype(types.customServers) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "includeServers", bridging::toJs(rt, value.includeServers, jsInvoker));
    result.setProperty(rt, "transportPolicy", bridging::toJs(rt, value.transportPolicy, jsInvoker));
    result.setProperty(rt, "filterOutLanCandidates", bridging::toJs(rt, value.filterOutLanCandidates, jsInvoker));
    result.setProperty(rt, "customServers", bridging::toJs(rt, value.customServers, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokMuteForcedEvent

template <typename P0>
struct NativeOpentokMuteForcedEvent {
  P0 active;
  bool operator==(const NativeOpentokMuteForcedEvent &other) const {
    return active == other.active;
  }
};

template <typename T>
struct NativeOpentokMuteForcedEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.active)>(rt, value.getProperty(rt, "active"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static bool activeToJs(jsi::Runtime &rt, decltype(types.active) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "active", bridging::toJs(rt, value.active, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokSessionConnectEvent

template <typename P0, typename P1>
struct NativeOpentokSessionConnectEvent {
  P0 sessionId;
  P1 connection;
  bool operator==(const NativeOpentokSessionConnectEvent &other) const {
    return sessionId == other.sessionId && connection == other.connection;
  }
};

template <typename T>
struct NativeOpentokSessionConnectEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker),
      bridging::fromJs<decltype(types.connection)>(rt, value.getProperty(rt, "connection"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Object connectionToJs(jsi::Runtime &rt, decltype(types.connection) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    result.setProperty(rt, "connection", bridging::toJs(rt, value.connection, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokSessionDisconnectEvent

template <typename P0>
struct NativeOpentokSessionDisconnectEvent {
  P0 sessionId;
  bool operator==(const NativeOpentokSessionDisconnectEvent &other) const {
    return sessionId == other.sessionId;
  }
};

template <typename T>
struct NativeOpentokSessionDisconnectEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokSessionErrorEvent

template <typename P0, typename P1>
struct NativeOpentokSessionErrorEvent {
  P0 code;
  P1 message;
  bool operator==(const NativeOpentokSessionErrorEvent &other) const {
    return code == other.code && message == other.message;
  }
};

template <typename T>
struct NativeOpentokSessionErrorEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.code)>(rt, value.getProperty(rt, "code"), jsInvoker),
      bridging::fromJs<decltype(types.message)>(rt, value.getProperty(rt, "message"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String codeToJs(jsi::Runtime &rt, decltype(types.code) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String messageToJs(jsi::Runtime &rt, decltype(types.message) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "code", bridging::toJs(rt, value.code, jsInvoker));
    result.setProperty(rt, "message", bridging::toJs(rt, value.message, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokSessionOptions

template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
struct NativeOpentokSessionOptions {
  P0 androidZOrder;
  P1 apiUrl;
  P2 connectionEventsSuppressed;
  P3 enableStereoOutput;
  P4 enableSinglePeerConnection;
  P5 sessionMigration;
  P6 iceConfig;
  P7 ipWhitelist;
  P8 isCamera2Capable;
  P9 proxyUrl;
  P10 useTextureViews;
  bool operator==(const NativeOpentokSessionOptions &other) const {
    return androidZOrder == other.androidZOrder && apiUrl == other.apiUrl && connectionEventsSuppressed == other.connectionEventsSuppressed && enableStereoOutput == other.enableStereoOutput && enableSinglePeerConnection == other.enableSinglePeerConnection && sessionMigration == other.sessionMigration && iceConfig == other.iceConfig && ipWhitelist == other.ipWhitelist && isCamera2Capable == other.isCamera2Capable && proxyUrl == other.proxyUrl && useTextureViews == other.useTextureViews;
  }
};

template <typename T>
struct NativeOpentokSessionOptionsBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.androidZOrder)>(rt, value.getProperty(rt, "androidZOrder"), jsInvoker),
      bridging::fromJs<decltype(types.apiUrl)>(rt, value.getProperty(rt, "apiUrl"), jsInvoker),
      bridging::fromJs<decltype(types.connectionEventsSuppressed)>(rt, value.getProperty(rt, "connectionEventsSuppressed"), jsInvoker),
      bridging::fromJs<decltype(types.enableStereoOutput)>(rt, value.getProperty(rt, "enableStereoOutput"), jsInvoker),
      bridging::fromJs<decltype(types.enableSinglePeerConnection)>(rt, value.getProperty(rt, "enableSinglePeerConnection"), jsInvoker),
      bridging::fromJs<decltype(types.sessionMigration)>(rt, value.getProperty(rt, "sessionMigration"), jsInvoker),
      bridging::fromJs<decltype(types.iceConfig)>(rt, value.getProperty(rt, "iceConfig"), jsInvoker),
      bridging::fromJs<decltype(types.ipWhitelist)>(rt, value.getProperty(rt, "ipWhitelist"), jsInvoker),
      bridging::fromJs<decltype(types.isCamera2Capable)>(rt, value.getProperty(rt, "isCamera2Capable"), jsInvoker),
      bridging::fromJs<decltype(types.proxyUrl)>(rt, value.getProperty(rt, "proxyUrl"), jsInvoker),
      bridging::fromJs<decltype(types.useTextureViews)>(rt, value.getProperty(rt, "useTextureViews"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String androidZOrderToJs(jsi::Runtime &rt, decltype(types.androidZOrder) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String apiUrlToJs(jsi::Runtime &rt, decltype(types.apiUrl) value) {
    return bridging::toJs(rt, value);
  }

  static bool connectionEventsSuppressedToJs(jsi::Runtime &rt, decltype(types.connectionEventsSuppressed) value) {
    return bridging::toJs(rt, value);
  }

  static bool enableStereoOutputToJs(jsi::Runtime &rt, decltype(types.enableStereoOutput) value) {
    return bridging::toJs(rt, value);
  }

  static bool enableSinglePeerConnectionToJs(jsi::Runtime &rt, decltype(types.enableSinglePeerConnection) value) {
    return bridging::toJs(rt, value);
  }

  static bool sessionMigrationToJs(jsi::Runtime &rt, decltype(types.sessionMigration) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Object iceConfigToJs(jsi::Runtime &rt, decltype(types.iceConfig) value) {
    return bridging::toJs(rt, value);
  }

  static bool ipWhitelistToJs(jsi::Runtime &rt, decltype(types.ipWhitelist) value) {
    return bridging::toJs(rt, value);
  }

  static bool isCamera2CapableToJs(jsi::Runtime &rt, decltype(types.isCamera2Capable) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String proxyUrlToJs(jsi::Runtime &rt, decltype(types.proxyUrl) value) {
    return bridging::toJs(rt, value);
  }

  static bool useTextureViewsToJs(jsi::Runtime &rt, decltype(types.useTextureViews) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    if (value.androidZOrder) {
      result.setProperty(rt, "androidZOrder", bridging::toJs(rt, value.androidZOrder.value(), jsInvoker));
    }
    if (value.apiUrl) {
      result.setProperty(rt, "apiUrl", bridging::toJs(rt, value.apiUrl.value(), jsInvoker));
    }
    if (value.connectionEventsSuppressed) {
      result.setProperty(rt, "connectionEventsSuppressed", bridging::toJs(rt, value.connectionEventsSuppressed.value(), jsInvoker));
    }
    if (value.enableStereoOutput) {
      result.setProperty(rt, "enableStereoOutput", bridging::toJs(rt, value.enableStereoOutput.value(), jsInvoker));
    }
    if (value.enableSinglePeerConnection) {
      result.setProperty(rt, "enableSinglePeerConnection", bridging::toJs(rt, value.enableSinglePeerConnection.value(), jsInvoker));
    }
    if (value.sessionMigration) {
      result.setProperty(rt, "sessionMigration", bridging::toJs(rt, value.sessionMigration.value(), jsInvoker));
    }
    if (value.iceConfig) {
      result.setProperty(rt, "iceConfig", bridging::toJs(rt, value.iceConfig.value(), jsInvoker));
    }
    if (value.ipWhitelist) {
      result.setProperty(rt, "ipWhitelist", bridging::toJs(rt, value.ipWhitelist.value(), jsInvoker));
    }
    if (value.isCamera2Capable) {
      result.setProperty(rt, "isCamera2Capable", bridging::toJs(rt, value.isCamera2Capable.value(), jsInvoker));
    }
    if (value.proxyUrl) {
      result.setProperty(rt, "proxyUrl", bridging::toJs(rt, value.proxyUrl.value(), jsInvoker));
    }
    if (value.useTextureViews) {
      result.setProperty(rt, "useTextureViews", bridging::toJs(rt, value.useTextureViews.value(), jsInvoker));
    }
    return result;
  }
};



#pragma mark - NativeOpentokSignalEvent

template <typename P0, typename P1, typename P2, typename P3>
struct NativeOpentokSignalEvent {
  P0 sessionId;
  P1 connectionId;
  P2 type;
  P3 data;
  bool operator==(const NativeOpentokSignalEvent &other) const {
    return sessionId == other.sessionId && connectionId == other.connectionId && type == other.type && data == other.data;
  }
};

template <typename T>
struct NativeOpentokSignalEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker),
      bridging::fromJs<decltype(types.connectionId)>(rt, value.getProperty(rt, "connectionId"), jsInvoker),
      bridging::fromJs<decltype(types.type)>(rt, value.getProperty(rt, "type"), jsInvoker),
      bridging::fromJs<decltype(types.data)>(rt, value.getProperty(rt, "data"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String connectionIdToJs(jsi::Runtime &rt, decltype(types.connectionId) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String typeToJs(jsi::Runtime &rt, decltype(types.type) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String dataToJs(jsi::Runtime &rt, decltype(types.data) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    result.setProperty(rt, "connectionId", bridging::toJs(rt, value.connectionId, jsInvoker));
    result.setProperty(rt, "type", bridging::toJs(rt, value.type, jsInvoker));
    result.setProperty(rt, "data", bridging::toJs(rt, value.data, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokStream

template <typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
struct NativeOpentokStream {
  P0 name;
  P1 streamId;
  P2 hasAudio;
  P3 hasCaptions;
  P4 hasVideo;
  P5 sessionId;
  P6 width;
  P7 height;
  P8 videoType;
  P9 connection;
  P10 creationTime;
  bool operator==(const NativeOpentokStream &other) const {
    return name == other.name && streamId == other.streamId && hasAudio == other.hasAudio && hasCaptions == other.hasCaptions && hasVideo == other.hasVideo && sessionId == other.sessionId && width == other.width && height == other.height && videoType == other.videoType && connection == other.connection && creationTime == other.creationTime;
  }
};

template <typename T>
struct NativeOpentokStreamBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.name)>(rt, value.getProperty(rt, "name"), jsInvoker),
      bridging::fromJs<decltype(types.streamId)>(rt, value.getProperty(rt, "streamId"), jsInvoker),
      bridging::fromJs<decltype(types.hasAudio)>(rt, value.getProperty(rt, "hasAudio"), jsInvoker),
      bridging::fromJs<decltype(types.hasCaptions)>(rt, value.getProperty(rt, "hasCaptions"), jsInvoker),
      bridging::fromJs<decltype(types.hasVideo)>(rt, value.getProperty(rt, "hasVideo"), jsInvoker),
      bridging::fromJs<decltype(types.sessionId)>(rt, value.getProperty(rt, "sessionId"), jsInvoker),
      bridging::fromJs<decltype(types.width)>(rt, value.getProperty(rt, "width"), jsInvoker),
      bridging::fromJs<decltype(types.height)>(rt, value.getProperty(rt, "height"), jsInvoker),
      bridging::fromJs<decltype(types.videoType)>(rt, value.getProperty(rt, "videoType"), jsInvoker),
      bridging::fromJs<decltype(types.connection)>(rt, value.getProperty(rt, "connection"), jsInvoker),
      bridging::fromJs<decltype(types.creationTime)>(rt, value.getProperty(rt, "creationTime"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String streamIdToJs(jsi::Runtime &rt, decltype(types.streamId) value) {
    return bridging::toJs(rt, value);
  }

  static bool hasAudioToJs(jsi::Runtime &rt, decltype(types.hasAudio) value) {
    return bridging::toJs(rt, value);
  }

  static bool hasCaptionsToJs(jsi::Runtime &rt, decltype(types.hasCaptions) value) {
    return bridging::toJs(rt, value);
  }

  static bool hasVideoToJs(jsi::Runtime &rt, decltype(types.hasVideo) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String sessionIdToJs(jsi::Runtime &rt, decltype(types.sessionId) value) {
    return bridging::toJs(rt, value);
  }

  static double widthToJs(jsi::Runtime &rt, decltype(types.width) value) {
    return bridging::toJs(rt, value);
  }

  static double heightToJs(jsi::Runtime &rt, decltype(types.height) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String videoTypeToJs(jsi::Runtime &rt, decltype(types.videoType) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Object connectionToJs(jsi::Runtime &rt, decltype(types.connection) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String creationTimeToJs(jsi::Runtime &rt, decltype(types.creationTime) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "name", bridging::toJs(rt, value.name, jsInvoker));
    result.setProperty(rt, "streamId", bridging::toJs(rt, value.streamId, jsInvoker));
    result.setProperty(rt, "hasAudio", bridging::toJs(rt, value.hasAudio, jsInvoker));
    result.setProperty(rt, "hasCaptions", bridging::toJs(rt, value.hasCaptions, jsInvoker));
    result.setProperty(rt, "hasVideo", bridging::toJs(rt, value.hasVideo, jsInvoker));
    result.setProperty(rt, "sessionId", bridging::toJs(rt, value.sessionId, jsInvoker));
    result.setProperty(rt, "width", bridging::toJs(rt, value.width, jsInvoker));
    result.setProperty(rt, "height", bridging::toJs(rt, value.height, jsInvoker));
    result.setProperty(rt, "videoType", bridging::toJs(rt, value.videoType, jsInvoker));
    result.setProperty(rt, "connection", bridging::toJs(rt, value.connection, jsInvoker));
    result.setProperty(rt, "creationTime", bridging::toJs(rt, value.creationTime, jsInvoker));
    return result;
  }
};



#pragma mark - NativeOpentokStreamPropertyChangedEvent

template <typename P0, typename P1, typename P2, typename P3>
struct NativeOpentokStreamPropertyChangedEvent {
  P0 oldValue;
  P1 newValue;
  P2 stream;
  P3 changedProperty;
  bool operator==(const NativeOpentokStreamPropertyChangedEvent &other) const {
    return oldValue == other.oldValue && newValue == other.newValue && stream == other.stream && changedProperty == other.changedProperty;
  }
};

template <typename T>
struct NativeOpentokStreamPropertyChangedEventBridging {
  static T types;

  static T fromJs(
      jsi::Runtime &rt,
      const jsi::Object &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    T result{
      bridging::fromJs<decltype(types.oldValue)>(rt, value.getProperty(rt, "oldValue"), jsInvoker),
      bridging::fromJs<decltype(types.newValue)>(rt, value.getProperty(rt, "newValue"), jsInvoker),
      bridging::fromJs<decltype(types.stream)>(rt, value.getProperty(rt, "stream"), jsInvoker),
      bridging::fromJs<decltype(types.changedProperty)>(rt, value.getProperty(rt, "changedProperty"), jsInvoker)};
    return result;
  }

#ifdef DEBUG
  static jsi::Object oldValueToJs(jsi::Runtime &rt, decltype(types.oldValue) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Object newValueToJs(jsi::Runtime &rt, decltype(types.newValue) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::Object streamToJs(jsi::Runtime &rt, decltype(types.stream) value) {
    return bridging::toJs(rt, value);
  }

  static jsi::String changedPropertyToJs(jsi::Runtime &rt, decltype(types.changedProperty) value) {
    return bridging::toJs(rt, value);
  }
#endif

  static jsi::Object toJs(
      jsi::Runtime &rt,
      const T &value,
      const std::shared_ptr<CallInvoker> &jsInvoker) {
    auto result = facebook::jsi::Object(rt);
    result.setProperty(rt, "oldValue", bridging::toJs(rt, value.oldValue, jsInvoker));
    result.setProperty(rt, "newValue", bridging::toJs(rt, value.newValue, jsInvoker));
    result.setProperty(rt, "stream", bridging::toJs(rt, value.stream, jsInvoker));
    result.setProperty(rt, "changedProperty", bridging::toJs(rt, value.changedProperty, jsInvoker));
    return result;
  }
};

class JSI_EXPORT NativeOpentokCxxSpecJSI : public TurboModule {
protected:
  NativeOpentokCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);

public:
  virtual void initSession(jsi::Runtime &rt, jsi::String apiKey, jsi::String sessionId, std::optional<jsi::Object> options) = 0;
  virtual jsi::Value connect(jsi::Runtime &rt, jsi::String sessionId, jsi::String token) = 0;
  virtual jsi::Value disconnect(jsi::Runtime &rt, jsi::String sessionId) = 0;
  virtual void getSubscriberRtcStatsReport(jsi::Runtime &rt, jsi::String sessionId) = 0;
  virtual void getPublisherRtcStatsReport(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) = 0;
  virtual void setAudioTransformers(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId, jsi::Array transformers) = 0;
  virtual void setVideoTransformers(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId, jsi::Array transformers) = 0;
  virtual void publish(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) = 0;
  virtual void unpublish(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) = 0;
  virtual void removeSubscriber(jsi::Runtime &rt, jsi::String sessionId, jsi::String streamId) = 0;
  virtual void sendSignal(jsi::Runtime &rt, jsi::String sessionId, jsi::String type, jsi::String data, jsi::String to) = 0;
  virtual jsi::Value setEncryptionSecret(jsi::Runtime &rt, jsi::String sessionId, jsi::String secret) = 0;
  virtual jsi::Value getCapabilities(jsi::Runtime &rt, jsi::String sessionId) = 0;
  virtual jsi::Value reportIssue(jsi::Runtime &rt, jsi::String sessionId) = 0;
  virtual jsi::Value forceMuteAll(jsi::Runtime &rt, jsi::String sessionId, jsi::Array excludedStreamIds) = 0;
  virtual jsi::Value forceMuteStream(jsi::Runtime &rt, jsi::String sessionId, jsi::String streamId) = 0;
  virtual jsi::Value forceDisconnect(jsi::Runtime &rt, jsi::String sessionId, jsi::String connectionId) = 0;
  virtual jsi::Value disableForceMute(jsi::Runtime &rt, jsi::String sessionId) = 0;

};

template <typename T>
class JSI_EXPORT NativeOpentokCxxSpec : public TurboModule {
public:
  jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override {
    return delegate_.create(rt, propName);
  }

  std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& runtime) override {
    return delegate_.getPropertyNames(runtime);
  }

  static constexpr std::string_view kModuleName = "OpentokReactNative";

protected:
  NativeOpentokCxxSpec(std::shared_ptr<CallInvoker> jsInvoker)
    : TurboModule(std::string{NativeOpentokCxxSpec::kModuleName}, jsInvoker),
      delegate_(reinterpret_cast<T*>(this), jsInvoker) {}

  template <typename OnArchiveStartedType> void emitOnArchiveStarted(OnArchiveStartedType value) {
    static_assert(bridging::supportsFromJs<OnArchiveStartedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onArchiveStarted"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnArchiveStoppedType> void emitOnArchiveStopped(OnArchiveStoppedType value) {
    static_assert(bridging::supportsFromJs<OnArchiveStoppedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onArchiveStopped"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnConnectionCreatedType> void emitOnConnectionCreated(OnConnectionCreatedType value) {
    static_assert(bridging::supportsFromJs<OnConnectionCreatedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onConnectionCreated"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnConnectionDestroyedType> void emitOnConnectionDestroyed(OnConnectionDestroyedType value) {
    static_assert(bridging::supportsFromJs<OnConnectionDestroyedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onConnectionDestroyed"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnMuteForcedType> void emitOnMuteForced(OnMuteForcedType value) {
    static_assert(bridging::supportsFromJs<OnMuteForcedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onMuteForced"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSessionConnectedType> void emitOnSessionConnected(OnSessionConnectedType value) {
    static_assert(bridging::supportsFromJs<OnSessionConnectedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSessionConnected"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSessionDisconnectedType> void emitOnSessionDisconnected(OnSessionDisconnectedType value) {
    static_assert(bridging::supportsFromJs<OnSessionDisconnectedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSessionDisconnected"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSessionReconnectingType> void emitOnSessionReconnecting(OnSessionReconnectingType value) {
    static_assert(bridging::supportsFromJs<OnSessionReconnectingType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSessionReconnecting"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSessionReconnectedType> void emitOnSessionReconnected(OnSessionReconnectedType value) {
    static_assert(bridging::supportsFromJs<OnSessionReconnectedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSessionReconnected"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnStreamCreatedType> void emitOnStreamCreated(OnStreamCreatedType value) {
    static_assert(bridging::supportsFromJs<OnStreamCreatedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onStreamCreated"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnStreamDestroyedType> void emitOnStreamDestroyed(OnStreamDestroyedType value) {
    static_assert(bridging::supportsFromJs<OnStreamDestroyedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onStreamDestroyed"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnStreamPropertyChangedType> void emitOnStreamPropertyChanged(OnStreamPropertyChangedType value) {
    static_assert(bridging::supportsFromJs<OnStreamPropertyChangedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onStreamPropertyChanged"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSignalReceivedType> void emitOnSignalReceived(OnSignalReceivedType value) {
    static_assert(bridging::supportsFromJs<OnSignalReceivedType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSignalReceived"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

  template <typename OnSessionErrorType> void emitOnSessionError(OnSessionErrorType value) {
    static_assert(bridging::supportsFromJs<OnSessionErrorType, jsi::Object>, "value cannnot be converted to jsi::Object");
    static_cast<AsyncEventEmitter<jsi::Value>&>(*delegate_.eventEmitterMap_["onSessionError"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
      return bridging::toJs(rt, eventValue, jsInvoker);
    });
  }

private:
  class Delegate : public NativeOpentokCxxSpecJSI {
  public:
    Delegate(T *instance, std::shared_ptr<CallInvoker> jsInvoker) :
      NativeOpentokCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {
      eventEmitterMap_["onArchiveStarted"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onArchiveStopped"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onConnectionCreated"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onConnectionDestroyed"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onMuteForced"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSessionConnected"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSessionDisconnected"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSessionReconnecting"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSessionReconnected"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onStreamCreated"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onStreamDestroyed"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onStreamPropertyChanged"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSignalReceived"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
      eventEmitterMap_["onSessionError"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
    }

    void initSession(jsi::Runtime &rt, jsi::String apiKey, jsi::String sessionId, std::optional<jsi::Object> options) override {
      static_assert(
          bridging::getParameterCount(&T::initSession) == 4,
          "Expected initSession(...) to have 4 parameters");

      return bridging::callFromJs<void>(
          rt, &T::initSession, jsInvoker_, instance_, std::move(apiKey), std::move(sessionId), std::move(options));
    }
    jsi::Value connect(jsi::Runtime &rt, jsi::String sessionId, jsi::String token) override {
      static_assert(
          bridging::getParameterCount(&T::connect) == 3,
          "Expected connect(...) to have 3 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::connect, jsInvoker_, instance_, std::move(sessionId), std::move(token));
    }
    jsi::Value disconnect(jsi::Runtime &rt, jsi::String sessionId) override {
      static_assert(
          bridging::getParameterCount(&T::disconnect) == 2,
          "Expected disconnect(...) to have 2 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::disconnect, jsInvoker_, instance_, std::move(sessionId));
    }
    void getSubscriberRtcStatsReport(jsi::Runtime &rt, jsi::String sessionId) override {
      static_assert(
          bridging::getParameterCount(&T::getSubscriberRtcStatsReport) == 2,
          "Expected getSubscriberRtcStatsReport(...) to have 2 parameters");

      return bridging::callFromJs<void>(
          rt, &T::getSubscriberRtcStatsReport, jsInvoker_, instance_, std::move(sessionId));
    }
    void getPublisherRtcStatsReport(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) override {
      static_assert(
          bridging::getParameterCount(&T::getPublisherRtcStatsReport) == 3,
          "Expected getPublisherRtcStatsReport(...) to have 3 parameters");

      return bridging::callFromJs<void>(
          rt, &T::getPublisherRtcStatsReport, jsInvoker_, instance_, std::move(sessionId), std::move(publisherId));
    }
    void setAudioTransformers(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId, jsi::Array transformers) override {
      static_assert(
          bridging::getParameterCount(&T::setAudioTransformers) == 4,
          "Expected setAudioTransformers(...) to have 4 parameters");

      return bridging::callFromJs<void>(
          rt, &T::setAudioTransformers, jsInvoker_, instance_, std::move(sessionId), std::move(publisherId), std::move(transformers));
    }
    void setVideoTransformers(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId, jsi::Array transformers) override {
      static_assert(
          bridging::getParameterCount(&T::setVideoTransformers) == 4,
          "Expected setVideoTransformers(...) to have 4 parameters");

      return bridging::callFromJs<void>(
          rt, &T::setVideoTransformers, jsInvoker_, instance_, std::move(sessionId), std::move(publisherId), std::move(transformers));
    }
    void publish(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) override {
      static_assert(
          bridging::getParameterCount(&T::publish) == 3,
          "Expected publish(...) to have 3 parameters");

      return bridging::callFromJs<void>(
          rt, &T::publish, jsInvoker_, instance_, std::move(sessionId), std::move(publisherId));
    }
    void unpublish(jsi::Runtime &rt, jsi::String sessionId, jsi::String publisherId) override {
      static_assert(
          bridging::getParameterCount(&T::unpublish) == 3,
          "Expected unpublish(...) to have 3 parameters");

      return bridging::callFromJs<void>(
          rt, &T::unpublish, jsInvoker_, instance_, std::move(sessionId), std::move(publisherId));
    }
    void removeSubscriber(jsi::Runtime &rt, jsi::String sessionId, jsi::String streamId) override {
      static_assert(
          bridging::getParameterCount(&T::removeSubscriber) == 3,
          "Expected removeSubscriber(...) to have 3 parameters");

      return bridging::callFromJs<void>(
          rt, &T::removeSubscriber, jsInvoker_, instance_, std::move(sessionId), std::move(streamId));
    }
    void sendSignal(jsi::Runtime &rt, jsi::String sessionId, jsi::String type, jsi::String data, jsi::String to) override {
      static_assert(
          bridging::getParameterCount(&T::sendSignal) == 5,
          "Expected sendSignal(...) to have 5 parameters");

      return bridging::callFromJs<void>(
          rt, &T::sendSignal, jsInvoker_, instance_, std::move(sessionId), std::move(type), std::move(data), std::move(to));
    }
    jsi::Value setEncryptionSecret(jsi::Runtime &rt, jsi::String sessionId, jsi::String secret) override {
      static_assert(
          bridging::getParameterCount(&T::setEncryptionSecret) == 3,
          "Expected setEncryptionSecret(...) to have 3 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::setEncryptionSecret, jsInvoker_, instance_, std::move(sessionId), std::move(secret));
    }
    jsi::Value getCapabilities(jsi::Runtime &rt, jsi::String sessionId) override {
      static_assert(
          bridging::getParameterCount(&T::getCapabilities) == 2,
          "Expected getCapabilities(...) to have 2 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::getCapabilities, jsInvoker_, instance_, std::move(sessionId));
    }
    jsi::Value reportIssue(jsi::Runtime &rt, jsi::String sessionId) override {
      static_assert(
          bridging::getParameterCount(&T::reportIssue) == 2,
          "Expected reportIssue(...) to have 2 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::reportIssue, jsInvoker_, instance_, std::move(sessionId));
    }
    jsi::Value forceMuteAll(jsi::Runtime &rt, jsi::String sessionId, jsi::Array excludedStreamIds) override {
      static_assert(
          bridging::getParameterCount(&T::forceMuteAll) == 3,
          "Expected forceMuteAll(...) to have 3 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::forceMuteAll, jsInvoker_, instance_, std::move(sessionId), std::move(excludedStreamIds));
    }
    jsi::Value forceMuteStream(jsi::Runtime &rt, jsi::String sessionId, jsi::String streamId) override {
      static_assert(
          bridging::getParameterCount(&T::forceMuteStream) == 3,
          "Expected forceMuteStream(...) to have 3 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::forceMuteStream, jsInvoker_, instance_, std::move(sessionId), std::move(streamId));
    }
    jsi::Value forceDisconnect(jsi::Runtime &rt, jsi::String sessionId, jsi::String connectionId) override {
      static_assert(
          bridging::getParameterCount(&T::forceDisconnect) == 3,
          "Expected forceDisconnect(...) to have 3 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::forceDisconnect, jsInvoker_, instance_, std::move(sessionId), std::move(connectionId));
    }
    jsi::Value disableForceMute(jsi::Runtime &rt, jsi::String sessionId) override {
      static_assert(
          bridging::getParameterCount(&T::disableForceMute) == 2,
          "Expected disableForceMute(...) to have 2 parameters");

      return bridging::callFromJs<jsi::Value>(
          rt, &T::disableForceMute, jsInvoker_, instance_, std::move(sessionId));
    }

  private:
    friend class NativeOpentokCxxSpec;
    T *instance_;
  };

  Delegate delegate_;
};

} // namespace facebook::react
