@apocaliss92/nodelink-js 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8070,6 +8070,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
8070
8070
  flow;
8071
8071
  deviceId;
8072
8072
  dedicatedSessionRelease;
8073
+ externalListener;
8073
8074
  // Authentication
8074
8075
  authCredentials = [];
8075
8076
  requireAuth;
@@ -8237,6 +8238,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
8237
8238
  this.logger = options.logger ?? console;
8238
8239
  this.tcpRtpFraming = options.tcpRtpFraming ?? "rfc4571";
8239
8240
  this.deviceId = options.deviceId;
8241
+ this.externalListener = options.externalListener ?? false;
8240
8242
  this.authCredentials = options.credentials ?? [];
8241
8243
  this.requireAuth = options.requireAuth ?? this.authCredentials.length > 0;
8242
8244
  const transport = this.api.client.getTransport();
@@ -8367,41 +8369,56 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
8367
8369
  this.streamMetadata = { frameRate: 25 };
8368
8370
  this.setFlowVideoType("H264", "metadata unavailable");
8369
8371
  }
8370
- this.clientConnectionServer = net.createServer((socket) => {
8371
- this.handleRtspConnection(socket);
8372
- });
8373
- await new Promise((resolve, reject) => {
8374
- this.clientConnectionServer.listen(
8375
- this.listenPort,
8376
- this.listenHost,
8377
- () => {
8378
- const address = this.clientConnectionServer.address();
8379
- if (address && typeof address === "object" && "port" in address) {
8380
- this.listenPort = address.port;
8372
+ if (!this.externalListener) {
8373
+ this.clientConnectionServer = net.createServer((socket) => {
8374
+ this.handleRtspConnection(socket);
8375
+ });
8376
+ await new Promise((resolve, reject) => {
8377
+ this.clientConnectionServer.listen(
8378
+ this.listenPort,
8379
+ this.listenHost,
8380
+ () => {
8381
+ const address = this.clientConnectionServer.address();
8382
+ if (address && typeof address === "object" && "port" in address) {
8383
+ this.listenPort = address.port;
8384
+ }
8385
+ resolve();
8381
8386
  }
8382
- resolve();
8383
- }
8384
- );
8385
- this.clientConnectionServer.on("error", (error) => {
8386
- reject(error);
8387
+ );
8388
+ this.clientConnectionServer.on("error", (error) => {
8389
+ reject(error);
8390
+ });
8387
8391
  });
8388
- });
8392
+ }
8389
8393
  this.active = true;
8390
8394
  this.logger.info(
8391
8395
  `[BaichuanRtspServer] RTSP server started on ${this.listenHost}:${this.listenPort}, path: ${this.path}`
8392
8396
  );
8393
8397
  }
8398
+ /**
8399
+ * Accept an externally-routed RTSP connection.
8400
+ * Used in directHandoff mode where RtspProxyServer routes sockets here.
8401
+ * @param socket - The client TCP socket (already authenticated by proxy)
8402
+ * @param initialBuffer - Any bytes already read during path parsing/auth
8403
+ */
8404
+ acceptConnection(socket, initialBuffer) {
8405
+ if (!this.active) {
8406
+ socket.end("RTSP/1.0 503 Service Unavailable\r\n\r\n");
8407
+ return;
8408
+ }
8409
+ this.handleRtspConnection(socket, initialBuffer);
8410
+ }
8394
8411
  /**
8395
8412
  * Handle RTSP connection from a client.
8396
8413
  */
8397
- handleRtspConnection(socket) {
8414
+ handleRtspConnection(socket, initialBuffer) {
8398
8415
  const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
8399
8416
  const connectTime = Date.now();
8400
8417
  this.logger.info(
8401
8418
  `[rebroadcast] client connected client=${clientId} path=${this.path} profile=${this.profile} channel=${this.channel}`
8402
8419
  );
8403
8420
  let sessionId = "";
8404
- let buffer = Buffer.alloc(0);
8421
+ let buffer = initialBuffer ?? Buffer.alloc(0);
8405
8422
  let clientFfmpeg;
8406
8423
  let useTcpInterleaved = false;
8407
8424
  let clientUdpSocket = null;
@@ -8486,8 +8503,7 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
8486
8503
  }
8487
8504
  cleanup();
8488
8505
  });
8489
- socket.on("data", async (data) => {
8490
- buffer = Buffer.concat([buffer, data]);
8506
+ const processBuffer = async () => {
8491
8507
  while (buffer.includes("\r\n\r\n")) {
8492
8508
  const endIndex = buffer.indexOf("\r\n\r\n");
8493
8509
  const requestText = buffer.subarray(0, endIndex).toString();
@@ -8762,7 +8778,14 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
8762
8778
  sendResponse(501, "Not Implemented");
8763
8779
  }
8764
8780
  }
8781
+ };
8782
+ socket.on("data", (data) => {
8783
+ buffer = Buffer.concat([buffer, data]);
8784
+ void processBuffer();
8765
8785
  });
8786
+ if (buffer.includes("\r\n\r\n")) {
8787
+ void processBuffer();
8788
+ }
8766
8789
  }
8767
8790
  /**
8768
8791
  * Generate SDP (Session Description Protocol) for RTSP DESCRIBE.
@@ -9730,21 +9753,27 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
9730
9753
  res.seenFirstVideoKeyframe = false;
9731
9754
  res.rtpSentVideoConfig = false;
9732
9755
  }
9733
- if (this.dedicatedSessionRelease) {
9734
- const release = this.dedicatedSessionRelease;
9735
- this.dedicatedSessionRelease = void 0;
9736
- release().catch(() => {
9737
- });
9738
- }
9739
9756
  this.logger.info(
9740
9757
  `[rebroadcast] native stream ended (camera sleeping or connection lost) profile=${this.profile} channel=${this.channel} clients=${this.connectedClients.size}`
9741
9758
  );
9742
- if (this.connectedClients.size > 0) {
9743
- this.logger.info(
9744
- `[rebroadcast] restarting native stream for ${this.connectedClients.size} active client(s)`
9745
- );
9746
- setImmediate(() => void this.startNativeStream());
9747
- }
9759
+ const releaseAndRestart = async () => {
9760
+ if (this.dedicatedSessionRelease) {
9761
+ const release = this.dedicatedSessionRelease;
9762
+ this.dedicatedSessionRelease = void 0;
9763
+ try {
9764
+ await release();
9765
+ } catch {
9766
+ }
9767
+ }
9768
+ if (this.connectedClients.size > 0) {
9769
+ this.logger.info(
9770
+ `[rebroadcast] restarting native stream for ${this.connectedClients.size} active client(s)`
9771
+ );
9772
+ await new Promise((r) => setTimeout(r, 500));
9773
+ void this.startNativeStream();
9774
+ }
9775
+ };
9776
+ void releaseAndRestart();
9748
9777
  }
9749
9778
  });
9750
9779
  this.nativeFanout.start();
@@ -9968,6 +9997,31 @@ var BaichuanRtspServer = class _BaichuanRtspServer extends import_node_events2.E
9968
9997
  getClientCount() {
9969
9998
  return this.connectedClients.size;
9970
9999
  }
10000
+ /**
10001
+ * Subscribe to the raw native stream for diagnostic purposes.
10002
+ * The subscriber receives the same frames as RTSP clients.
10003
+ * Counts as a "consumer" for lifecycle — prevents auto-stop while subscribed.
10004
+ * If the native stream is not active, starts it automatically.
10005
+ */
10006
+ async subscribeDiagnostic(id) {
10007
+ this.connectedClients.add(`diag:${id}`);
10008
+ if (!this.nativeStreamActive) {
10009
+ await this.startNativeStream();
10010
+ }
10011
+ return this.nativeFanout.subscribe(`diag:${id}`);
10012
+ }
10013
+ /**
10014
+ * Unsubscribe a diagnostic session.
10015
+ */
10016
+ unsubscribeDiagnostic(id) {
10017
+ this.removeClient(`diag:${id}`);
10018
+ }
10019
+ /**
10020
+ * Returns detected audio metadata (available after first audio frame).
10021
+ */
10022
+ getAudioInfo() {
10023
+ return this.audioInfo;
10024
+ }
9971
10025
  };
9972
10026
 
9973
10027
  // src/reolink/baichuan/ReolinkBaichuanApi.ts