jwt-sip.js
v0.1.0
Published
TypeScript SDK for SIP.js with JWT authentication and simplified VoIP functionality
Maintainers
Readme
jwt-sip.js
TypeScript SDK for SIP.js with JWT authentication and simplified VoIP functionality.
Installation
npm install jwt-sip.jsQuick Start
import { CallSDK } from 'jwt-sip.js';
const sdk = CallSDK.getInstance({
serverUrl: 'wss://your-sip-server.com',
appId: 'your-app-id',
secret: 'your-secret',
logLevel: 'info'
});
sdk.on('registered', () => console.log('Registered'));
sdk.on('callAnswered', () => console.log('Call answered'));
await sdk.register('1001', 'example.com', 'jwt-token');
await sdk.makeCall('sip:[email protected]');Configuration
interface CallSDKConfig {
serverUrl: string; // WebSocket URL (ws:// or wss://)
appId: string; // Application ID
secret: string; // Application secret
logLevel?: 'debug' | 'info' | 'warn' | 'error'; // Log level (default: 'warn')
audioDeviceId?: string; // Audio input device ID
remoteAudioElement?: HTMLAudioElement; // Custom audio element for remote audio
}Complete API Reference
Initialization
CallSDK.getInstance(config?, registrationOptions?)
Get or create SDK singleton instance.
Parameters:
config(CallSDKConfig, optional): Configuration object (required on first call)registrationOptions(RegistrationOptions, optional): Registration options
Returns: CallSDK instance
Example:
const sdk = CallSDK.getInstance({
serverUrl: 'wss://sip.example.com',
appId: 'my-app',
secret: 'my-secret',
logLevel: 'info',
audioDeviceId: 'default'
});Registration Methods
register(extension, domain, token)
Register with SIP server using JWT authentication.
Parameters:
extension(string): SIP extension numberdomain(string): SIP domaintoken(string): JWT authentication token
Returns: Promise
Example:
await sdk.register('1001', 'example.com', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');Events: registered, registrationFailed, registrationForbidden
unregister()
Unregister from SIP server.
Returns: Promise
Example:
await sdk.unregister();Events: unregistered
updateToken(token)
Update JWT token and trigger re-registration.
Parameters:
token(string): New JWT token
Returns: void
Example:
sdk.updateToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');Call Management Methods
makeCall(targetUri, options?)
Initiate outbound call.
Parameters:
targetUri(string): Target SIP URI or phone numberoptions(MakeCallOptions, optional):callId(string): Custom Call-ID (auto-generated if not provided)did(string): DID/Caller ID for routingtrace(boolean): Enable trace timestamp headerbusinessVars(Record<string, string>): Custom business variables
Returns: Promise
Example:
await sdk.makeCall('sip:[email protected]', {
did: '+84123456789',
trace: true,
businessVars: {
campaign: 'summer-sale',
agent: 'john-doe'
}
});Events: callCreated, callRinging, callAnswered, callFailed
hangup()
Terminate active call.
Returns: Promise
Example:
await sdk.hangup();Events: callEnded
acceptCall()
Accept incoming call.
Returns: Promise
Example:
sdk.on('incomingCall', async (data) => {
console.log('Incoming call from:', data.targetUri);
await sdk.acceptCall();
});Events: callAnswered
rejectCall()
Reject incoming call.
Returns: Promise
Example:
sdk.on('incomingCall', async () => {
await sdk.rejectCall();
});Events: callEnded
Call Operation Methods
hold()
Put active call on hold.
Returns: Promise
Example:
await sdk.hold();Events: callHeld
Note: Uses SDP manipulation (sendonly direction)
unhold()
Resume held call.
Returns: Promise
Example:
await sdk.unhold();Events: callResumed
mute()
Mute microphone (local only, no SIP signaling).
Returns: Promise
Example:
await sdk.mute();Events: callMuted
Note: Uses WebRTC track.enabled property
unmute()
Unmute microphone.
Returns: Promise
Example:
await sdk.unmute();Events: callUnmuted
blindTransfer(targetUri)
Transfer call to another destination (blind transfer).
Parameters:
targetUri(string): Transfer destination URI
Returns: Promise
Example:
await sdk.blindTransfer('sip:[email protected]');Events: transferInitiated, transferSucceeded, transferFailed
Note: Uses SIP REFER method, automatically terminates original call on success
Audio Control Methods
setAudioDeviceId(deviceId)
Set audio input device ID.
Parameters:
deviceId(string): Device ID from getUserMedia
Returns: void
Example:
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevice = devices.find(d => d.kind === 'audioinput');
sdk.setAudioDeviceId(audioDevice.deviceId);getAudioDeviceId()
Get current audio device ID.
Returns: string | null
Example:
const deviceId = sdk.getAudioDeviceId();
console.log('Current device:', deviceId);getRemoteAudioElement()
Get HTML audio element for remote audio.
Returns: HTMLAudioElement | null
Example:
const audioElement = sdk.getRemoteAudioElement();
if (audioElement) {
audioElement.volume = 0.5;
}setInputVolume(volume)
Set input volume (0-1).
Parameters:
volume(number): Volume level (0.0 to 1.0)
Returns: void
Example:
sdk.setInputVolume(0.8);getInputVolume()
Get current input volume.
Returns: number
Example:
const volume = sdk.getInputVolume();
console.log('Input volume:', volume);setOutputVolume(volume)
Set output volume (0-1).
Parameters:
volume(number): Volume level (0.0 to 1.0)
Returns: void
Example:
sdk.setOutputVolume(0.5);getOutputVolume()
Get current output volume.
Returns: number
Example:
const volume = sdk.getOutputVolume();
console.log('Output volume:', volume);State Management Methods
getState()
Get current SDK state.
Returns: SdkState
interface SdkState {
isInitialized: boolean;
isRegistered: boolean;
currentCall: CallSession | null;
registrationState: string;
}Example:
const state = sdk.getState();
console.log('Registered:', state.isRegistered);
console.log('Current call:', state.currentCall);getConfig()
Get current configuration.
Returns: CallSDKConfig | null
Example:
const config = sdk.getConfig();
console.log('Server URL:', config?.serverUrl);hasValidInputStream()
Check if valid input stream exists.
Returns: boolean
Example:
if (sdk.hasValidInputStream()) {
await sdk.makeCall('sip:[email protected]');
}getInputStreamTracks()
Get input stream tracks (deprecated).
Returns: MediaStreamTrack[]
Note: Deprecated - input streams are now created per call
Cleanup Methods
dispose()
Dispose SDK and cleanup resources.
Returns: Promise
Example:
await sdk.dispose();Events: disposed
Note: Terminates active calls, unregisters, stops UserAgent, clears all listeners
Events Reference
Registration Events
registered
Emitted when registration succeeds.
Data:
interface RegisteredEventData {
timestamp: number;
expires: number; // Registration expiry in seconds
}unregistered
Emitted when unregistration completes.
Data:
interface UnregisteredEventData {
timestamp: number;
}registrationFailed
Emitted when registration fails.
Data:
interface RegistrationFailedEventData {
timestamp: number;
statusCode: number;
reason: string;
}registrationForbidden
Emitted when registration is forbidden (403).
Data:
interface RegistrationForbiddenEventData {
timestamp: number;
statusCode: number;
reason: string;
}Call Lifecycle Events
callCreated
Emitted when call is created (before INVITE sent).
Data:
interface CallCreatedEventData {
callId: string;
targetUri: string;
timestamp: number;
direction: 'inbound' | 'outbound';
}callRinging
Emitted when call is ringing (180 Ringing received).
Data:
interface CallEventData {
callId: string;
targetUri?: string;
timestamp: number;
}callAnswered
Emitted when call is answered (200 OK received).
Data:
interface CallEventData {
callId: string;
targetUri?: string;
timestamp: number;
}callEnded
Emitted when call ends normally.
Data:
interface CallEndedEventData {
callId: string;
targetUri?: string;
timestamp: number;
reason?: string;
duration?: number; // Call duration in milliseconds
}callFailed
Emitted when call fails.
Data:
interface CallFailedEventData {
callId: string;
targetUri?: string;
timestamp: number;
error: string;
statusCode?: number;
}incomingCall
Emitted when incoming call received.
Data:
interface CallCreatedEventData {
callId: string;
targetUri: string;
timestamp: number;
direction: 'inbound';
}Call Operation Events
callHeld
Emitted when call is put on hold.
Data:
interface CallHeldEventData {
callId: string;
targetUri?: string;
timestamp: number;
}callResumed
Emitted when held call is resumed.
Data:
interface CallResumedEventData {
callId: string;
targetUri?: string;
timestamp: number;
}callMuted
Emitted when microphone is muted.
Data:
interface CallMutedEventData {
callId: string;
targetUri?: string;
timestamp: number;
}callUnmuted
Emitted when microphone is unmuted.
Data:
interface CallUnmutedEventData {
callId: string;
targetUri?: string;
timestamp: number;
}Transfer Events
transferInitiated
Emitted when transfer is initiated (REFER accepted).
Data:
interface TransferInitiatedEventData {
callId: string;
targetUri?: string;
timestamp: number;
transferTarget: string;
}transferSucceeded
Emitted when transfer succeeds (NOTIFY with 200).
Data:
interface TransferSucceededEventData {
callId: string;
targetUri?: string;
timestamp: number;
transferTarget: string;
}transferFailed
Emitted when transfer fails.
Data:
interface TransferFailedEventData {
callId: string;
targetUri?: string;
timestamp: number;
transferTarget: string;
reason: string;
statusCode?: number;
}Audio Events
audioInputFailed
Emitted when audio input fails.
Data:
interface AudioInputFailedEventData {
error: string;
timestamp: number;
}audioProcessingFailed
Emitted when audio processing fails.
Data:
interface AudioProcessingFailedEventData {
error: string;
timestamp: number;
}Connection Events
connected
Emitted when WebSocket connection established.
Data:
{
timestamp: number;
}disconnected
Emitted when WebSocket connection lost.
Data:
{
timestamp: number;
error?: string;
}disposed
Emitted when SDK is disposed.
Data:
{
timestamp: number;
}Error Handling
import { CallSDKError, ErrorCode } from 'jwt-sip.js';
try {
await sdk.makeCall('sip:[email protected]');
} catch (error) {
if (error instanceof CallSDKError) {
console.error('Error code:', error.code);
console.error('Message:', error.message);
console.error('Details:', error.details);
console.error('Timestamp:', error.timestamp);
}
}Error Codes
INVALID_CONFIG- Configuration validation failedINVALID_URI- Malformed SIP URIINVALID_STATE- Operation attempted in wrong stateCALL_IN_PROGRESS- Call already activeNO_ACTIVE_CALL- No active call for operationREGISTRATION_FAILED- Registration errorCALL_FAILED- Call setup failedOPERATION_FAILED- General operation failureSDK_DISPOSED- SDK has been disposedSDK_NOT_INITIALIZED- SDK not initializedAUTHENTICATION_FAILED- Authentication failedNETWORK_ERROR- Network connectivity errorTIMEOUT- Operation timeoutPERMISSION_DENIED- Browser permission denied
Audio Input Modes
Mode 1: Default (Auto)
SDK automatically requests microphone access per call.
const sdk = CallSDK.getInstance({
serverUrl: 'wss://sip.example.com',
appId: 'my-app',
secret: 'my-secret'
});Mode 2: Specific Device ID
SDK uses specified audio device for all calls.
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevice = devices.find(d => d.kind === 'audioinput');
const sdk = CallSDK.getInstance({
serverUrl: 'wss://sip.example.com',
appId: 'my-app',
secret: 'my-secret',
audioDeviceId: audioDevice.deviceId
});Mode 3: Per-Call Stream (Manual)
Application manages MediaStream creation per call.
const sdk = CallSDK.getInstance({
serverUrl: 'wss://sip.example.com',
appId: 'my-app',
secret: 'my-secret'
});
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
});
await sdk.makeCall('sip:[email protected]');Auto-Answer Support
SDK automatically detects and handles auto-answer headers:
X-Auto-Answer: trueCall-Info: answer-after=0Alert-Info: auto answer
When detected, SDK automatically calls acceptCall() after 100ms delay.
Example:
sdk.on('incomingCall', (data) => {
console.log('Incoming call:', data);
});
sdk.on('callAnswered', () => {
console.log('Call auto-answered');
});Complete Usage Example
import { CallSDK, CallSDKError, ErrorCode } from 'jwt-sip.js';
const sdk = CallSDK.getInstance({
serverUrl: 'wss://sip.example.com',
appId: 'my-app',
secret: 'my-secret',
logLevel: 'info',
audioDeviceId: 'default'
});
sdk.on('registered', (data) => {
console.log('Registered, expires in:', data.expires, 'seconds');
});
sdk.on('callAnswered', () => {
console.log('Call answered');
});
sdk.on('callEnded', (data) => {
console.log('Call ended, duration:', data.duration, 'ms');
});
sdk.on('incomingCall', async (data) => {
console.log('Incoming call from:', data.targetUri);
await sdk.acceptCall();
});
try {
await sdk.register('1001', 'example.com', 'jwt-token');
await sdk.makeCall('sip:[email protected]', {
did: '+84123456789',
trace: true
});
await new Promise(resolve => setTimeout(resolve, 5000));
await sdk.hold();
await new Promise(resolve => setTimeout(resolve, 2000));
await sdk.unhold();
await sdk.mute();
await new Promise(resolve => setTimeout(resolve, 2000));
await sdk.unmute();
await sdk.hangup();
await sdk.unregister();
await sdk.dispose();
} catch (error) {
if (error instanceof CallSDKError) {
console.error('SDK Error:', error.code, error.message);
}
}Examples
See examples/index.html for complete demo application with:
- Registration management
- Outbound/inbound calls
- Call controls (hold, mute, transfer)
- Audio device selection
- Real-time event logging
Development
npm install
npm run build
npm run serve-examplesVisit http://localhost:3000/examples/
License
SEE LICENSE IN LICENSE
