Skip to content

Releases: signalwire/signalwire-js

@signalwire/js v3.29

09 Jul 14:16
7732e79
Compare
Choose a tag to compare

Summary

This release improves the websocket connection and stability significantly. It also focuses on microphone controls, participant management, and Call Fabric SDK enhancements.

Key additions include new microphone control features (auto gain, echo cancellation, noise suppression), the ability to mute/unmute all participants simultaneously, and improved Call Fabric SDK functionality with fromFabricAddressId parameter support and configurable default media parameters. Additionally, this release fixes critical issues with push notifications, improves WebSocket reconnection handling, and resolves various type interface inconsistencies for a more stable development experience.


Added

1. Microphone controls for self and other members

Added support for microphone control features including auto gain, echo cancellation, and noise suppression.

New FabricMemberContract controls:

  • member.auto_gain
  • member.echo_cancellation
  • member.noise_suppression

New function support:

await FabricRoomSession.setAudioFlags({
  autoGain: false,
  echoCancellation: false,
  noiseSuppression: false,
});

2. Mute/unmute controls for all participants

Added support for muting and unmuting audio and video for all participants in both audio-only and video calls.

// Mute all members' audio
await FabricRoomSession.audioMute({ memberId: "all" });

// Unmute all members' audio
await FabricRoomSession.audioUnmute({ memberId: "all" });

// Mute all members' video
await FabricRoomSession.videoMute({ memberId: "all" });

// Unmute all members' video
await FabricRoomSession.videoUnmute({ memberId: "all" });

3. CF SDK: Support for fromFabricAddressId parameter

Added the ability to pass fromFabricAddressId when dialing.

const call = await SignalWireClient.dial({
  // ... other parameters
  to: "...",
  fromFabricAddressId: "valid_subscriber_id", // Optional
  // ... other parameters
});

4. CF SDK: Default media parameters

Added support for configuring default media parameters during call setup.

await call.dial({
  applyLocalVideoOverlay: false, // Should the SDK apply local video overlay? Default: true
  applyMemberOverlay: true, // Should the SDK apply member video overlays? Default: true
  stopCameraWhileMuted: true, // Should the SDK stop the camera when muted? Default: true
  stopMicrophoneWhileMuted: true, // Should the SDK stop the mic when muted? Default: true
  mirrorLocalVideoOverlay: false, // Should the SDK mirror the local video overlay? Default: true
});

Fixed

1. Handle push notifications without enabling websocket connection

Added an optional handlePushNotification method to allow developers to receive push notifications without being online via websocket.

SignalWireContract.handlePushNotification(params: HandlePushNotificationParams)

Previously, receiving push notifications required calling SignalWireContract.online() which automatically made you online on websocket as well.

2. CF SDK: Raise hand functionality

Fixed raise hand call and member capability issues.

3. Pagination interfaces

Exposed pagination interfaces for better type safety:

  • PaginatedResponse
  • PaginatedResult

4. WebSocket reconnection improvements

Improved WebSocket reconnections and re-subscription to voice call topics after socket reconnects.

5. Type interface fixes

Fixed type interfaces for getMessages and getMembers methods.

@signalwire/swaig 0.0.1

05 Mar 13:51
1223c4a
Compare
Choose a tag to compare

Summary

We have updated the dependencies to make sure security vulnerabilities are patched, and performance improvements are made.

@signalwire/realtime-api 4.1.1

05 Mar 13:50
1223c4a
Compare
Choose a tag to compare

Summary

This release of the Realtime API SDK includes bug fixes and improvements. Further, dependencies have been updated to ensure stability.

Fixed

  1. Chat message subscription are now resilient to websocket reconnections.

@signalwire/js v3.28.1

05 Mar 13:52
1223c4a
Compare
Choose a tag to compare

Summary

This release introduces Call Fabric and Video SDK enhancements, including new APIs for room management,
media renegotiation, member overlays, chat messaging, user hand raising, and more. In the Call Fabric interface, several
types and interfaces have been refined or added for better clarity, and default call behavior is now audio-only for a
more optimized initial setup. Additionally, we've introduced convenient methods for sorting addresses, reattaching calls,
and handling conversations. Numerous fixes address type inconsistencies, event handling, and memory leaks,
ensuring a more stable and efficient development experience.


Added

1. Lock/Unlock Methods

New lock and unlock methods on FabricRoomSession to restrict and restore entry to a specific room.

await call.lock()
await call.unlock()

2. Set Member Position API

Allows you to move a member to a specific position within the room layout.

await roomSession.setPositions({ positions: { self: "standard-2" }})

3. Member Overlays

Expose overlays on top of video elements for each member to display additional member information or custom UI for the Call Fabric and Video SDK.

4. Raise/Lower Hand

Call Fabric SDK now supports raising and lowering the participant's hand.

await roomSession.setRaisedHand({ raised: true })
await roomSession.setRaisedHand({ raised: false })

5. Chat Namespace in Call Fabric

New chat methods to handle sending and receiving chat messages within a room or call context.

const messages = await client.chat.getMessages({ addressId: 'id' })
const sub = await client.chat.subscribe({ addressId: 'id', onMessage: console.log })
await client.chat.sendMessage({ addressId: 'id', text: 'hello' })

6. Reattach Method

A new reattach method has been introduced for the Call Fabric client to reattach a call without starting from scratch.

const call = await client.reattach({
  to: `/public/${roomName}`,
  rootElement: document.getElementById('rootElement'),
})

7. Expose Room Layout

The FabricRoomSession object now provides direct access to the current room layout.

const call = await client.dial({ ... })
await call.start()
call.currentLayout;

8. Sort Parameters on Addresses

You can now use sort parameters when fetching addresses on the server side for more organized data retrieval.

const response = await client.address.getAddresses({
  type: 'room',
  sortBy: 'name',
  sortOrder: 'desc',
  pageSize: 3,
})

9. User Variables Param

Added a userVariables parameter to both DialOption and SignalWireClientParams to send additional metadata.

const call = await SignalWire({
  ...params,
  userVariables: { name: 'Jane Doe', email: 'john.doe@gmail.com' },
})

// Or
const call = await client.dial({
  ...params,
  userVariables: { name: 'Jane Doe', email: 'john.doe@gmail.com' },
})

10. New Media APIs with Renegotiation

Dynamically set or change the audio/video direction (sendonly, recvonly, sendrecv, inactive) and apply new MediaTrackConstraints during an active session.

await updateMedia({
  audio: {
    enable: true,
    direction: 'send' | 'sendrecv',
    constraints?: MediaTrackConstraints
  },
  video: {
    enable: false,
    direction: 'none' | 'receive'
  }
})

await setVideoDirection('send' | 'sendrecv' | 'none' | 'receive')
await setAudioDirection('send' | 'sendrecv' | 'none' | 'receive')

11. Screen Share Feature

Screen sharing is now baked into the Call Fabric SDK for simpler real-time collaboration.

const screenShare = await call 
    .startScreenShare({
      audio: true,
      video: true,
      ...opts,
    })
    .catch((error) => {
      console.error('ScreenShare Error', error)
    })

await screenShare.hangup()

12. Conversations Join API

Seamlessly join existing conversations in the CF SDK.

await client.conversation.join({
  addressId: id,
})

13. Fetch Address by Name

New name parameter to client.address.getAddress for retrieving addresses using their name.

const addressByName = await client.address.getAddress({ name: "john doe" })

Changed

1. Remove Implicit Re-authentication

Call Fabric SDK no longer tries to automatically reauthenticate, giving you full control over session auth flow.

The onRefreshToken is no longer available for the CF SDK that performed the implicit re-authentication.

With the new changes, the application needs to call the updateToken function to perform the explicit re-authentication.

await client.updateToken('newToken');

2. Default Audio-Only

Dialing a Call Fabric room (e.g. client.dial()) defaults to audio-only unless otherwise specified.

const call = await client.dial({address: `/public/${roomName}`}) // now defaults to audio-only
const call = await client.dial({address: `/public/${roomName}?channel=video`}) // use channel parameter to explicitly request video

3. User Params Priority for client.dial

User-defined parameters (e.g., audio, video, negotiateAudio, negotiateVideo) now override or get higher priority than the channel specified in the resource address when dialing a call with client.dial.

4. Screen Share Error Handling

Call.startScreenShare() now throws an error if the user denies screen sharing permission.

5. Internal Video Layout Layer

The InternalVideoLayoutLayer interface type is now publicly exposed.

6. Enumerate Devices by Kind

Browser SDKs can now leverage a more specialized enumerateDevicesByKind method for microphone, camera, and more.

import { enumerateDevicesByKind } from '@signalwire/js'
const devices = await enumerateDevicesByKind('videoinput') // "videoinput", "audioinput" or "audiooutput"

7. Expose FabricRoomSession Type

Types for FabricRoomSession are now exported for easier type-checking and integration.

8. Address ID in Conversation

The CF SDK ConversationContract now exposes the addressId for more direct resource referencing

9. Negotiate Audio/Video

You can set the audio/video negotiation parameters to better control media usage while dialing a call.

const call = await client.dial({
  address: `/public/room`,
  negotiateAudio: true,
  negotiateVideo: false,
})

10. Updated Conversation/Address Schemas

New properties were added to ConversationMessage, GetAddressResponse, and GetSubscriberInfoResponse interfaces for expanded functionality.

11. Unsubscribe from Conversations

CF SDK allows unsubscribing from conversation updates, giving you more fine-grained control over event listening.

const { unsubscribe } = await client.conversation.subscribe(() => { /* ... */ })
unsubscribe();

12. Dedicated Types for Video and Fabric SDKs

Clear separation of types for each SDK to reduce confusion and potential collisions. The Video SDK and the Call Fabric SDK are now distinct types.
For example, FabricRoomSession and VideoRoomSession are now distinct types which both derive from BaseRoomSession.

Fixed

  1. New types have been added and incorrect type definitions have been fixed:
    • ConversationMessageEventParams.type is now string instead of MessageType
    • ConversationContract has been added
    • Types for VideoLayout and other layout related types fixed
  2. Chat Messages filtering for previous and next pages have been fixed
  3. The getAddress method now returns a normalized response
  4. Local audio_muted and video_muted state for Call will now reflect the actual state
  5. Typos in type names have been fixed for ConversationChatMessagesSubscribeParams and ConversationChatMessagesSubscribeResult

@signalwire/js v3.27.0

06 Jun 11:59
fcd913c
Compare
Choose a tag to compare

Summary

This release brings significant enhancements and new features to the SignalWireClient, focusing on improved video handling, expanded API capabilities, and better user management:

  1. Video Handling:

    • New buildVideoElement function to easily create and manage video elements for calls and rooms.
    • Video streams now automatically adjust to occupy the full width of the specified container.
  2. Enhanced API Capabilities:

    • Added methods for managing addresses and conversations, including fetching details, sending messages, and subscribing to updates.
    • New functionality to handle user variables when dialing calls, enabling more personalized and detailed session information.
  3. User Management:

    • Introduced methods to get subscriber info and manage WebRTC endpoints' online/offline status.
  4. Unified Notifications:

    • Unified approach for handling incoming call notifications via WebSocket and Push Notification, simplifying the development process.
  5. Improved Flexibility:

    • Options to specify video/audio constraints while making calls, allowing for more customized call setups.

These updates collectively aim to provide a more flexible, powerful, and user-friendly experience for developers using the SignalWireClient.


Added

  1. userVariables param added when dialing a Fabric call
const client = await SignalWire({
  host: ...
  token: ...,
})

const call = await client.dial({
      ...params,
      rootElement: document.getElementById('rootElement'),
      userVariables: {
                "name": "John Doe",
                "email": "johndoe@signalwire.com",
               //...
                "fullBrowserVersion": "125.0.0.0",
                "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
            }
    })

2.  buildVideoElement function that creates and optionally injects a video DOM element for a given Call or Room object

const call = await client.dial({
   // ...
})
await call.start();

const { element, unsubscribe } = await buildVideoElement({
   room: call,
})
const container = document.getElementById('container');
container.appendChild(element)

Or, to also implicitly inject the video DOM element into your chosen container:

const { element, unsubscribe } = await buildVideoElement({
   room: call,
   rootElement: document.getElementById('container'), 
})

  1. getAddress method added to the address namespace in SignalWireClient which returns the details about a particular address id
client.address.getAddress({id: <address_id_to_fetch_details>})

  1. getConversations, getConversationMessages, createConversationMessage methods added to the conversation namespace in SignalWireClient
const conversations = await client.conversation.getConversations()

const conversationMessages = await client.conversation.getConversationMessages({ addressId: '...' })

// Subscribe to updates
client.conversation.subscribeToUpdates((newConversation) => {
  console.log('>> newConversation', newConversation)
})

  1. SignalWireClient.getSubscriberInfo method returns the info about the current subscriber
const subscriber = await client.getSubscriberInfo()

  1. online and offline methods added to SignalWireClient to register/unregister the WebRTC endpoint
await client.online()
//or
await client.offline()

  1. sendMessage and getMessages methods added to the conversation namespace
const result = await client.conversation.getConversations();
const convo = result.data.filter(c => c.id == <address_id>)[0];
convo.sendMessage({
  text: 'hello world~',
})
await convo.getMessages()

  1. Ability to specify page size when querying for the conversation and the address namespace
await client.conversation.getConversations({ pageSize: 10 });

await client.conversation.getMessages({ pageSize: 10 });

await client.conversation.getConversationMessages({ pageSize: 10 });

const addressData = await client.address.getAddresses({
   type: 'room',
   displayName: 'john doe',
   pageSize: 10
})

Changed

  1. The video stream will occupy the full width of the rootElement container (breaking)

  1. Handling notifications of incoming calls via both WebSocket and Push Notification is now unified (breaking)
// register invitation callback for push notification only
client.online({pushNotification: __incomingCallNotification})

// register invitation callback for both push notification and websocket
client.online({all: __incomingCallNotification})

//accept call using the invite notification
function __incomingCallNotification(invite){
  const call = await invite.accept(document.getElementById('rootElement'))
}

  1. Both SignalWireClient.dial and CallInvite.accept methods now accept an optional rootElement parameter to specify where to put the video stream
invite.accept(document.getElementById('rootElement'))

const call = await client.dial({
    // ...
      rootElement: document.getElementById('rootElement')
    });

  1. member.joined event now emitted for all members in a call.joined event

  1. Users can now pass video/audio constraints while making a call.
const call = await client.dial({
  to: "/public/some_resource",
  video: false, // boolean | MediaTrackConstraints
  audio: true, // boolean | MediaTrackConstraints
})

@signalwire/realtime-api v4.0.0

17 Apr 17:26
1ac1bd5
Compare
Choose a tag to compare

Release of @signalwire/realtime-api v4.0.0

This marks the release of SignalWires new Relay Realtime-api v4 SDK. This SDK strives to model the SDK after the concept of PUC (Programmable Unified Communications.) The v4 SDK will include all the namespaces that were originally included in the v3 SDK:

  • Voice
  • Messaging
  • Chat
  • Video
  • PubSub
  • Task

Setting Up a Single Client in v4

  • In Relay v4, a single client instance provides access to all namespaces, simplifying the development process and reducing code complexity. This unified client architecture makes the system more maintainable and efficient, offering a streamlined approach to accessing different functionalities within the Relay ecosystem.
    This shift in architecture reflects a more modern and developer-friendly approach, focusing on ease of integration and simplicity, which are key in today's fast-paced development environments.

Setting Up a Single Client in v4:

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" });

// Access voice functionalities through the unified client
const voiceClient = client.voice;
const messagingClient = client.messaging;

Advanced Event Listening in Relay v4

Relay v4 introduces a new approach, offering more granular control over applications by allowing
listening to events not only on the Call and RoomSession but also on particular sessions through a new method/parameter called listen.
Examples of some sessions that can be directly listened to are: Collects, Recordings, Playback, Detects, etc.

You can now listen to when this particular session has: Started, Updated, Failed, Ended, and some other session-specific events.

Example:

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" })

const voiceClient = client.voice;

// Setup a Voice Client and listen for incoming calls
await voiceClient.listen({
  topics: ["office"],
  onCallReceived: async (call) => {
    call.answer();
    console.log("Call received", call.id);

    // Start a call collect session
    await call.collect({
      digits: {
        max: 4,
        digitTimeout: 10,
        terminators: "#"
      },
      partialResults: true,
      sendStartOfInput: true,
      listen: {
        onStarted: () => {
          console.log("Collect started");
        },
        onInputStarted: (collect) => {
          console.log("Collect input started:", collect.result);
        },
        onUpdated: (collect) => {
          console.log("Collect updated:", collect.result);
        },
        onFailed: (collect) => {
          console.log("Collect failed:", collect.result);
        },
        onEnded: async (collect) => {
          console.log("Collect ended:", collect.result);

          // Play back the digits collected
          await call.playTTS({ text: `You entered ${collect.digits}` });
          call.hangup()
        }
      }
    }).onStarted();
  }
});

Code Examples

Voice

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" })


await client.voice.listen({
  topics: ["office"],
  onCallReceived: (call) => {
    call.answer();
    call.playTTS({ text: "Hello world" });
  }
});

Messaging

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here"})

let messageClient = client.messaging;

await messageClient.listen({
  topics: ["office"],
  async onMessageReceived(message) {
    console.log("Received message", message);
    const response = await messageClient.send({
      from: message.to,
      to: message.from,
      body: "Hello World!"
    });
    console.log("Sent message", await response);
  }
})

Chat

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" })

const chatClient = client.chat;

await chatClient.listen({
  channels: ["channel1"],
  onMemberJoined: async (member) => {

    let members = await chatClient.getMembers({
      channel: member.channel
    });
    let chatMessage = `Hello ${member.id}!
    There are ${members.members.length} members in this channel.
    The members are: ${members.members.map(m => m.id).join(", ")}`

    await chatClient.publish({
      channel: member.channel,
      content: chatMessage
    })
  }
});

Video

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" })

const videoClient = client.video;

await videoClient.listen({
  onRoomStarted: async (room) => {
    console.log("Room started", room.displayName);
  },
  onRoomEnded: async (room) => {
    console.log("Room ended", room.displayName);
  },
});

PubSub

import { SignalWire} from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here" })

const pubSubClient = client.pubSub;

await pubSubClient.listen({
  channels: ["welcome"],
  onMessageReceived: (message) => {
    console.log("Received message:", message);
  }
});

Task

import { SignalWire } from "@signalwire/realtime-api";

const client = await SignalWire({ project: "ProjectID Here", token: "Token Here"})

const taskClient = client.task

await taskClient.listen({
  topics: ['office'],
  onTaskReceived: (payload) => {
    console.log('Received task', payload)
  }
});

@signalwire/js v3.25.0

05 Dec 11:21
27b8538
Compare
Choose a tag to compare

Added

  • The Browser SDK for Video RoomSession objects now includes a new function, sendDigits, which enables users to transmit DTMF (Dual-Tone Multi-Frequency) tones within a RoomSession. This enhancement allows for the sending of specific tone signals, akin to those produced by telephone key presses, directly within the video session environment.
 room.sendDigits('1')
  • The hand-raise API is a new feature added to Video SDKs for both real-time and browser-based applications. It introduces a visual cue around a participant's video when they 'raise their hand', enhancing interaction in virtual meetings. This API lets participants indicate their wish to speak without interrupting the session. Key features include the ability for participants to raise or lower their hands, and for moderators to prioritize those who have raised their hands, thereby improving the management and structure of participation in online group sessions.
// `room` is an instance of a RoomSession
// 'member' is an instance of RoomSessionMember


// Raise hand (browser only)
await room.setRaisedHand()

// Lower hand (browser only)
await room.setRaisedHand({ raised: false })

// Raise hand for a specific member
await room.setRaisedHand({ memberId: '...' })

// Lower hand for a specific member
await room.setRaisedHand({ raised: false, memberId: '...' })

// Enable/disable handraise prioritization
await room.setPrioritizeHandraise(true)

// Raise or lower this member's hand.
await member.setRaisedHand()

// check if a member's hand is raised
console.log(member.handraised)

Fixes

  • Updated dependencies
  • Resolve CallCollect.ended() only when state is NOT collecting and final is either undefined or true, and result.type is a valid END_STATE

@signalwire/realtime-api v3.12

08 Nov 10:53
dfbe379
Compare
Choose a tag to compare

Added

  • Support for lock and unlock on RoomSessions. This will allow the locking of the RoomSession which will prevent new members from being able to join. Additionally, room previews are stopped and replaced with a locked image. The RoomSession can be unlocked through the unlock method.
const roomSession = new SignalWire.Video.RoomSession({
  token: "<YourRoomToken>",
  rootElement: document.getElementById("myVideoElement"),
});

// Short example that locks the room when a member joins and unlocks it when they leave.
roomSession.on("member.joined", (e) => {
  roomSession.lock();
});

roomSession.on("member.leave", (e) => {
  roomSession.unlock();
});
  • Support for nodeId. Optional parameter for dialSip and dialPhone that allows you to direct your calls through a specified node. This can help with efficient geolocation routing.
try {
  const call = await client.dialSip({
    from: "sip:xxx@yyy.zz",
    to: "sip:ppp@qqq.rr",
    timeout: 30,
    nodeId: "NODE ID HERE"
  });
} catch (e) {
  console.log("Call not answered.");
}

Updated

  • @singalwire/core dependency.

@signalwire/js v3.24.0

08 Nov 10:52
dfbe379
Compare
Choose a tag to compare

Added

  • Support for lock and unlock on RoomSessions. This will allow the locking of the RoomSession which will prevent new members from being able to join. Additionally, room previews are stopped and replaced with a locked image. The RoomSession can be unlocked through the unlock method.
const roomSession = new SignalWire.Video.RoomSession({
  token: "<YourRoomToken>",
  rootElement: document.getElementById("myVideoElement"),
});

// Short example that locks the room when a member joins and unlocks it when they leave.
roomSession.on("member.joined", (e) => {
  roomSession.lock();
});

roomSession.on("member.leave", (e) => {
  roomSession.unlock();
});

Fixed

  • Removed Video prefix from member.updated events to emit them properly.

Updated

  • @singalwire/webrtc dependency
  • @signalwire/core dependecy

@signalwire/swaig@0.0.0

18 Sep 17:48
217bdfe
Compare
Choose a tag to compare

Release of the SWAIG SDK

This SWAIG SDK will provide users the tools to build their own SWAIG server in Node.js to help with their AI Agent. Users will be able to define functions for the AI to utilize such as a transfer function, send SMS function, start streaming function, etc...

This SDK implementation simplifies the process of hosting a server for your SignalWire AI Agent to perform server-side processing.

Example

import { SWAIG } from '@signalwire/swaig'

const server = await SWAIG({
  user: "<USER_NAME_HERE>",
  password: "<PASSWORD_HERE>",
  generateMetaDataToken: () => uuid()
})

await server.addFunction({
  // user: "<USER_NAME_HERE>",
  // password: "<PASSWORD_HERE>",
  // token: "<META_DATA_TOKEN>", // to check

  name: "get_weather",
  purpose: "use when inquired about weather anywhere across the globe",
  argument: {
    properties: {
      location: {
        description: "the location to check the weather in",
        type: "string"
      }
    },
    type: "object"
  },
}, (params) => { /* implementation */ });

await server.run()

The above SWAIG server will expose the routes:

  • GET /
  • GET /get_weather

When the route /get_weather is requested from a SignalWire AI agent, it will perform the get_weather function.

Getting Started

To get started with the SWAIG SDK, please refer to our NPM package here