A Node.js addon that embeds PJSIP with complete session management - similar to baresip-node.
This project provides a professional Node.js wrapper for the PJSIP SIP stack with advanced session management capabilities. It includes all necessary PJSIP libraries bundled, so users don't need to install any additional dependencies.
- ✅ Real PJSIP Integration: Uses actual PJSIP C++ library
- ✅ Complete Session Management: JavaScript-layer session tracking with unique IDs
- ✅ SIP Registration: Full SIP registration with digest authentication
- ✅ Call Management: Make, answer, and hangup calls with session objects
- ✅ Callback-Based System: Clean callback system (no event stacking)
- ✅ Configuration Separation: Separate configs for Init, Register, and Invite
- ✅ Cross-Platform: Windows and macOS support
- ✅ Bundled Dependencies: All PJSIP libraries included - no external dependencies
- ✅ Electron Ready: Perfect for Electron Phone UI integration
- ✅ Client-Required API: Implements exact API structure as specified by client
- Node.js 18+ (or 20+/22+)
- C++ toolchain:
- Windows: MSVC 2022 Build Tools (for building from source)
- macOS: Xcode Command Line Tools (for building from source)
npm install pjsip-node
No additional dependencies required! All PJSIP libraries are bundled.
git clone <repository>
cd pjsip-node
npm install
npm run build
const api = require('pjsip-node');
// Set up callbacks (single-assignment system)
api.setCallbacks({
onReady: (info) => {
console.log('✅ PJSIP initialized');
// Register account after initialization
const reg = api.Register({
username: "1113",
password: "password",
domain: "pbx.sheerbit.com",
registrar: "sip:pbx.sheerbit.com:5060"
});
if (reg.ok) {
console.log('✅ Account registered with ID:', reg.data);
}
},
onRegisterSuccess: (e) => {
console.log('✅ Registration successful for:', e.data);
// Make an outgoing call
const inviteRes = api.Invite({
to: "sip:8080@pbx.sheerbit.com"
});
if (inviteRes.ok) {
console.log('✅ INVITE sent with call ID:', inviteRes.data);
}
},
onInvite: (e) => {
console.log('📞 Incoming INVITE from:', e.data.caller);
// Answer incoming calls
const answerRes = api.Answer({ callId: e.data.callId });
if (answerRes.ok) {
console.log('✅ Call answered');
}
},
onCallState: (e) => {
console.log(`📞 Call ${e.data.callId} state: ${e.data.state}`);
if (e.data.state === 'CONFIRMED') {
console.log('🔊 Media connected!');
}
},
onError: (err) => {
console.error('❌ Error:', err);
}
});
// Initialize PJSIP with global configuration
const initResult = api.Init({
logLevel: 4,
userAgent: "PJSIP Node.js Wrapper",
maxCalls: 10,
localPort: 5060,
transport: "UDP"
});
if (!initResult.ok) {
console.error('❌ Initialization failed:', initResult.message);
process.exit(1);
}
// Shutdown when done
setTimeout(() => {
api.Shutdown();
}, 30000);
const result = api.Init({
logLevel: 4, // 0-6 (0=disabled, 6=debug)
userAgent: "My App", // User agent string
maxCalls: 10, // Maximum concurrent calls
localPort: 5060, // Local SIP port
transport: "UDP" // Transport type
});
const result = api.Register({
username: "user", // SIP username
password: "password", // SIP password
domain: "domain.com", // SIP domain
registrar: "sip:domain.com:5060", // Registrar URI
displayName: "My Name", // Display name
expires: 3600 // Registration expiry (seconds)
});
const result = api.Invite({
to: "sip:8080@domain.com", // Destination URI
withVideo: false, // Enable video
audioCodec: "PCMU" // Preferred audio codec
});
Answer(config)
- Answer incoming callBye(config)
- Hangup callHold(config)
- Hold callUnhold(config)
- Unhold callMute(config)
- Mute audioUnmute(config)
- Unmute audioDtmf(config)
- Send DTMF tones
GetVersion()
- Get PJSIP versionGetLocalIP()
- Get local IP addressGetBoundPort()
- Get bound SIP portGetRegistrationStatus()
- Get account registration statusListCalls()
- List active callsShutdown()
- Shutdown PJSIP
The API uses a single-assignment callback system (no event stacking):
api.setCallbacks({
// Library events
onReady: (info) => { /* PJSIP initialized */ },
onError: (err) => { /* Error occurred */ },
onShutdown: () => { /* PJSIP shutdown */ },
// Registration events
onRegisterStart: (e) => { /* Registration started */ },
onRegisterSuccess: (e) => { /* Registration successful */ },
onRegisterFailed: (e) => { /* Registration failed */ },
onUnregister: (e) => { /* Unregistered */ },
// Call events
onInvite: (e) => { /* Incoming INVITE */ },
onCallState: (e) => { /* Call state changed */ },
onBye: (e) => { /* Call ended */ },
onHold: (e) => { /* Call held */ },
onUnhold: (e) => { /* Call unheld */ },
onDtmf: (e) => { /* DTMF received */ },
// Media events
onMediaState: (e) => { /* Media state changed */ },
onStats: (e) => { /* Media statistics */ }
});
This project has been developed through extensive collaboration to meet specific client requirements:
-
JavaScript Wrapper Architecture: Replaced TypeScript with a pure JavaScript wrapper (
lib/index.js
) that loads the native addon and provides a clean API interface. -
Callback-Based System: Implemented single-assignment callbacks instead of EventEmitter to prevent event stacking and ensure only one handler per event type.
-
API Configuration Separation:
Init(options)
- Global PJSIP configuration (log levels, bindings, etc.)Register(options)
- Account-specific configuration (username, password, etc.)Invite(options)
- Session-specific configuration (To, From, WithVideo, etc.)
-
Session Management: JavaScript-layer session tracking with unique IDs for easy integration with Electron Phone UI.
-
Bundled Dependencies: All PJSIP binary libraries (
.lib
files) are included for distribution, ensuring users don't need to install any external dependencies. -
Result Normalization: All API functions return a consistent
{ ok: boolean, code: number, message: string, data?: any }
format.
- Native Addon: C++ addon using N-API for Node.js integration
- PJSIP Integration: Real PJSIP 2.15.1 library embedded
- Cross-Platform: Windows (x64) and macOS support
- Build System: Node-gyp for native addon compilation
- Error Handling: Comprehensive error handling with normalized results
The project has been optimized by removing unnecessary files:
- Removed old TypeScript files (
src/index.ts
,src/native.ts
) - Removed TypeScript build artifacts (
dist/
directory) - Removed TypeScript configuration (
tsconfig.json
) - Updated
package.json
to remove TypeScript dependencies - Kept only essential working files
This package includes all necessary PJSIP libraries and dependencies:
pjsua2-lib-x86_64-x64-vc14-Release.lib
- PJSIP User Agent Library v2pjsua-lib-x86_64-x64-vc14-Release.lib
- PJSIP User Agent Librarypjsip-ua-x86_64-x64-vc14-Release.lib
- PJSIP User Agent Layerpjsip-simple-x86_64-x64-vc14-Release.lib
- PJSIP Simple Frameworkpjsip-core-x86_64-x64-vc14-Release.lib
- PJSIP Core
pjmedia-x86_64-x64-vc14-Release.lib
- PJMedia Frameworkpjmedia-codec-x86_64-x64-vc14-Release.lib
- Media Codecspjmedia-audiodev-x86_64-x64-vc14-Release.lib
- Audio Devicespjmedia-videodev-x86_64-x64-vc14-Release.lib
- Video Devices
pjnath-x86_64-x64-vc14-Release.lib
- NAT Traversalpjlib-util-x86_64-x64-vc14-Release.lib
- PJLIB Utilitiespjlib-x86_64-x64-vc14-Release.lib
- PJLIB Core
libspeex-x86_64-x64-vc14-Release.lib
- Speex Codeclibilbccodec-x86_64-x64-vc14-Release.lib
- iLBC Codeclibg7221codec-x86_64-x64-vc14-Release.lib
- G.722.1 Codeclibgsmcodec-x86_64-x64-vc14-Release.lib
- GSM Codeclibsrtp-x86_64-x64-vc14-Release.lib
- SRTP Securitylibresample-x86_64-x64-vc14-Release.lib
- Audio Resamplinglibwebrtc-x86_64-x64-vc14-Release.lib
- WebRTC Componentslibyuv-x86_64-x64-vc14-Release.lib
- YUV Processinglibbaseclasses-x86_64-x64-vc14-Release.lib
- Base Classeslibmilenage-x86_64-x64-vc14-Release.lib
- Milenage Algorithm
No external dependencies required! Users can install and use this package without installing any additional libraries.
This project uses node-gyp for building the native addon:
# Configure
npm run configure
# Build
npm run build
# Clean
npm run clean
# Test
npm test
pjsip-node/
├── .git/ # Git repository
├── .github/ # GitHub workflows
├── build/ # Native build artifacts
├── lib/ # JavaScript wrapper (main entry point)
│ └── index.js # Client-required JS wrapper
├── node_modules/ # Dependencies
├── pjproject-2.15.1/ # PJSIP source
├── src/ # C++ source files
│ ├── addon.cpp # N-API addon entry point
│ ├── pjsip_wrapper.cpp # Main PJSIP wrapper
│ └── pjsip_wrapper.h # Header file
├── *.lib # PJSIP binary libraries (bundled)
├── binding.gyp # Node-gyp configuration
├── package.json # Package configuration
├── test.js # Working test file
└── README.md # This file
- Install Visual Studio Build Tools 2022 (Windows)
- Install Node.js 18+
- Install Python 3.x (for node-gyp)
-
Clone and install dependencies:
git clone <repository> cd pjsip-node npm install
-
Build the addon:
npm run build
-
Test:
npm test
This project follows a clean architecture:
- Native Layer: C++ addon using N-API
- PJSIP Integration: Real PJSIP library embedded
- JavaScript Wrapper: High-level JavaScript API
- Node-gyp Build: Modern build system
- Callback-Driven: Single-assignment callback system
The project includes a comprehensive test file (test.js
) that demonstrates:
- PJSIP initialization
- Account registration with authentication
- Outgoing call initiation
- Call state management
- Proper shutdown and cleanup
Run the test:
node test.js
MIT License
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
- baresip-node - Reference implementation
- PJSIP Documentation
- Node-API Documentation