/**
 * 连接状态
 */
export type ConnectionState =
  | 'new'
  | 'connecting'
  | 'connected'
  | 'failed'
  | 'disconnected'
  | 'reconnecting'
  | 'not_support'
  | 'limit_exceeded';

/**
 * 云模式
 *
 * - `public` 公有云
 * - `public_intl` 公有云国际站
 * - `private` 私有云
 *
 */
export type CloudMode = 'public' | 'public_intl' | 'private';

/**
 * 服务模式
 *
 * - `server` 专属加速模式
 * - `server2` 普通加速模式
 */
export type SDKMode = 'server' | 'server2';

/**
 * 媒体类型
 */
export type MediaType = 'video' | 'audio';

/**
 * 房间状态
 */
export type RoomState = 'joining' | 'joined' | 'unjoined';

/**
 * 信令状态
 */
export type SignalingState =
  | 'new'
  | 'scheduling'
  | 'scheduled'
  | 'connecting'
  | 'connected'
  | 'disconnected'
  | 'closed'
  | 'reconnecting';

export const enum NetworkErrorCode {
  // success - 默认所有信令返回
  SUCCESS = 0,
  // stream not found - 媒体服务-流不存在 - subscribe 信令返回
  MEDIA_SERVER_STREAM_NOT_FOUND = 4000,
  // param err - 媒体服务-参数错误 - subscribe 信令返回
  MEDIA_SERVER_PARAM_ERROR = 4001,
  // track not found - 媒体服务-订阅的 track 不存在 - subscribe 信令返回
  MEDIA_SERVER_TRACK_NOT_FOUND = 4002,
  // json invalid! - 检查信令结构、参数
  INVALID_JSON = 10000,
  // param invalid! - 检查信令参数
  INVALID_PARAMS = 10001,
  // user not join! - 用户未进房,请先进房
  USER_NOT_JOIN = 10002,
  // user repeat join! - 用户重复登录,进房只需要调用一次
  USER_REPEAT_JOIN = 10003,
  // src user not exist! - 远端用户不存在 (invite/offer/answer/custom data 等和远端用户有关的信令)
  SRCUSER_NOT_EXIST = 10004,
  // user sig invalid!
  INVALID_USER_SIG = 10005,
  // auth server sig invalid! - 公有云鉴权服务鉴权失败
  INVALID_AUTH_SERVER_SIG = 10006,
  // no track exist! - 流不存在 - subscribe 信令返回
  NO_TRACK_EXIST = 10007,
  // server overload! - 服务过载 - join 信令返回
  SERVER_OVERLOAD = 10008,
  // media server except! - 媒体服务响应异常
  MEDIA_SERVER_EXCEPT = 11000,
  // unknown - 未定义错误
  SIGNALING_SERVER_ERROR = 20000,
}

/**
 * MQTT 连接状态
 */
export type MqttConnectionState = 'new' | 'connecting' | 'connected' | 'reconnecting' | 'error' | 'closed';

/**
 * 网关设备权限
 */
export type PermissionState = 'master' | 'guest';

/**
 * 网关信息
 */
export type Gateway = {
  /**
   * 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   */
  deviceId: string;
  deviceName: string;
  deviceType: string;
  streamCount: number;
  status: string;
  /**
   * 网关 SDK 版本号
   */
  version: string;
  /**
   * License 过期时间戳（秒）
   */
  licenseExpire?: number;
};

/**
 * 媒体流统计信息
 */
export type WebRTCStats = {
  /** 媒体流推流 ID */
  srcUserId: string;
  /** 媒体流流 ID */
  trackId: string;
  /** 媒体流流号 */
  streamId: number;
  /** 媒体类型 */
  mediaType: MediaType;

  /** 当前码率，单位为 Mbps */
  bitrate: number;
  /** 接收到的 RTP 数据包总数，累积值 */
  packetsReceived: number;
  /** 丢失的 RTP 数据包总数，累积值 */
  packetsLost: number;
  /** 当前丢包率，单位为 % */
  lost: number;
  /** 平均丢包率，单位为 % */
  lostAvg: number;
  /** RTT（往返时间），单位为 ms */
  rtt: number;
  /** RTT（往返时间）平均值，单位为 ms */
  rttAvg: number;

  /** 媒体流编解码 MIME 类型 */
  codec: string;
  /** 解码器标识 */
  decoderImplementation: string;
  /**
   * 解码器类型：
   * - hardware 硬件解码器
   * - software 软件解码器
   * - unknown 未知类型
   */
  decoderType: 'hardware' | 'software' | 'unknown';

  /** NACK 数据包发送总次数，累积值 */
  nack: number;
  /** FIR 数量 */
  firCount: number;
  /** PLI 数量，仅对视频流生效 */
  pliCount: number;

  /** 接收到的帧总数，累积值，仅对视频流生效 */
  framesReceived: number;
  /** 解码的帧总数，累积值，仅对视频流生效 */
  framesDecoded: number;
  /** 解码的关键帧总数，累积值，仅对视频流生效 */
  keyFramesDecoded: number;
  /** 分辨率，格式为 `${width}x${height}`，仅对视频流生效 */
  resolution: string;
  /** 帧率，仅对视频流生效 */
  fps: number;
  /** 当前解码耗时，单位为 ms，仅对视频流生效 */
  decodeTime: number;
  /** 平均解码耗时，单位为 ms，仅对视频流生效 */
  decodeTimeAvg: number;
  /** 当前处理视频帧的耗时，单位为 ms，仅对视频流生效 */
  processingDelay: number;
  /** 平均处理视频帧的耗时，单位为 ms，仅对视频流生效 */
  processingDelayAvg: number;

  /** 当前音频轨道音量，取值范围为 0 到 1，仅对音频流生效 */
  audioLevel: number;

  /** 抖动，单位为 s */
  jitter: number;
  /** 当前抖动缓冲区延迟，单位为 ms */
  jitterBuffer: number;
  /** 平均抖动缓冲区延迟，单位为 ms */
  jitterBufferAvg: number;
  /** 当前目标抖动缓冲延迟，单位为 ms */
  jitterBufferTarget: number;
  /** 平均目标抖动缓冲延迟，单位为 ms */
  jitterBufferTargetAvg: number;

  /** 视频延迟，单位为 ms */
  latency: number;
  /** @deprecated latancy 旧算法，2.4.2.2 及以后版本不再回调该字段 */
  latency1?: number;
  /** @deprecated latancy 新算法，2.4.2.2 及以后版本不再回调该字段 */
  latency2?: number;
  /** 视频 100ms 卡顿率 */
  lag100: number;
  /** 视频 150ms 卡顿率 */
  lag150: number;

  /** 周期增量：当前采集周期内 NACK 发送次数 */
  nackDelta: number;
  /** 周期增量：当前采集周期内 FIR 数量 */
  firCountDelta: number;
  /** 周期增量：当前采集周期内 PLI 数量 */
  pliCountDelta: number;
  /** 周期增量：当前采集周期内接收帧数 */
  framesReceivedDelta: number;
  /** 周期增量：当前采集周期内解码帧数 */
  framesDecodedDelta: number;
  /** 周期增量：当前采集周期内接收包数 */
  packetsReceivedDelta: number;
  /** 周期增量：当前采集周期内丢包数 */
  packetsLostDelta: number;
  /** 稳定帧率：10s 滑动窗口平均值，排除 0 值，仅对视频流生效 */
  stableFps: number;
};

/**
 * 诊断报告
 */
export type DiagnosisReport = {
  /** 诊断错误信息，若没有错误则返回 `'ok'`，否则返回错误信息 */
  diag_error: string;
  /** 现场设备 ID */
  device_id: string;
  /** 现场设备进程 ID */
  field_pid?: string;
  /** 现场设备 License 检测，若通过则返回 `'ok'`，否则返回错误信息 */
  license_check?: string;
  /** 现场设备 MQTT 连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
  field_mqtt_connect?: string;
  /** 远端设备 MQTT 连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
  remote_mqtt_connect: string;
  /** 视频流诊断报告 */
  result: {
    /** 视频流 ID */
    stream_id: number;
    /** 现场设备视频流诊断报告 */
    field?: {
      /** 现场设备服务模式 */
      field_mode: string;
      /** 现场设备信令连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
      signal_connect: string;
      /** 现场设备媒体连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
      media_connect: string;
      /** 现场设备视频传输状态，若视频传输正常则返回 `'ok'`，否则返回错误信息 */
      video_transfer: string;
      /** 现场设备视频采集状态，若视频编码正常则返回 `'ok'`，否则返回错误信息 */
      video_capture: string;
      /** 现场设备视频编码状态，若视频编码正常则返回 `'ok'`，否则返回错误信息 */
      video_encode: string;
      /** 现场设备 RTT 统计信息，单位为毫秒，统计间隔为 2 秒 */
      rtt: Array<number>;
      /** 现场设备丢包率统计信息，统计间隔为 2 秒 */
      lost: Array<number>;
      /** 现场设备比特率统计信息，单位为 kbps，统计间隔为 2 秒 */
      bps: Array<number>;
      /** 现场设备帧率统计信息，统计间隔为 2 秒 */
      fps: Array<number>;
    };
    /** 远端设备视频流诊断报告 */
    remote?: {
      /** 远端设备服务模式 */
      remote_mode: string;
      /** 远端设备信令连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
      signal_connect: string;
      /** 远端设备媒体连接状态，若连接正常则返回 `'ok'`，否则返回错误信息 */
      media_connect: string;
      /** 远端设备视频传输状态，若视频传输正常则返回 `'ok'`，否则返回错误信息 */
      video_transfer: string;
      /** 远端设备视频解码状态，若视频解码正常则返回 `'ok'`，否则返回错误信息 */
      video_decode: string;
      /** 远端设备 100ms 卡顿率 */
      lag_k100: number;
      /** 远端设备 150ms 卡顿率 */
      lag_k150: number;
      /** 远端设备 RTT 统计信息，单位为毫秒，统计间隔为 2 秒 */
      rtt: Array<number>;
      /** 远端设备丢包率统计信息，统计间隔为 2 秒 */
      lost: Array<number>;
      /** 远端设备比特率统计信息，单位为 kbps，统计间隔为 2 秒 */
      bps: Array<number>;
      /** 远端设备帧率统计信息，统计间隔为 2 秒 */
      fps: Array<number>;
      /** 远端设备延迟统计信息，单位为毫秒，统计间隔为 2 秒 */
      latency: Array<number>;
      /** 远端设备完整统计信息，统计间隔为 2 秒 */
      webrtc_stats: Array<WebRTCStats>;
    };
  }[];
};

/**
 * 自动播放返回类型
 */
export type OnEventAutoplayResponse = {
  type: 'autoplay';
  data: {
    /**
     * 0 success
     *
     * -1 failed
     * 20 mqtt client not found （只在公有云场景下出现）
     *
     * 21 mqtt client not connected （只在公有云场景下出现）
     *
     * 22 mqtt publish message failed （只在公有云场景下出现）
     *
     * 25 mqtt sessionId not found （只在公有云场景下出现）
     */
    code: number;
    message: string;
    fieldDeviceId: string;
    srcUserId: string;
    streamId: number;
    trackId: string;
    mediaType: MediaType;
    videoWidth?: number;
    videoHeight?: number;
  };
};

/**
 * 媒体流统计信息回调
 */
export type OnEventWebRTCStatsResponse = {
  type: 'webrtcStats';
  data: Array<WebRTCStats>;
};

/**
 * 远端设备媒体流统计信息回调
 *
 * stats 数组中每个元素的字段（可能随网关版本变化，以下仅列出常见字段）：
 *   - stream: number          // 流 ID
 *   - fps: number             // 帧率（fps）
 *   - bps: number             // 码率（bps）
 *   - rtt: number             // RTT（ms）
 *   - jitter: number          // 抖动（ms）
 *   - lost: number            // 丢包数（包）
 *   - w: number               // 编码宽度（px）
 *   - h: number               // 编码高度（px）
 *   - encode_cost: number     // 编码耗时（ms）
 */
export type OnEventGatewayStatsResponse = {
  type: 'gatewayStats';
  data: {
    fieldDeviceId: string;
    stats: any;
  };
};

/**
 * 本地音频流自动取消推流回调
 */
export type OnEventLocalTrackUnpublishedResponse = {
  type: 'localTrackUnpublished';
  data: {};
};

/**
 * 视频延迟上报单条数据
 */
export type LatencyReportItem = {
  /** 现场设备 ID */
  fieldDeviceId: string;
  /** 视频流号 */
  streamId: number;
  /** 媒体流 ID */
  trackId: string;
  /** 视频延迟（ms），与当前帧级延迟计算一致 */
  latency: number;
  /** 视频信道往返时延（ms） */
  vcct: number;
  /** 控制信道往返时延（ms） */
  rcct: number;
  /** 网关视频时间戳（ms） */
  gatewayVideoTime: number;
};

/**
 * 视频延迟回调（帧级触发）
 */
export type OnEventLatencyReportResponse = {
  type: 'latencyReport';
  data: Array<LatencyReportItem>;
};

/**
 * OnEvent 回调
 */
export type OnEventResponse =
  | OnEventAutoplayResponse
  | OnEventWebRTCStatsResponse
  | OnEventGatewayStatsResponse
  | OnEventLocalTrackUnpublishedResponse
  | OnEventLatencyReportResponse;

/**
 * TRROMediaObserver 回调函数
 */
export interface TRROMediaObserver {
  /**
   * @function
   *
   * @description
   * MQTT 连接状态回调
   *
   * @param {Object} param
   * @param {MqttConnectionState} param.state MQTT 连接状态
   * @param {string} [param.message] 相关信息
   */
  onMqttConnectionState?: ({
    state,
    message,
  }: {
    /**
     * MQTT 连接状态
     */
    state: MQTTConnectionState;
    /**
     * 相关信息
     */
    message?: string;
  }) => void;
  /**
   * @function
   *
   * @description
   * 信令状态回调
   *
   * @param {Object} param
   * @param {string} roomId 信令房间 ID
   * @param {string} param.state socket.io-client 内置事件，具体可以参考 https://socket.io/docs/v2/client-api/#events
   * @param {Object} param.data socket.io-client 内置事件的相关参数，具体可以参考 https://socket.io/docs/v2/client-api/#events
   */
  onSignalingState?: ({
    roomId,
    state,
    param,
  }: {
    /**
     * 信令房间 ID
     */
    roomId: string;
    /**
     * socket.io-client 内置事件，具体可以参考 https://socket.io/docs/v2/client-api/#events
     */
    state: string;
    /**
     * socket.io-client 内置事件的相关参数，具体可以参考 https://socket.io/docs/v2/client-api/#events
     */
    data?: Record<string, any>;
  }) => void;
  /**
   * @function
   *
   * @description
   * peer connection 连接改变回调
   *
   * CONNECTED = 0  连接成功 <br />
   * NEW = 1  新建连接 <br />
   * CONNECTING = 2  连接中 <br />
   * FAILED = 3  连接失败 <br />
   * DISCONNECTED = 4  连接断开 <br />
   * CLOSED = 5  主动关闭 <br />
   * RECONNECTING = 6 重连中 <br />
   * NOT_SUPPORT = 255 当前浏览器不支持 WebRTC <br />
   * LIMIT_EXCEEDED = 256 当前 PeerConnection 连接数已达到浏览器上限
   *
   * @param {Object} param
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   * @param {number} [param.streamId] 流 ID，该字段只在 server2 模式下有值
   * @param {MediaType} [param.mediaType] 流类型，该字段只在 server2 模式下有值
   * @param {string} param.state 连接状态信息
   * @param {string} param.code 连接状态码
   * @param {string} param.message message
   * @param {Object} param.data 扩展信息
   */
  onPeerConnectionState?: ({
    deviceId,
    streamId,
    mediaType,
    code,
    state,
    message,
    data,
  }: {
    deviceId: string;
    streamId?: number;
    mediaType?: MediaType;
    code: number;
    state: ConnectionState;
    message?: string;
    data?: Record<string, any>;
  }) => void;
  /**
   * @function
   *
   * @description
   * 数据通道状态回调
   *
   * @param {Object} param
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   * @param {string} param.state 数据通道状态，取值为 'open' | 'close' | 'error'
   * @param {string} [param.message] 错误信息
   * @param {string} param.label 数据通道标签
   * @returns {void}
   */
  onDataChannelState?: ({
    deviceId,
    state,
    message,
  }: {
    deviceId: string;
    state: string;
    message?: string;
    label: string;
  }) => void;
  /**
   * @function
   *
   * @description
   * 现场设备连接回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   *
   */
  onConnected?: ({ deviceId }: { deviceId: string }) => void;
  /**
   * @function
   *
   * @description
   * 现场设备断开连接回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   *
   */
  onDisconnected?: ({ deviceId }: { deviceId: string }) => void;
  /**
   * @function
   *
   * @description
   * 视频流 发布/取消发布 回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.state 视频流状态 'publish' | 'unpublish'
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   * @param {number} param.streamId 对应已经订阅的 streamId
   * @param {MediaType} param.mediaType 'video' | 'audio'
   */
  onTrackPublishState?: ({
    state,
    deviceId,
    streamId,
    mediaType,
  }: {
    state: 'publish' | 'unpublish';
    deviceId: string;
    streamId: number;
    mediaType: MediaType;
  }) => void;
  /**
   * @ignore
   * @function
   *
   * @description
   * 信令 自定义消息 回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.deviceId 现场设备 ID
   * @param {any} param.customData 自定义消息
   */
  onCustomMessage?: ({ deviceId, customData }: { deviceId: string; customData: any }) => void;
  /**
   * @function
   *
   * @description
   * DataChannel 自定义消息 回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   * @param {string} param.dataType 自定义消息类型 'string' | 'arrayBuffer'
   * @param {string|ArrayBuffer} param.data 自定义消息
   * @param {boolean} [param.ordered] 是否通过可靠通道发送，仅在 channelType 为 'sctp' 时有值
   * @param {'sctp'|'mqtt'} param.channelType 消息通道类型，'sctp' 表示 DataChannel，'mqtt' 表示 MQTT
   */
  onControlData?: ({
    deviceId,
    data,
    dataType,
    ordered,
    channelType,
  }: {
    deviceId: string;
    dataType: 'string' | 'arrayBuffer';
    data: string | ArrayBuffer;
    ordered?: boolean;
    channelType: 'sctp' | 'mqtt';
  }) => void;
  /**
   * @function
   *
   * @description
   * 剔除回调
   *
   * @param {Object} param 回调数据
   * @param {number} param.code code
   * @param {string} param.reason 原因
   */
  onKick?: ({ code, reason }: { code: number; reason: string }) => void;
  /**
   * @function
   *
   * @description
   * 权限信息回调
   *
   * @param {Object} param 回调数据
   * @param {string} param.deviceId 现场设备 ID。公有云模式下，返回的 ID 的格式为 `${projectId}/${fieldDeviceId}`
   * @param {string} param.userId 远端设备 ID
   * @param {PermissionState} param.permission 权限信息
   */
  onPermissionStateChange?: (response: { deviceId: string; userId: string; permission: PermissionState }) => void;
  /**
   * @function
   *
   * @description
   *
   * 错误通知
   *
   * | 错误码 | 原因 |
   * | :--- | :--- |
   * | 20101 | 用户名或者密码错误 |
   * | 20102 | 同名用户登录 |
   * | 20199 | MQTT 连接错误 |
   *
   * @param {Object} param 回调数据
   * @param {number} param.code 错误码
   * @param {string} param.message 错误信息
   */
  onError?: ({ code, message }: { code: number; message: string }) => void;
  /**
   * @function
   *
   * @description
   * 事件回调
   *
   * @param {OnEventResponse} param 回调数据
   * @param {string} param.type 事件类型 autoplay | webrtcStats | gatewayStats | localTrackUnpublished
   * @param {Object} param.data 扩展信息
   */
  onEvent?: (response: OnEventResponse) => void;
}

/**
 * TRROSDK 初始化配置项
 *
 * 包含云模式、信令地址、设备信息、事件回调、日志、自定义消息等所有顶层配置;
 * 各字段的详细说明见下方对应字段。
 */
export interface TRROConfig {
  /**
   * 云模式
   *
   * 取值：
   * - `public` 公有云
   * - `public_intl` 公有云国际站
   * - `private` 私有云
   *
   * @default "private"
   */
  cloudMode?: CloudMode;
  /**
   * 信令调度服务器的域名或 IP 地址，可传入多个信令调度服务器地址
   *
   * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效；
   * - 云模式 `cloudMode` 设置为 `private` 时，必须提供该字段，否则将抛出错误。
   */
  serverIp?: string | string[];
  /**
   * 信令调度服务端口。
   *
   * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效；
   * - 云模式 `cloudMode` 设置为 `private` 时，该字段默认值为 `3000` / `443`（启用 https）。
   */
  port?: number;
  /**
   * 服务器远程访问 IP 地址，仅在多网段访问场景下需要提供该字段
   *
   * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效；
   * - 必须为 IPv4 形式。
   *
   * @deprecated 2.4.1.4 及以后版本弃用该参数
   */
  targetIp?: string;
  /**
   * 服务器远程访问端口，仅在多网段访问场景下需要提供该字段
   *
   * 注意：
   * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效。
   *
   * @deprecated 2.4.1.4 及以后版本弃用该参数
   */
  targetPort?: number;
  /**
   * 是否启用 SSL
   *
   * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，强制使用 SSL，该字段无效；
   * - 云模式 `cloudMode` 设置为 `private` 时，该字段默认值为 `false`。
   */
  https?: boolean;
  /**
   * MQTT 配置项
   */
  mqttOptions?: {
    /**
     * MQTT 服务器的域名或 IP 地址，可传入多个 MQTT 服务器地址
     *
     * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，一般无需配置该字段，请在专业人员指导下配置；
     * - 云模式 `cloudMode` 设置为 `private` 时，该字段默认与 `serverIp` 一致。
     */
    url?: string | string[];
    /**
     * MQTT 服务器端口
     *
     * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，一般无需配置该字段，请在专业人员指导下配置；
     * - 云模式 `cloudMode` 设置为 `private` 时，该字段默认值为 `2833`。
     */
    port?: number;
    /**
     * 强制登录
     *
     * - 若配置为 `true`，则登录时会无视是否已有同名用户登录，并踢掉已登录的同名用户
     *
     * @default false
     */
    forceLogin?: boolean;
    /**
     * 打开 MQTT 底层日志
     *
     * - `loggerOption.showLog` 的值为 `false` 时，即使该字段设置为 `true`，也不会打印日志
     * - `loggerOption.reportLog` 的值为 `true`，且该字段设置为 `true`，MQTT 底层日志会和其它 SDK 日志同时上报
     *
     * @default false
     */
    enableLog?: boolean;
  };
  /**
   * 服务模式
   *
   * 取值：
   * - `server`
   * - `server2`
   *
   * 注意：
   * - 云模式 `cloudMode` 设置为 `public` 时，该字段默认值为 `server2`；
   * - 云模式 `cloudMode` 设置为 `public_intl` 时，强制使用 `server2` 模式，该字段无效；
   * - 云模式 `cloudMode` 设置为 `private` 时，该字段默认值为 `server`。
   */
  sdkMode?: SDKMode;
  /**
   * 项目 ID
   */
  projectId: number | string;
  /**
   * 远端设备 ID
   */
  remoteDeviceId: string;
  /**
   * 远端设备密码
   */
  password: string;
  observer?: TRROMediaObserver;
  /**
   * SDK 日志配置
   */
  loggerOption?: {
    /**
     * 是否打印 SDK 日志
     *
     * @default true
     */
    showLog?: boolean;
    /**
     * 是否上传 SDK 日志
     *
     * - 云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效。
     *
     * @default false
     */
    reportLog?: boolean;
    /**
     * 控制台打印的最低日志级别（含）。低于该级别的日志不打印。
     *
     * 级别从低到高：`'DEBUG'` < `'LOG'` < `'INFO'` < `'WARN'` < `'ERROR'`。
     * 例如设置为 `'WARN'` 时，仅打印 `WARN` 与 `ERROR` 级别日志。需 `showLog` 为 `true` 时生效。
     *
     * @default 'DEBUG'
     */
    logLevel?: 'DEBUG' | 'LOG' | 'INFO' | 'WARN' | 'ERROR';
    /**
     * 上报的最低日志级别（含）。低于该级别的日志不进入上报。
     *
     * 级别从低到高：`'DEBUG'` < `'LOG'` < `'INFO'` < `'WARN'` < `'ERROR'`。
     * 例如设置为 `'INFO'` 时，仅上报 `INFO`/`WARN`/`ERROR` 级别日志。需 `reportLog` 为 `true` 时生效。
     *
     * @default 'DEBUG'
     */
    reportLevel?: 'DEBUG' | 'LOG' | 'INFO' | 'WARN' | 'ERROR';
    /**
     * 自定义 log 级别的日志打印函数
     *
     * @default console.log
     */
    log?: Function;
    /**
     * 自定义 error 级别的日志打印函数
     *
     * @default console.error
     */
    error?: Function;
    /**
     * 自定义 warn 级别的日志打印函数
     *
     * @default console.warn
     */
    warn?: Function;
    /**
     * 自定义 info 级别的日志打印函数
     *
     * @default console.info
     */
    info?: Function;
    /**
     * 自定义 debug 级别的日志打印函数
     *
     * @default console.debug
     */
    debug?: Function;
  };
  /**
   * 自定义消息（onControlData）相关配置
   */
  customMessageOption?: {
    /**
     * 是否将 `onControlData` 回调中的 `data` 统一为 `ArrayBuffer`。
     *
     * - `true`：`dataType` 均为 `'arrayBuffer'`，`data` 均为 `ArrayBuffer` 类型。
     *   业务方按字节解析即可，无需再根据 `dataType` 分支判断。
     * - `false`（默认）：业务方需要根据 `dataType` 分支判断 `data` 的类型。
     *
     * 仅影响 SCTP DataChannel 通道（`channelType: 'sctp'`）的 `onControlData` 回调；
     * MQTT 通道（`channelType: 'mqtt'`）始终按内容自适应判定，不受该开关影响。
     *
     * @default false
     */
    preferArrayBuffer?: boolean;
  };
}

/**
 * getCameraViewNavigationLine 导航线计算参数
 */
export interface CameraViewNavigationLineParams {
  /**
   * 导航线远端到车辆的距离。
   * 定义了导航线的最远可视距离，单位应与其他距离参数保持一致（如米）。
   */
  navDist: number;
  /**
   * 导航线近端（相机图像底部）到车辆的真实距离，即前方视觉盲区的距离。
   * 该值对应画面底部边缘在地面上的投影距离。
   */
  blindDist: number;
  /**
   * 车辆宽度，单位与距离参数一致。
   * 用于确定左右导航线之间的横向间距。
   */
  carWidth: number;
  /**
   * 车辆前后轮轴距，单位与距离参数一致。
   * 用于阿克曼转向模型中计算转弯半径。
   */
  carLength: number;
  /**
   * 相机安装高度（离地高度），单位与距离参数一致。
   * 影响透视投影的垂直缩放关系。
   */
  cameraHeight: number;
  /**
   * 相机俯仰角，范围 (0, 90] 度。
   * 正对前方水平方向为 90 度，越小表示相机越朝下看。
   */
  cameraPitchDegree: number;
  /**
   * 相机图像的宽高比（图像宽度 / 图像高度）。
   * 例如 16:9 画面传入 16/9 ≈ 1.778。
   */
  cameraAspectRatio: number;
  /**
   * 车辆转向角，范围 -90 到 90 度。
   * 左转为负值，右转为正值。可取内侧轮转向角度。
   * 当值为 0 或绝对值 >= 180 时按直线行驶计算。
   */
  carAngle: number;
  /**
   * 导航线采样点数，至少为 2。
   * 采样点在 blindDist 到 navDist 之间均匀分布，
   * 第 i 个点与车的近似距离为: blindDist + i * (navDist - blindDist) / (size - 1)。
   */
  size: number;
}

/**
 * 导航线单个采样点坐标。
 * 坐标原点为画面中心点，X 坐标范围 (-1, 1)，Y 坐标范围 (-1, 1)。
 */
export interface NavigationLinePoint {
  /**
   * 左侧导航线 X 坐标。
   * 范围 (-1, 1)，-1 为画面最左侧，1 为画面最右侧。
   */
  leftX: number;
  /**
   * 左侧导航线 Y 坐标。
   * 范围 (-1, 1)，-1 为画面最底部，1 为画面最顶部。
   */
  leftY: number;
  /**
   * 右侧导航线 X 坐标。
   * 范围 (-1, 1)，-1 为画面最左侧，1 为画面最右侧。
   */
  rightX: number;
  /**
   * 右侧导航线 Y 坐标。
   * 范围 (-1, 1)，-1 为画面最底部，1 为画面最顶部。
   */
  rightY: number;
  /**
   * 该采样点是否有效。
   * 当坐标超出 (-1, 1) 范围或转弯计算溢出时为 false，表示该距离点不存在或超出图像范围。
   */
  valid: boolean;
  /**
   * 该采样点与车辆的近似距离（与输入参数单位一致）。
   * 计算公式: blindDist + i * (navDist - blindDist) / (size - 1)
   */
  distance: number;
}

/**
 *
 * TRRO 类
 *
 * @param {Object} params
 * @param {CloudMode} [params.cloudMode="private"] - 云模式<br/><br/>取值：<ul><li>`public` 公有云</li><li>`public_intl` 公有云国际站</li><li>`private` 私有云</li></ul>
 * @param {string | string[]} [params.serverIp] - 信令调度服务器的域名或 IP 地址，可传入多个信令调度服务器地址<ul><li>云模式 `cloudMode` 设置为 `public` 或 `public_intl` 时，该字段无效；</li><li>云模式 `cloudMode` 设置为 `private` 时，必须提供该字段，否则将抛出错误。</li></ul>
 * @param {number} [params.port] - 信令调度服务端口。<br/>公有云模式下，该字段无效，私有云模式下默认为 3000/443（启用 https）。
 * @param {boolean} [params.https=false] - 是否启用 https 协议，可选。<br/>公有云模式下强制使用 https，该字段无效，私有云模式下默认为 false。
 * @param {Object} [params.mqttOptions] - MQTT 配置项，可选。
 * @param {string | string[]} [params.mqttOptions.url] - MQTT 服务器的域名或 IP，可选，可传入多个 MQTT 服务器地址。<br/>公有云模式下，一般无需配置该字段；私有云模式下默认与 serverIp 一致。
 * @param {number} [params.mqttOptions.port] - MQTT 服务器端口，可选。<br/>公有云模式下，一般无需配置该字段；私有云模式下默认为 2833。
 * @param {boolean} [params.mqttOptions.forceLogin=false] - 强制登录<ul><li>若配置为 `true`，则登录时会无视是否已有同名用户登录，并踢掉已登录的同名用户</li></ul>
 * @param {string | number} params.projectId - 项目 ID
 * @param {string} params.remoteDeviceId - 远端设备 ID
 * @param {string} params.password - 远端设备密码
 * @param {TRROMediaObserver} [params.observer] - 事件回调函数,完整字段说明详见 {@link TRROMediaObserver}
 * @param {Object} [params.loggerOption] - SDK 日志配置,完整字段说明详见 {@link TRROConfig#loggerOption}
 * @param {Object} [params.customMessageOption] - 自定义消息(onControlData)相关配置,完整字段说明详见 {@link TRROConfig#customMessageOption}
 *
 * @example
 * // 公有云模式，初始化最小配置
 * new TRROSDK({
 *  cloudMode: 'public',
 *  projectId: 'xxxxxxxx',
 *  remoteDeviceId: 'xxxxxxxx',
 *  password: '********',
 * });
 *
 * // 私有云模式，初始化最小配置
 * new TRROSDK({
 *  serverIp: '1.1.1.1',
 *  projectId: 1111,
 *  remoteDeviceId: 'xxxxxxxx',
 *  password: '',
 * });
 *
 */
class TRROSDK {
  constructor(params: TRROConfig);
  /**
   * @async
   *
   * @description 初始化 MQTT 连接
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 21 mqtt client connnect error, 26 mqtt client alreay connected, 100 request error |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * init()
   *
   */
  init(): Promise<{ code: number; message: string }>;
  /**
   * @description
   *
   * 设置指定现场设备的临时会话密钥。<br />
   * 只有在公有云模式下，通过使用项目共享密钥生成的远端设备 ID 和密码，实现远端设备的自动注册和登录时，才需要调用该方法。
   *
   * @example
   * setSessionPermissionToken('<FIELD-DEVICE-ID>', '<TOKEN>')
   */
  setSessionPermissionToken(fieldDeviceId: string, token: string): void;
  /**
   * @async
   *
   * @description
   *
   * 连接指定现场设备
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   *
   * @returns 返回 Promise 对象。
   *
   * | 字段 | 类型 | 描述 |
   * | :--- | :--- | :--- |
   * | code | number | 错误码 |
   * | message | string | 描述信息 |
   *
   * 其中，code 和 message 字段的含义如下：
   *
   * | code | message | 描述 |
   * | :--- | :--- | :--- |
   * | 0 | Already joined. | 已连接 |
   * | 2 | Joining | 当前传入的现场设备正在连接中 |
   * | 20 | Connect failed for public cloud mode, MQTT client not found. | 公有云模式，MQTT 未初始化 |
   * | 21 | Connect failed for public cloud mode: xxxxxx | 公有云模式，MQTT 连接失败 |
   *
   * @example
   * connect('<FIELD-DEVICE-ID>')
   */
  connect(fieldDeviceId: string): Promise<{ code: number; message: string }>;
  /**
   * @ignore
   *
   * @async
   *
   * @description
   *
   * 设置视频流渲染配置
   *
   * 注意：可在 `subscribe` 接口调用之前，提前指定视频流的渲染配置，也可以在 `subscribe` 接口调用之后，实时改变渲染配置
   *
   * @param {Object} params
   * @param {string} params.fieldDeviceId - 现场设备 ID
   * @param {Object[]} params.renderConfigs - 渲染配置
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 20 mqtt client not found, 21 mqtt client connnect error, 100 request error |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * setVideoRenderConfig({
   *  fieldDeviceId: '<FIELD-DEVICE-ID>',
   *  renderConfigs: [{
   *    streamId: 0,
   *    mount: '#test-div-0',
   *    nightVision: true,
   *  }],
   * })
   *
   */
  setVideoRenderConfig(params: {
    /**
     * 现场设备 ID
     */
    fieldDeviceId: string;
    renderConfigs: {
      /**
       * 视频流流号
       */
      streamId: number;
      mount?: string;
      /**
       * 旋转，取值范围 0-360
       *
       * @default 0
       */
      rotate?: number;
      /**
       * 缩放
       */
      zoom?: {
        /**
         * 缩放原点坐标 `[x, y]`，纵坐标 `x` 及横坐标 `y` 取值范围均为 `[0, 1]`
         *
         * @example
         * [0, 0]     // 视频画面左上角坐标点
         * [0.5, 0.5] // 视频画面正中心坐标点
         * [1, 1]     // 视频画面右下角坐标点
         *
         * @default
         * [0.5, 0.5]
         */
        position?: [number, number];
        /**
         * 缩放比例，取值范围为 `(0, 10]`
         *
         * @default 1
         */
        ratio?: number;
      };
      /**
       * 镜像
       *
       * - `horizontal` 水平镜像
       * - `vertical` 垂直镜像
       * - `off` 关闭
       *
       * @default "off"
       */
      mirror?: 'horizontal' | 'vertical' | 'off';
      /**
       * 夜视增强
       *
       * @default false
       */
      nightVision?: boolean;
      /**
       * 渲染后端，控制 `rotate` / `zoom` / `mirror` 几何变换使用何种方式实现：
       *
       * - `auto`（默认）：几何变换优先使用 **CSS Transform** 实现（零 WebGL 上下文开销，可显著降低 WebGL OOM 风险）
       * - `css`：强制使用 **CSS Transform**
       * - `webgl`：强制使用 **WebGL** 着色器
       *
       * **CSS 与 WebGL 的实现差异（由调用方按需取舍）**：
       * - 任意角度 `rotate`：CSS 旋转整个视频元素，四角会出现黑色三角空白；WebGL 在固定画面内旋转采样并对越界区域做边缘像素填充（无黑角）。若依赖"无黑角"效果，请显式指定 `renderBackend: 'webgl'`。
       * - 缩小（`zoom.ratio < 1`）：CSS 会留出黑边；WebGL 做边缘拉伸填充。
       * - 放大 / 镜像：两者效果基本一致。
       *
       * **注意**：`nightVision` 为逐像素增强，CSS 无等价实现。当 `nightVision: true` 时无论 `renderBackend` 取值如何都会强制使用 WebGL。
       *
       * @default "auto"
       */
      renderBackend?: 'auto' | 'css' | 'webgl';
    }[];
  }): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 订阅媒体流（拉流）
   *
   * @param {Object} params
   * @param {string} params.fieldDeviceId - 现场设备 ID
   * @param {Object[]} params.containers
   * @param {number} params.containers.streamId - 视频流流号
   * @param {string} params.containers.mount 视频流挂载节点，以 ID 形式，#test-div-0，SDK 会在该节点下自动创建媒体元素并播放流。
   * @param {Function} params.containers.callback latency 为端到端延迟，metadata 为 requestVideoFrameCallback 回调的 metadata
   * @param {string} [params.audioContainer] 音频流挂载节点，以 ID 形式，#test-div-0。SDK 会在该节点下自动创建媒体元素并播放流。若不传该字段，则不拉取音频流。若不传 containers 字段，则该字段无效，订阅接口返回错误码。
   * @param {boolean} [params.incremental] 是否增量订阅，默认为 false，即每次调用订阅接口传入的参数，会全量覆盖现有的订阅状态。若为 true，则会增量订阅，即保持现有流的订阅状态并新增订阅的传入的流，或者更新已订阅的流的相关参数（如挂载节点）
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 3 failed, 4 streams not published, 5 empty containers, 20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * subscribe({
   *   fieldDeviceId: 'xxxxxxxx',
   *   containers: [{
   *     streamId: 0,
   *     mount: '#test-div-0',
   *     callback: ({latency, metadata}) => {
   *      console.log(latency, metadata);
   *     }
   *   },{
   *     streamId: 1,
   *     mount: '#test-div-1',
   *     callback: ({latency, metadata}) => {
   *      console.log(latency, metadata);
   *     }
   *   }],
   *  audioContainer: '#test-div-audio'
   * })
   *
   */
  subscribe({
    fieldDeviceId,
    containers,
    audioContainer,
  }: {
    /**
     * 现场设备 ID
     */
    fieldDeviceId: string;
    containers: {
      /**
       * 视频流流号
       */
      streamId: number;
      mount: string; // Element;
      callback?: ({
        latency,
        latencyMax,
        gatewayTime,
        metadata,
        srcUserId,
        trackId,
      }: {
        /**
         * 视频帧端到端延迟
         */
        latency: number;
        latencyMax: number;
        /**
         * 视频帧网关时间戳
         */
        gatewayTime: number;
        metadata: VideoFrameCallbackMetadata & { now: DOMHighResTimeStamp };
        srcUserId: string;
        trackId: string;
      }) => void;
    }[];
    /**
     * 音频流挂载节点，以 ID 形式。SDK 会在该节点下自动创建媒体元素并播放流。
     *
     * - 若不传该字段，则不拉取音频流。
     * - 若不传 `containers` 字段，则该字段无效，订阅接口返回错误码。
     *
     * @example
     * audioContainer: '#test-div-audio'
     */
    audioContainer?: string;
    /**
     * 是否增量订阅
     *
     * - 默认值为 `false`，即每次调用订阅接口传入的参数，会全量覆盖现有的订阅状态
     * - 若为 `true`，则会增量订阅，即保持现有流的订阅状态并新增订阅的传入的流，或者更新已订阅的流的相关参数（如挂载节点）
     *
     * @default false
     */
    incremental?: boolean;
  }): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 取消订阅 track （拉流）
   *
   * @param {Object} params
   * @param {string} params.fieldDeviceId - 现场设备 ID
   * @param {Array<number>} params.streamIds 需要取消订阅的视频流流号
   * @param {boolean} [params.audioStream] 是否取消订阅音频流，默认为 false
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 5 empty streamIds，20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * unsubscribe({ fieldDeviceId: 'xxxxxxxx', streamIds: [0] })
   */
  unsubscribe({
    fieldDeviceId,
    streamIds,
    audioStream,
    sendUnpublishNotification,
  }: {
    /**
     * 现场设备 ID
     */
    fieldDeviceId: string;
    /**
     * 需要取消订阅的视频流流号
     */
    streamIds: Array<number>;
    /**
     * 是否取消订阅音频流，默认为 false
     */
    audioStream?: boolean;
    /**
     * 是否立即通知网关取消推流，默认为 false
     */
    sendUnpublishNotification?: boolean;
  }): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 发布音频流（推流）<br/>只有在成功订阅了视频流的情况下，才能发布音频流，若取消订阅了所有视频流，则 SDK 会自动取消发布音频流，并通过 `onEvent` 回调通知<br/>一个 SDK 实例只允许发布一个音频流<br/>若使用 server 模式，**需先调用 `requestPermission` 申请 `master` 权限**，否则无法推流
   *
   * @param {Object} params
   * @param {MediaStreamTrack} params.audioTrack - 音频流。需要业务层自行通过 `navigator.mediaDevices.getUserMedia()` 等手段获取 `MediaStreamTrack` 对象。·
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 3 failed, 4 streams not published, 5 empty containers, 20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * try {
   *   // 初始化 SDK 实例
   *   const client = new TRROSDK({ ... });
   *   // 连接指定现场设备
   *   await client.connect('xxxxxxxx');
   *   // 订阅视频流
   *   await client.subscribe({ fieldDeviceId: 'xxxxxxxx', containers: [{ streamId: 0, mount: '#test-div-0' }] });
   *   // 获取本地音频流
   *   const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
   *   [audioTrack] = stream.getAudioTracks()
   *   // 发布音频流
   *   await client.publish({ audioTrack });
   * } catch () {}
   *
   */
  publish({
    audioTrack,
  }: {
    /**
     * 音频流
     */
    audioTrack: MediaStreamTrack;
  }): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 取消发布音频流（取消推流）
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 3 failed, 4 streams not published, 5 empty containers, 20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * unpublish();
   *
   */
  unpublish(): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 静音或者取消静音指定音频流
   *
   * @param {Object} params
   * @param {string} params.deviceId - 现场设备 ID 或远端设备 ID（即 SDK 初始化时传入的 `remoteDeviceId`）
   * @param {boolean} params.muted - true 表示静音，false 表示取消静音
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 5 empty streamIds，20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * muteAudio({ deviceId: 'xxxxxxxx', muted: true })
   */
  muteAudio({
    deviceId,
    muted,
  }: {
    /**
     * 现场设备 ID 或远端设备 ID（即 SDK 初始化时传入的 `remoteDeviceId`）
     */
    deviceId: string;
    /**
     * true 表示静音，false 表示取消静音
     */
    muted: boolean;
  }): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 断开与指定现场设备的连接
   *
   * @param {string} fieldDeviceId - 现场设备
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 3 failed, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * disconnect('xxxxxxxx')
   *
   */
  disconnect(fieldDeviceId: string): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 断开与所有现场设备的连接
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 3 failed, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * disconnectAll()
   *
   */
  disconnectAll(): Promise<{ code: number; message: string }>;
  /**
   * @async
   *
   * @description 销毁所有连接
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 3 failed, 100 request error |
   * | message       | string              | 描述信息，error 信息  |
   *
   *
   * @example
   * destroy()
   *
   */
  destroy(): Promise<{ code: number; message: string }>;
  /**
   * @description 调整现场设备编码配置。<br/>调用此接口将临时更新现场设备的编码配置，现场设备重启后仍会恢复到原配置。<br/>配置更新只涉及传入的字段，未传入的配置项将保持当前状态。
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   * @param {Object[]} params
   * @param {number} params.streamId - 视频流流号
   * @param {Object} params.encodeConfig - 视频流编码配置
   * @param {number} [params.encodeConfig.encodeWidth] - 编码分辨率宽度
   * @param {number} [params.encodeConfig.encodeHeight] - 编码分辨率高度
   * @param {number} [params.encodeConfig.minWidth] - 最低分辨率宽度
   * @param {number} [params.encodeConfig.fps] - 视频期望帧率
   * @param {number} [params.encodeConfig.minFps] - 视频最低帧率
   * @param {number} [params.encodeConfig.bps] - 视频期望码率，单位 kbps
   * @param {number} [params.encodeConfig.minBps] - 视频最低码率，单位 kbps
   * @param {boolean} [params.encodeConfig.forceMinBps] - 是否强制保证视频分配码率不低于最低码率
   *
   * @returns
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 20 mqtt client not found, 21 mqtt client not connected  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * changeFieldDeviceEncodeConfig('xxxxxxxx', [{ streamId: 0, encodeConfig: { minBps: 1000, forceMin: true } }])
   */
  changeFieldDeviceEncodeConfig(
    /**
     * 现场设备 ID
     */
    fieldDeviceId: string,
    params: {
      /**
       * 视频流流号
       */
      streamId: number;
      /**
       * 视频流编码配置
       */
      encodeConfig: {
        /**
         * 编码分辨率宽度
         */
        encodeWidth?: number;
        /**
         * @deprecated 后续版本将不再支持该字段，请使用 `encodeHeight`
         *
         * 编码分辨率高度
         */
        encodeHeigt?: number;
        /**
         * 编码分辨率高度
         */
        encodeHeight?: number;
        /**
         * 最低分辨率宽度
         */
        minWidth?: number;
        /**
         * 视频期望帧率
         */
        fps?: number;
        /**
         * 视频最低帧率
         */
        minFps?: number;
        /**
         * 视频期望码率，单位 kbps
         */
        bps?: number;
        /**
         * 视频最低码率，单位 kbps
         */
        minBps?: number;
        /**
         * 是否强制保证视频分配码率不低于最低码率
         */
        forceMinBps?: boolean;
      };
    }[],
  ): { code: number; message: string };
  /**
   * @async
   *
   * @description 网关权限申请
   *
   * @param {string} fieldDeviceId 现场设备 ID
   * @param {Object[]} params
   * @param {PermissionState} params.permission master 控制权限及观看权限 guest 仅观看权限
   *
   * @returns
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 20 mqtt client not found, 21 mqtt client not connected, 22 mqtt message publish failed, 23 request pending 24 request timeout   |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * requestPermission({ fieldDeviceId: 'xxx', permission: 'master' })
   */
  requestPermission(
    fieldDeviceId: string,
    params: { permission: PermissionState },
  ): {
    code: number;
    message: string;
    data?: { deviceId: string; userId: string; permission: PermissionState };
  };
  /**
   * @async
   *
   * @description 拉取网关设备列表
   *
   * @returns
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 20 mqtt client not found, 21 mqtt client not connected, 22 request publish failed, 23 request pending 24 request timeout  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * pullGatewayList()
   */
  pullGatewayList(): Promise<{
    code: number;
    message: string;
    data?: Gateway[];
  }>;
  /**
   * @async
   *
   * @description 获取指定网关设备信息
   *
   * @param {string} gatewayId - 网关设备 ID
   *
   * @returns
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 20 mqtt client not found, 21 mqtt client not connected, 22 request publish failed, 23 request pending 24 request timeout  |
   * | message       | string              | 描述信息，error 信息  |
   * | data          | Gateway             | 网关设备信息  |
   *
   * @example
   * getGatewayInfo('gateway_id_123')
   */
  getGatewayInfo(gatewayId: string): Promise<{
    code: number;
    message: string;
    data?: Gateway;
  }>;
  /**
   * @async
   *
   * @description 调整视频码率
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   * @param {Object[]} params
   * @param {number} params.streamId - 视频流流号
   * @param {number} params.videoRate - 码率，单位 kbps
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined, 2 joining, 3 failed, 20 mqtt client not found, 21 mqtt client not connected, 100 request error |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * adjustVideoRate('xxxxxxxx', [{ streamId: 0, videoRate: 3000 }, { streamId: 1, videoRate: 1000 }])
   */
  adjustVideoRate(
    fieldDeviceId: string,
    params: { streamId: number; videoRate: number }[],
  ): Promise<{ code: number; message: string }>;
  /**
   * @ignore
   * @deprecated 后续版本将不再支持该接口
   * @async
   *
   * @description 重置网关
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   * @param {Object} params
   * @param {Array<number>} params.streamIds
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 0 success, 1 unjoined, 2 joining, 3 failed, 20 mqtt client not found, 21 mqtt client not connected, 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @example
   * reset('xxxxxxxx', { streamId: [0] })
   */
  reset(fieldDeviceId: string, params: { streamIds: Array<number> }): Promise<{ code: number; message: string }>;
  /**
   * @description 通过 DataChannel 或 MQTT 发送自定义消息。**需先调用 `requestPermission` 申请 `master` 权限**，否则返回失败。
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   * @param {Object} params
   * @param {string|ArrayBuffer} params.data - 自定义消息
   * @param {boolean} [params.ordered=true] - 是否通过可靠通道发送（仅 SCTP 通道有效，与 channelType='mqtt' 互斥）
   * @param {'sctp'|'mqtt'} [params.channelType='sctp'] - 消息通道类型，'sctp' 表示 DataChannel，'mqtt' 表示 MQTT
   *
   * @returns 返回 Promise 对象。
   * | Name          | Type                | Description                 |
   * | ------------- | ------------------- | --------------------------- |
   * | code          | number              | 0 success, 1 unjoined (仅SCTP), 2 joining (仅SCTP), 3 failed, 20 mqtt client not found, 21 mqtt client not connected, 42 no permission, 45 no subscribed streams (仅SCTP), 100 request error  |
   * | message       | string              | 描述信息，error 信息  |
   *
   * @note
   * - **SCTP 通道**：需要 `init()` → `requestPermission('master')` → `connect()` → `subscribe()` 至少一路视频流
   * - **MQTT 通道**：需要 `init()` → `requestPermission('master')`，无需 `connect()` 和 `subscribe()`
   *
   * @example
   * // 通过 SCTP DataChannel 发送（需要先 connect 和 subscribe）
   * sendControlData('xxxxxxxx', { data: 'xxx', ordered: true })
   *
   * // 通过 MQTT 发送（只需登录，无需 connect 和 subscribe）
   * await sdk.init(); // 登录成功即可
   * await sdk.requestPermission('fieldDeviceId', { permission: 'master' });
   * sendControlData('xxxxxxxx', { data: 'xxx', channelType: 'mqtt' })
   */
  sendControlData(
    fieldDeviceId: string,
    params: { data: string | ArrayBuffer; ordered?: boolean; channelType?: 'sctp' | 'mqtt' },
  ): { code: number; message: string };
  /**
   * @async
   * @description 获取诊断报告。通常需要等待 10 秒后才能获取到诊断报告，最大等待时间为 15 秒。
   *
   * @param {string} fieldDeviceId - 现场设备 ID
   *
   * @returns {Promise<DiagnosisReport>} 返回诊断报告。
   *
   * @example
   * requestDiagnosisReport('<FIELD-DEVICE-ID>')
   */
  requestDiagnosisReport(fieldDeviceId: string): Promise<DiagnosisReport>;
  /**
   * @description 设置 jitterBufferTarget（抖动缓冲区目标值）。若网络环境较差，视频卡顿比较明显，可以尝试手动调用该方法调大 jitterBufferTarget。注意：调大 jitterBufferTarget 会增加视频延迟；Chrome 浏览器推荐优先调整 playoutDelayHint 而不是 jitterBufferTarget。
   *
   * @param {Object} params - 参数对象
   * @param {string} params.fieldDeviceId - 现场设备 ID
   * @param {number} params.streamId - 流 ID
   * @param {number | null} params.jitterBufferTarget - jitterBufferTarget 值，单位毫秒，传 null 还原为默认值
   *
   * @returns {Object} 返回状态对象，包含 code（0 成功, -1 失败）和 message（描述信息）
   *
   * @example
   * setJitterBufferTarget({ fieldDeviceId: '<FIELD-DEVICE-ID>', streamId: 0, jitterBufferTarget: 100 })
   * setJitterBufferTarget({ fieldDeviceId: '<FIELD-DEVICE-ID>', streamId: 0, jitterBufferTarget: null }) // 还原默认值
   */
  setJitterBufferTarget(params: { fieldDeviceId: string; streamId: number; jitterBufferTarget: number | null }): {
    code: number;
    message: string;
  };
  /**
   * @description 设置 playoutDelayHint（播放延迟提示值）。若网络环境较差，视频卡顿比较明显，可以尝试手动调用该方法调大 playoutDelayHint。注意：调大 playoutDelayHint 会增加视频延迟；Chrome 浏览器推荐优先调整 playoutDelayHint 而不是 jitterBufferTarget。
   *
   * @param {Object} params - 参数对象
   * @param {string} params.fieldDeviceId - 现场设备 ID
   * @param {number} params.streamId - 流 ID
   * @param {number | null} params.playoutDelayHint - playoutDelayHint 值，单位毫秒，传 null 还原为默认值
   *
   * @returns {Object} 返回状态对象，包含 code（0 成功, -1 失败）和 message（描述信息）
   *
   * @example
   * setPlayoutDelayHint({ fieldDeviceId: '<FIELD-DEVICE-ID>', streamId: 0, playoutDelayHint: 100 })
   * setPlayoutDelayHint({ fieldDeviceId: '<FIELD-DEVICE-ID>', streamId: 0, playoutDelayHint: null }) // 还原默认值
   */
  setPlayoutDelayHint(params: { fieldDeviceId: string; streamId: number; playoutDelayHint: number | null }): {
    code: number;
    message: string;
  };
  /**
   * @description 获取车辆行驶方向的导航线坐标（实验性功能）。基于针孔相机视角模型构建，需要根据真实参数设置，可接近图中真实轨迹。
   *
   * @param {CameraViewNavigationLineParams} params - 导航线计算参数
   * @param {number} params.navDist - 导航线远端到车辆的距离，单位与其他距离参数一致（如米）
   * @param {number} params.blindDist - 导航线近端（相机图像底部）到车辆的真实距离，即前方视觉盲区的距离
   * @param {number} params.carWidth - 车辆宽度，单位与距离参数一致
   * @param {number} params.carLength - 车辆前后轮轴距，单位与距离参数一致
   * @param {number} params.cameraHeight - 相机安装高度，单位与距离参数一致
   * @param {number} params.cameraPitchDegree - 相机俯仰角，范围 (0, 90] 度，正对前方为 90 度
   * @param {number} params.cameraAspectRatio - 相机图像宽高比（图像宽度 / 高度）
   * @param {number} params.carAngle - 车辆转向角，范围 -90 到 90 度，左转为负值，右转为正值，可取内侧轮转向角度
   * @param {number} params.size - 导航线采样点数（至少为 2）
   *
   * @returns {NavigationLinePoint[]} 导航线坐标数组，共 size 个采样点。坐标原点为画面中心点，X/Y 坐标范围均为 (-1, 1)。
   *
   * @example
   * const points = sdk.getCameraViewNavigationLine({
   *   navDist: 20,
   *   blindDist: 2,
   *   carWidth: 2.5,
   *   carLength: 3.5,
   *   cameraHeight: 2.0,
   *   cameraPitchDegree: 75,
   *   cameraAspectRatio: 16 / 9,
   *   carAngle: 15,
   *   size: 20,
   * });
   * // 使用坐标在 Canvas 上绘制导航线
   * points.filter(p => p.valid).forEach(p => {
   *   const canvasX = (p.leftX + 1) / 2 * canvasWidth;
   *   const canvasY = (1 - (p.leftY + 1) / 2) * canvasHeight;
   *   // ...绑定绘制逻辑
   * });
   */
  getCameraViewNavigationLine(params: CameraViewNavigationLineParams): NavigationLinePoint[];
}

export default TRROSDK;
