Releases: signalwire/signalwire-js
@signalwire/js v3.29
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
Summary
We have updated the dependencies to make sure security vulnerabilities are patched, and performance improvements are made.
@signalwire/realtime-api 4.1.1
Summary
This release of the Realtime API SDK includes bug fixes and improvements. Further, dependencies have been updated to ensure stability.
Fixed
- Chat message subscription are now resilient to websocket reconnections.
@signalwire/js v3.28.1
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
- New types have been added and incorrect type definitions have been fixed:
ConversationMessageEventParams.type
is nowstring
instead ofMessageType
ConversationContract
has been added- Types for
VideoLayout
and other layout related types fixed
- Chat Messages filtering for previous and next pages have been fixed
- The
getAddress
method now returns a normalized response - Local
audio_muted
andvideo_muted
state forCall
will now reflect the actual state - Typos in type names have been fixed for
ConversationChatMessagesSubscribeParams
andConversationChatMessagesSubscribeResult
@signalwire/js v3.27.0
Summary
This release brings significant enhancements and new features to the SignalWireClient, focusing on improved video handling, expanded API capabilities, and better user management:
-
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.
- New
-
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.
-
User Management:
- Introduced methods to get subscriber info and manage WebRTC endpoints' online/offline status.
-
Unified Notifications:
- Unified approach for handling incoming call notifications via WebSocket and Push Notification, simplifying the development process.
-
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
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'),
})
getAddress
method added to theaddress
namespace inSignalWireClient
which returns the details about a particular address id
client.address.getAddress({id: <address_id_to_fetch_details>})
getConversations
,getConversationMessages
,createConversationMessage
methods added to theconversation
namespace inSignalWireClient
const conversations = await client.conversation.getConversations()
const conversationMessages = await client.conversation.getConversationMessages({ addressId: '...' })
// Subscribe to updates
client.conversation.subscribeToUpdates((newConversation) => {
console.log('>> newConversation', newConversation)
})
SignalWireClient.getSubscriberInfo
method returns the info about the current subscriber
const subscriber = await client.getSubscriberInfo()
online
andoffline
methods added toSignalWireClient
to register/unregister the WebRTC endpoint
await client.online()
//or
await client.offline()
sendMessage
andgetMessages
methods added to theconversation
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()
- Ability to specify page size when querying for the
conversation
and theaddress
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
- The video stream will occupy the full width of the
rootElement
container (breaking)
- 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'))
}
- Both
SignalWireClient.dial
andCallInvite.accept
methods now accept an optionalrootElement
parameter to specify where to put the video stream
invite.accept(document.getElementById('rootElement'))
const call = await client.dial({
// ...
rootElement: document.getElementById('rootElement')
});
member.joined
event now emitted for all members in acall.joined
event
- 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
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
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 whenstate
is NOTcollecting
andfinal
is eitherundefined
ortrue
, andresult.type
is a validEND_STATE
@signalwire/realtime-api v3.12
Added
- Support for
lock
andunlock
on RoomSessions. This will allow the locking of theRoomSession
which will prevent new members from being able to join. Additionally, room previews are stopped and replaced with a locked image. TheRoomSession
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 fordialSip
anddialPhone
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
Added
- Support for
lock
andunlock
onRoomSessions
. This will allow the locking of theRoomSession
which will prevent new members from being able to join. Additionally, room previews are stopped and replaced with a locked image. TheRoomSession
can be unlocked through theunlock
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
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