@unisphere/models-sdk-js 1.2.0 → 1.3.0

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.
package/index.esm.js CHANGED
@@ -4423,7 +4423,8 @@ class AvatarControlSDK {
4423
4423
  id: config.avatarId
4424
4424
  },
4425
4425
  voiceConfig: config.voiceId ? {
4426
- id: config.voiceId
4426
+ id: config.voiceId,
4427
+ modelId: 'eleven_flash_v2_5'
4427
4428
  } : undefined
4428
4429
  })
4429
4430
  });
@@ -4891,11 +4892,12 @@ class PeerConnectionManager {
4891
4892
  }
4892
4893
  const config = {
4893
4894
  iceServers: this.iceServers,
4894
- iceTransportPolicy: this.iceTransportPolicy
4895
+ iceTransportPolicy: this.iceTransportPolicy,
4896
+ bundlePolicy: 'max-bundle'
4895
4897
  };
4896
4898
  this.logger.info('Creating RTCPeerConnection');
4897
4899
  this.pc = new RTCPeerConnection(config);
4898
- // Setup event handlers
4900
+ // Setup event handlersCan you
4899
4901
  this.setupEventHandlers();
4900
4902
  this.logger.info('RTCPeerConnection created successfully');
4901
4903
  }
@@ -5272,32 +5274,30 @@ class AvatarRTCSDK {
5272
5274
  this.signalingManager = null;
5273
5275
  this.videoElement = null;
5274
5276
  this.state = ConnectionState.DISCONNECTED;
5275
- // Reconnection state
5276
- this.whepUrl = null;
5277
5277
  this.reconnectAttempts = 0;
5278
5278
  this.isReconnecting = false;
5279
5279
  // Event handlers
5280
5280
  this.eventHandlers = new Map();
5281
- this.iceServers = (config === null || config === void 0 ? void 0 : config.iceServers) || DEFAULT_ICE_SERVERS;
5282
- this.iceTransportPolicy = (config === null || config === void 0 ? void 0 : config.iceTransportPolicy) || 'all';
5283
- this.retryConfig = (config === null || config === void 0 ? void 0 : config.retryConfig) || DEFAULT_RETRY_CONFIG;
5284
- this.logger = (config === null || config === void 0 ? void 0 : config.logger) || createLogger('AvatarRTCSDK', parseLogLevel(config === null || config === void 0 ? void 0 : config.logLevel));
5285
- this.logger.info('Initialized AvatarRTCSDK');
5281
+ if (!config.whepUrl) {
5282
+ throw new AvatarError('WHEP URL is required', AvatarErrorCode.INVALID_ARGUMENT);
5283
+ }
5284
+ this.whepUrl = config.whepUrl;
5285
+ this.iceServers = config.iceServers || DEFAULT_ICE_SERVERS;
5286
+ this.iceTransportPolicy = config.iceTransportPolicy || 'all';
5287
+ this.retryConfig = config.retryConfig || DEFAULT_RETRY_CONFIG;
5288
+ this.logger = config.logger || createLogger('AvatarRTCSDK', parseLogLevel(config.logLevel));
5289
+ this.logger.info('Initialized AvatarRTCSDK with WHEP URL:', this.whepUrl);
5286
5290
  }
5287
5291
  /**
5288
5292
  * Connect to WebRTC endpoint using WHEP URL with retry logic
5289
- *
5290
- * @param whepUrl - WHEP URL for WebRTC signaling
5291
5293
  */
5292
- connect(whepUrl) {
5294
+ connect() {
5293
5295
  return __awaiter(this, void 0, void 0, function* () {
5294
- this.logger.info('Connecting to WHEP URL:', whepUrl);
5296
+ this.logger.info('Connecting to WHEP URL:', this.whepUrl);
5295
5297
  if (this.state === ConnectionState.CONNECTING || this.state === ConnectionState.CONNECTED) {
5296
5298
  this.logger.warn('Already connecting or connected, ignoring');
5297
5299
  return;
5298
5300
  }
5299
- // Store whepUrl for reconnection
5300
- this.whepUrl = whepUrl;
5301
5301
  this.reconnectAttempts = 0;
5302
5302
  this.setState(ConnectionState.CONNECTING);
5303
5303
  try {
@@ -5326,9 +5326,6 @@ class AvatarRTCSDK {
5326
5326
  */
5327
5327
  connectInternal() {
5328
5328
  return __awaiter(this, void 0, void 0, function* () {
5329
- if (!this.whepUrl) {
5330
- throw new AvatarError('WHEP URL not set', AvatarErrorCode.INVALID_ARGUMENT);
5331
- }
5332
5329
  // Create peer connection manager
5333
5330
  this.pcManager = new PeerConnectionManager({
5334
5331
  iceServers: this.iceServers,
@@ -5442,7 +5439,6 @@ class AvatarRTCSDK {
5442
5439
  // Stop any ongoing reconnection attempts
5443
5440
  this.isReconnecting = false;
5444
5441
  this.reconnectAttempts = 0;
5445
- this.whepUrl = null;
5446
5442
  // Stop video
5447
5443
  if (this.videoElement) {
5448
5444
  if (this.videoElement.srcObject) {
@@ -6498,6 +6494,7 @@ class KalturaAvatarSession {
6498
6494
  * @param config - Optional configuration
6499
6495
  */
6500
6496
  constructor(apiKey, config) {
6497
+ this.rtcSDK = null;
6501
6498
  this.state = SessionState.IDLE;
6502
6499
  this.sessionId = null;
6503
6500
  // Event handlers
@@ -6507,6 +6504,7 @@ class KalturaAvatarSession {
6507
6504
  }
6508
6505
  const logLevel = (config === null || config === void 0 ? void 0 : config.logLevel) || 'info';
6509
6506
  this.logger = createLogger('KalturaAvatarSession', parseLogLevel(logLevel));
6507
+ this.config = config;
6510
6508
  this.logger.info('Initializing Kaltura Avatar SDK');
6511
6509
  // Initialize Control SDK
6512
6510
  const controlConfig = {
@@ -6516,15 +6514,6 @@ class KalturaAvatarSession {
6516
6514
  logLevel
6517
6515
  };
6518
6516
  this.controlSDK = new AvatarControlSDK(controlConfig);
6519
- // Initialize RTC SDK
6520
- const rtcConfig = {
6521
- iceServers: config === null || config === void 0 ? void 0 : config.iceServers,
6522
- iceTransportPolicy: config === null || config === void 0 ? void 0 : config.iceTransportPolicy,
6523
- logger: this.logger
6524
- };
6525
- this.rtcSDK = new AvatarRTCSDK(rtcConfig);
6526
- // Setup RTC event handlers
6527
- this.setupRTCEventHandlers();
6528
6517
  this.logger.info('Kaltura Avatar SDK initialized');
6529
6518
  }
6530
6519
  /**
@@ -6539,6 +6528,7 @@ class KalturaAvatarSession {
6539
6528
  */
6540
6529
  createSession(options) {
6541
6530
  return __awaiter(this, void 0, void 0, function* () {
6531
+ var _a, _b;
6542
6532
  this.logger.info('Creating session with options:', options);
6543
6533
  // Validate state
6544
6534
  if (this.state !== SessionState.IDLE && this.state !== SessionState.ERROR) {
@@ -6563,11 +6553,35 @@ class KalturaAvatarSession {
6563
6553
  const initResponse = yield this.controlSDK.initClient(this.sessionId);
6564
6554
  const whepUrl = initResponse.whepUrl;
6565
6555
  this.logger.info('Client initialized, WHEP URL:', whepUrl);
6566
- // Step 3: Connect WebRTC
6567
- this.logger.info('Step 3: Connecting WebRTC');
6568
- yield this.rtcSDK.connect(whepUrl);
6556
+ // Convert TURN server fields to ICE servers format
6557
+ const iceServers = [{
6558
+ urls: [`turn:${initResponse.turn.url}:80?transport=udp`, `turn:${initResponse.turn.url}:443?transport=udp`, `turn:${initResponse.turn.url}:80?transport=tcp`],
6559
+ username: initResponse.turn.username,
6560
+ credential: initResponse.turn.credential
6561
+ }];
6562
+ this.logger.info('ICE servers configured:', iceServers);
6563
+ // Step 3: Initialize RTC SDK with WHEP URL and ICE servers from backend
6564
+ this.logger.info('Step 3: Initializing RTC SDK');
6565
+ const rtcConfig = {
6566
+ whepUrl,
6567
+ // Use ICE servers from backend response, fallback to config if not provided
6568
+ iceServers: iceServers || ((_a = this.config) === null || _a === void 0 ? void 0 : _a.iceServers),
6569
+ iceTransportPolicy: (_b = this.config) === null || _b === void 0 ? void 0 : _b.iceTransportPolicy,
6570
+ logger: this.logger
6571
+ };
6572
+ this.rtcSDK = new AvatarRTCSDK(rtcConfig);
6573
+ // Setup RTC event handlers
6574
+ this.setupRTCEventHandlers();
6575
+ // Step 4: Connect WebRTC
6576
+ this.logger.info('Step 4: Connecting WebRTC');
6577
+ yield this.rtcSDK.connect();
6569
6578
  this.setState(SessionState.READY);
6570
6579
  this.logger.info('Session ready');
6580
+ // Step 5: Auto-attach video if container ID provided
6581
+ if (options.videoContainerId) {
6582
+ this.logger.info('Auto-attaching avatar to container:', options.videoContainerId);
6583
+ this.attachAvatar(options.videoContainerId);
6584
+ }
6571
6585
  } catch (error) {
6572
6586
  this.logger.error('Failed to create session:', error);
6573
6587
  this.setState(SessionState.ERROR);
@@ -6577,14 +6591,35 @@ class KalturaAvatarSession {
6577
6591
  });
6578
6592
  }
6579
6593
  /**
6580
- * Attach avatar video to a video element
6594
+ * Attach avatar video to a div container by creating a video element inside it
6581
6595
  *
6582
- * @param videoElement - HTML video element to display avatar
6596
+ * @param containerId - ID of the div element to attach the avatar video to
6583
6597
  */
6584
- attachAvatar(videoElement) {
6585
- this.logger.info('Attaching avatar to video element');
6586
- if (!videoElement || !(videoElement instanceof HTMLVideoElement)) {
6587
- throw new AvatarError('Invalid video element', AvatarErrorCode.VIDEO_ELEMENT_INVALID);
6598
+ attachAvatar(containerId) {
6599
+ this.logger.info('Attaching avatar to container:', containerId);
6600
+ if (!containerId || typeof containerId !== 'string') {
6601
+ throw new AvatarError('Invalid container ID', AvatarErrorCode.INVALID_ARGUMENT);
6602
+ }
6603
+ if (!this.rtcSDK) {
6604
+ throw new AvatarError('RTC SDK not initialized. Create a session first.', AvatarErrorCode.INVALID_STATE);
6605
+ }
6606
+ // Find the container element
6607
+ const container = document.getElementById(containerId);
6608
+ if (!container) {
6609
+ throw new AvatarError(`Container element with ID '${containerId}' not found`, AvatarErrorCode.VIDEO_ELEMENT_INVALID);
6610
+ }
6611
+ // Create video element if it doesn't exist
6612
+ let videoElement = container.querySelector('video');
6613
+ if (!videoElement) {
6614
+ videoElement = document.createElement('video');
6615
+ videoElement.setAttribute('autoplay', '');
6616
+ videoElement.setAttribute('playsinline', '');
6617
+ videoElement.style.width = '100%';
6618
+ videoElement.style.height = '100%';
6619
+ container.appendChild(videoElement);
6620
+ this.logger.info('Created new video element in container');
6621
+ } else {
6622
+ this.logger.info('Using existing video element in container');
6588
6623
  }
6589
6624
  this.rtcSDK.attachVideo(videoElement);
6590
6625
  this.logger.info('Avatar attached');
@@ -6656,18 +6691,23 @@ class KalturaAvatarSession {
6656
6691
  this.setState(SessionState.ENDED);
6657
6692
  try {
6658
6693
  // Disconnect RTC first
6659
- this.rtcSDK.disconnect();
6694
+ if (this.rtcSDK) {
6695
+ this.rtcSDK.disconnect();
6696
+ }
6660
6697
  // End session with backend
6661
6698
  if (this.sessionId) {
6662
6699
  yield this.controlSDK.endSession(this.sessionId);
6663
6700
  this.sessionId = null;
6664
6701
  }
6702
+ // Clear RTC SDK reference
6703
+ this.rtcSDK = null;
6665
6704
  this.setState(SessionState.IDLE);
6666
6705
  this.logger.info('Session ended successfully');
6667
6706
  } catch (error) {
6668
6707
  this.logger.error('Error ending session:', error);
6669
6708
  // Set state to idle anyway to allow creating new session
6670
6709
  this.setState(SessionState.IDLE);
6710
+ this.rtcSDK = null;
6671
6711
  throw error;
6672
6712
  }
6673
6713
  });
@@ -6682,6 +6722,9 @@ class KalturaAvatarSession {
6682
6722
  * Get current connection state
6683
6723
  */
6684
6724
  getConnectionState() {
6725
+ if (!this.rtcSDK) {
6726
+ return ConnectionState.DISCONNECTED;
6727
+ }
6685
6728
  return this.rtcSDK.getConnectionState();
6686
6729
  }
6687
6730
  /**
@@ -6716,6 +6759,9 @@ class KalturaAvatarSession {
6716
6759
  * Setup event handlers for RTC SDK
6717
6760
  */
6718
6761
  setupRTCEventHandlers() {
6762
+ if (!this.rtcSDK) {
6763
+ return;
6764
+ }
6719
6765
  this.rtcSDK.on('connected', () => {
6720
6766
  this.emit('connectionChange', ConnectionState.CONNECTED);
6721
6767
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unisphere/models-sdk-js",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "author": "kaltura",
5
5
  "private": false,
6
6
  "license": "AGPL-3.0",
@@ -9,8 +9,16 @@
9
9
  * ```typescript
10
10
  * const session = new KalturaAvatarSession('your-api-key');
11
11
  *
12
+ * // Option 1: Auto-attach during session creation
13
+ * await session.createSession({
14
+ * avatarId: 'avatar-123',
15
+ * videoContainerId: 'avatar-container'
16
+ * });
17
+ *
18
+ * // Option 2: Attach manually after session creation
12
19
  * await session.createSession({ avatarId: 'avatar-123' });
13
- * session.attachAvatar(videoElement);
20
+ * session.attachAvatar('avatar-container');
21
+ *
14
22
  * await session.sayText('Hello from Kaltura Avatar!');
15
23
  * await session.endSession();
16
24
  * ```
@@ -21,8 +29,9 @@ import { AvatarConfig, ConnectionState, CreateSessionOptions, SessionState, Sess
21
29
  */
22
30
  export declare class KalturaAvatarSession {
23
31
  private readonly controlSDK;
24
- private readonly rtcSDK;
32
+ private rtcSDK;
25
33
  private readonly logger;
34
+ private readonly config;
26
35
  private state;
27
36
  private sessionId;
28
37
  private eventHandlers;
@@ -45,11 +54,11 @@ export declare class KalturaAvatarSession {
45
54
  */
46
55
  createSession(options: CreateSessionOptions): Promise<void>;
47
56
  /**
48
- * Attach avatar video to a video element
57
+ * Attach avatar video to a div container by creating a video element inside it
49
58
  *
50
- * @param videoElement - HTML video element to display avatar
59
+ * @param containerId - ID of the div element to attach the avatar video to
51
60
  */
52
- attachAvatar(videoElement: HTMLVideoElement): void;
61
+ attachAvatar(containerId: string): void;
53
62
  /**
54
63
  * Send audio file for the avatar to speak
55
64
  *
@@ -31,6 +31,15 @@ export interface InitClientResponse {
31
31
  success: boolean;
32
32
  /** WHEP URL for WebRTC connection */
33
33
  whepUrl: string;
34
+ /** TURN server configuration */
35
+ turn: {
36
+ /** TURN server URL */
37
+ url: string;
38
+ /** TURN server username */
39
+ username: string;
40
+ /** TURN server credential */
41
+ credential: string;
42
+ };
34
43
  /** Optional error message if initialization failed */
35
44
  error?: string;
36
45
  }
@@ -26,17 +26,15 @@ export declare class AvatarRTCSDK {
26
26
  private readonly iceServers;
27
27
  private readonly iceTransportPolicy;
28
28
  private readonly retryConfig;
29
- private whepUrl;
29
+ private readonly whepUrl;
30
30
  private reconnectAttempts;
31
31
  private isReconnecting;
32
32
  private eventHandlers;
33
- constructor(config?: RTCConfig);
33
+ constructor(config: RTCConfig);
34
34
  /**
35
35
  * Connect to WebRTC endpoint using WHEP URL with retry logic
36
- *
37
- * @param whepUrl - WHEP URL for WebRTC signaling
38
36
  */
39
- connect(whepUrl: string): Promise<void>;
37
+ connect(): Promise<void>;
40
38
  /**
41
39
  * Internal connection logic (without retry)
42
40
  */
@@ -7,6 +7,8 @@ import { RetryConfig } from '../types';
7
7
  * Configuration for the RTC SDK
8
8
  */
9
9
  export interface RTCConfig {
10
+ /** WHEP URL for WebRTC connection */
11
+ whepUrl: string;
10
12
  /** ICE servers for WebRTC connection */
11
13
  iceServers?: RTCIceServer[];
12
14
  /** ICE transport policy */
package/src/types.d.ts CHANGED
@@ -26,6 +26,8 @@ export interface CreateSessionOptions {
26
26
  avatarId: string;
27
27
  /** Optional voice ID for the avatar */
28
28
  voiceId?: string;
29
+ /** Optional ID of the div element to automatically attach the avatar video to */
30
+ videoContainerId?: string;
29
31
  }
30
32
  /**
31
33
  * Configuration for retry logic with exponential backoff