@decartai/sdk 0.1.1 → 0.1.3

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.
@@ -50,6 +50,10 @@ declare const realTimeClientConnectOptionsSchema: z.ZodObject<{
50
50
  "720p": "720p";
51
51
  "1080p": "1080p";
52
52
  }>>;
53
+ preferredVideoCodec: z.ZodOptional<z.ZodEnum<{
54
+ h264: "h264";
55
+ vp9: "vp9";
56
+ }>>;
53
57
  }, z.core.$strip>;
54
58
  type RealTimeClientConnectOptions = Omit<z.infer<typeof realTimeClientConnectOptionsSchema>, "model"> & {
55
59
  model: ModelDefinition | CustomModelDefinition;
@@ -21,7 +21,8 @@ const realTimeClientConnectOptionsSchema = z.object({
21
21
  initialState: realTimeClientInitialStateSchema.optional(),
22
22
  queryParams: z.record(z.string(), z.string()).optional(),
23
23
  mirror: z.union([z.literal("auto"), z.boolean()]).optional(),
24
- resolution: z.enum(["720p", "1080p"]).optional()
24
+ resolution: z.enum(["720p", "1080p"]).optional(),
25
+ preferredVideoCodec: z.enum(["h264", "vp9"]).optional()
25
26
  });
26
27
  const createRealTimeClient = (opts) => {
27
28
  const { baseUrl, apiKey, integration } = opts;
@@ -29,7 +30,7 @@ const createRealTimeClient = (opts) => {
29
30
  const connect = async (stream, options) => {
30
31
  const parsedOptions = realTimeClientConnectOptionsSchema.safeParse(options);
31
32
  if (!parsedOptions.success) throw parsedOptions.error;
32
- const { onRemoteStream, onConnectionChange, onQueuePosition, initialState, resolution } = parsedOptions.data;
33
+ const { onRemoteStream, onConnectionChange, onQueuePosition, initialState, resolution, preferredVideoCodec } = parsedOptions.data;
33
34
  const mirror = parsedOptions.data.mirror ?? false;
34
35
  let inputStream = stream ?? new MediaStream();
35
36
  let mirroredStream;
@@ -63,6 +64,7 @@ const createRealTimeClient = (opts) => {
63
64
  onStats: (stats) => emitOrBuffer("stats", stats)
64
65
  });
65
66
  const safariCodec = isDesktopSafari() ? "vp8" : void 0;
67
+ const publishCodec = safariCodec ?? preferredVideoCodec;
66
68
  session = new StreamSession({
67
69
  url: `${url}?${new URLSearchParams({
68
70
  ...safariCodec ? { livekit_server_codec: safariCodec } : {},
@@ -78,7 +80,7 @@ const createRealTimeClient = (opts) => {
78
80
  initialImageRef,
79
81
  initialPrompt,
80
82
  logger,
81
- videoCodec: safariCodec
83
+ videoCodec: publishCodec
82
84
  });
83
85
  let sessionId = null;
84
86
  let subscribeToken = null;
@@ -34,6 +34,7 @@ const REALTIME_CONFIG = {
34
34
  },
35
35
  defaultVideoCodec: "h264",
36
36
  defaultMaxVideoBitrateBps: 35e5,
37
+ vp9MaxVideoBitrateBps: 3e6,
37
38
  defaultPublishFps: 30
38
39
  },
39
40
  observability: {
@@ -1,18 +1,19 @@
1
1
  import { createConsoleLogger } from "../utils/logger.js";
2
2
  import { REALTIME_CONFIG } from "./config-realtime.js";
3
3
  import mitt from "mitt";
4
- import { Room, RoomEvent, Track, TrackEvent } from "livekit-client";
4
+ import { Room, RoomEvent, Track } from "livekit-client";
5
5
  //#region src/realtime/media-channel.ts
6
6
  function getDefaultVideoPublishOptions(videoCodec) {
7
- const videoEncoding = {
8
- maxBitrate: REALTIME_CONFIG.livekit.defaultMaxVideoBitrateBps,
9
- maxFramerate: REALTIME_CONFIG.livekit.defaultPublishFps
10
- };
7
+ const resolvedCodec = videoCodec ?? REALTIME_CONFIG.livekit.defaultVideoCodec;
8
+ const maxBitrate = resolvedCodec === "vp9" ? REALTIME_CONFIG.livekit.vp9MaxVideoBitrateBps : REALTIME_CONFIG.livekit.defaultMaxVideoBitrateBps;
11
9
  return {
12
10
  source: Track.Source.Camera,
13
- videoCodec: videoCodec ?? REALTIME_CONFIG.livekit.defaultVideoCodec,
14
- simulcast: true,
15
- videoEncoding
11
+ videoCodec: resolvedCodec,
12
+ simulcast: resolvedCodec !== "vp9",
13
+ videoEncoding: {
14
+ maxBitrate,
15
+ maxFramerate: REALTIME_CONFIG.livekit.defaultPublishFps
16
+ }
16
17
  };
17
18
  }
18
19
  var MediaChannel = class {
@@ -39,16 +40,13 @@ var MediaChannel = class {
39
40
  room.on(RoomEvent.TrackSubscribed, (track, _pub, participant) => {
40
41
  if (!participant.identity.startsWith(REALTIME_CONFIG.livekit.inferenceServerIdentityPrefix)) return;
41
42
  if (track.kind !== Track.Kind.Video && track.kind !== Track.Kind.Audio) return;
42
- track.attach();
43
43
  const mediaStreamTrack = track.mediaStreamTrack;
44
44
  if (mediaStreamTrack) {
45
- this.remoteStream ??= new MediaStream();
46
- if (!this.remoteStream.getTracks().includes(mediaStreamTrack)) this.remoteStream.addTrack(mediaStreamTrack);
45
+ const tracks = this.remoteStream?.getTracks() ?? [];
46
+ if (!tracks.includes(mediaStreamTrack)) tracks.push(mediaStreamTrack);
47
+ this.remoteStream = new MediaStream(tracks);
47
48
  this.events.emit("remoteStream", this.remoteStream);
48
49
  }
49
- track.on(TrackEvent.VideoPlaybackStarted, () => {
50
- this.events.emit("firstFrame");
51
- });
52
50
  });
53
51
  room.on(RoomEvent.Disconnected, (reason) => {
54
52
  this.logger.warn("livekit: room disconnected", { reason });
@@ -262,6 +262,9 @@ var SignalingChannel = class {
262
262
  queueSize: msg.queue_size
263
263
  });
264
264
  break;
265
+ case "generation_started":
266
+ this.events.emit("generationStarted");
267
+ break;
265
268
  case "generation_tick":
266
269
  this.events.emit("generationTick", { seconds: msg.seconds });
267
270
  break;
@@ -165,7 +165,11 @@ var StreamSession = class {
165
165
  this.queue = qp;
166
166
  this.events.emit("queuePosition", qp);
167
167
  });
168
- this.signaling.on("generationTick", (e) => this.events.emit("generationTick", e));
168
+ this.signaling.on("generationStarted", () => this.markGenerating());
169
+ this.signaling.on("generationTick", (e) => {
170
+ this.markGenerating();
171
+ this.events.emit("generationTick", e);
172
+ });
169
173
  this.signaling.on("generationEnded", (e) => this.events.emit("generationEnded", e));
170
174
  this.signaling.on("serverError", (err) => this.events.emit("error", err));
171
175
  this.signaling.on("closed", (info) => this.handleConnectionLoss({
@@ -173,11 +177,11 @@ var StreamSession = class {
173
177
  ...info
174
178
  }));
175
179
  }
180
+ markGenerating() {
181
+ if (this.state === "connected") this.setState("generating");
182
+ }
176
183
  wireMediaEvents() {
177
184
  this.media.on("remoteStream", (stream) => this.events.emit("remoteStream", stream));
178
- this.media.on("firstFrame", () => {
179
- if (this.state === "connected") this.setState("generating");
180
- });
181
185
  this.media.on("disconnected", (info) => this.handleConnectionLoss({
182
186
  source: "media",
183
187
  reason: info.reason
@@ -81,11 +81,11 @@ const createRealTimeSubscribeClient = (opts) => {
81
81
  activeRoom.on(RoomEvent.TrackSubscribed, (track, _pub, participant) => {
82
82
  if (!participant.identity.startsWith(REALTIME_CONFIG.livekit.inferenceServerIdentityPrefix)) return;
83
83
  if (track.kind !== Track.Kind.Video && track.kind !== Track.Kind.Audio) return;
84
- track.attach();
85
84
  const mediaStreamTrack = track.mediaStreamTrack;
86
85
  if (!mediaStreamTrack) return;
87
- remoteStream ??= new MediaStream();
88
- if (!remoteStream.getTracks().includes(mediaStreamTrack)) remoteStream.addTrack(mediaStreamTrack);
86
+ const tracks = remoteStream?.getTracks() ?? [];
87
+ if (!tracks.includes(mediaStreamTrack)) tracks.push(mediaStreamTrack);
88
+ remoteStream = new MediaStream(tracks);
89
89
  options.onRemoteStream(remoteStream);
90
90
  });
91
91
  activeRoom.on(RoomEvent.ConnectionStateChanged, (state) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decartai/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Decart's JavaScript SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",