Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
2abbb43
Added basic vad functionality
Apr 23, 2025
6a553fc
Improved vad usage
May 2, 2025
4a8ad54
Added form for vad configuration
May 13, 2025
cece4b8
Updated docs due to latest vad demo changes
May 14, 2025
27b8735
Added container for audio records
May 14, 2025
c967949
Update: improve keep-alive logic and increment version to 0.1.2
Regani Jun 12, 2025
c72bc56
Update: increment version to 0.1.3 in package.json
Regani Jun 12, 2025
31388bc
Added possibility to use * and # in dtmf
Jun 19, 2025
77532dd
Merge pull request #61 from OpenSIPS/dtmf-fix
Regani Jun 19, 2025
99b7747
[conference-fix] Update: Harmonizing audio streams for a symphonic ex…
Regani Jun 30, 2025
089e7cd
[conference-fix] Update: Harmonizing audio streams for a symphonic ex…
Regani Jun 30, 2025
d911197
Fixed conference bug: first agent is always active
Jul 2, 2025
50af78f
Fixed audio after moving call to other room
Jul 14, 2025
67e1952
Removed logs
Jul 14, 2025
d294624
Merge pull request #62 from OpenSIPS/conference-fix
SerhiiKun Jul 15, 2025
6cb263e
Added progressive reconnect timeout
Aug 5, 2025
34c64cf
Merge branch 'master' of https://github.com/OpenSIPS/opensips-js into…
Aug 5, 2025
6b31423
Changed opensipsjs version
Aug 5, 2025
11d9705
Merge pull request #66 from OpenSIPS/progressive-reconnect
SerhiiKun Aug 5, 2025
338b4b1
Removed unused functionality from audioContext helper
Aug 18, 2025
e6d8dc6
Updated package version
Aug 18, 2025
048c46e
Merge pull request #67 from OpenSIPS/audio-context-refactoring
SerhiiKun Aug 18, 2025
548923b
fixed vue meter issue on mobile devices
Sep 3, 2025
5d7c83d
Merge pull request #68 from OpenSIPS/vue-meter-fix
SerhiiKun Sep 3, 2025
5a5a3b9
Fix MSRP callback this binding for dist build, Add msrp domain
roicohenvc Sep 18, 2025
6985d10
Merged develop to vad
Sep 26, 2025
7516b6e
fix To-Path UNDEFINE
roicohenvc Sep 30, 2025
8570d37
fix msrp
roicohenvc Sep 30, 2025
266c191
add || this._ua._configuration.realm to msrp
roicohenvc Sep 30, 2025
c6d184d
Fixed vad, reached latency 150ms
Oct 8, 2025
a4ec36f
Implemented dynamic vad usage
Oct 14, 2025
05142a8
Finished vad intergation, added possibility to configure noice reduct…
Oct 17, 2025
d4cfbd3
Fixed bug with conferences when using dynamic vad
Oct 17, 2025
66306e1
Adjusted opensips noise reduction configuration after adjusting algoritm
Oct 20, 2025
3117326
Removed vad configaration fields from demo
Oct 20, 2025
070c9c9
Removed extra demo code
Oct 20, 2025
c308025
Updated package version
Oct 20, 2025
d57ed75
Fixed types
Oct 20, 2025
9f59439
Merge pull request #69 from OpenSIPS/vad
SerhiiKun Oct 20, 2025
412ff46
Added readme for noice reduction
Oct 20, 2025
a6e5bdb
Merge pull request #70 from OpenSIPS/vad
SerhiiKun Oct 20, 2025
f7d3adf
Merge pull request #71 from OpenSIPS/msrp-fix
SerhiiKun Oct 23, 2025
44f250f
Moved vad out of opensips scope to ake it work in react native apps
Oct 29, 2025
98e5568
Moved vad out of opensips
Oct 30, 2025
6485efb
Merge pull request #72 from OpenSIPS/vad
SerhiiKun Oct 30, 2025
f92979d
Added possibility to set vad options in runtime
Nov 6, 2025
8ee5429
Removed comments
Nov 6, 2025
193e122
Update package version to 0.1.18, add @ricky0123/vad-web dependency, …
Regani Nov 6, 2025
9ffd362
Update package version to 0.1.19
Regani Nov 6, 2025
89c3c04
Changed version
Nov 7, 2025
3758f41
Resolved conflicts
Nov 7, 2025
dd1871a
Added get curren mode methodt
Nov 7, 2025
b647c62
Merge pull request #74 from OpenSIPS/vad-runtime
SerhiiKun Nov 7, 2025
88c46c0
Added msrpWs and msrpDomain to configuration
Nov 19, 2025
4c0ab44
Merge pull request #75 from OpenSIPS/msrp-ws
SerhiiKun Nov 19, 2025
7b668f7
fix: improve registration refresh timing for short expiration intervals
Regani Dec 1, 2025
b9c362e
Merged with develop
Dec 2, 2025
8c54bb8
Added emits for rtc connection state change
Dec 2, 2025
8ba6644
Updated version
Dec 2, 2025
4a736c5
Merge pull request #77 from OpenSIPS/rtc-close
SerhiiKun Dec 2, 2025
ff9190e
Adjusted data for rtc connection emit
Dec 2, 2025
bb4645e
Merge pull request #78 from OpenSIPS/rtc-close
SerhiiKun Dec 2, 2025
d16d16b
Fixed member receivers in conference, added logs
Dec 10, 2025
f83b5c2
Merge branch 'develop' of https://github.com/OpenSIPS/opensips-js int…
Dec 10, 2025
328afed
Merge pull request #79 from OpenSIPS/rtc-close
SerhiiKun Dec 12, 2025
69813d5
Added dial beeps sound for internal calls without 183 response
Dec 15, 2025
2216964
Merge branch 'develop' of https://github.com/OpenSIPS/opensips-js int…
Dec 15, 2025
dcf4d57
Merge pull request #80 from OpenSIPS/rtc-close
SerhiiKun Dec 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 105 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,27 +119,33 @@ If you prefer using ES modules in the browser and your environment supports them
import OpensipsJS from 'https://cdn.opensipsjs.org/opensipsjs/v0.1.1/opensips-js.es.js';\

const opensipsJS = new OpensipsJS({
configuration: {
session_timers: false,
uri: 'sip:extension_user@domain',
// --- Use password or authorization_jwt to authorize
password: 'password',
// or
authorization_jwt: 'token',
},
socketInterfaces: ['wss://domain'],
pnExtraHeaders: {
'pn-provider': 'acme',
'pn-param': 'acme-param',
'pn-prid': 'ZH11Y4ZDJlMNzODE1NgKi0K>',
},
sipDomain: 'domain',
sipOptions: {
session_timers: false,
extraHeaders: ['X-Bar: bar'],
pcConfig: {},
},
modules: ['audio', 'video', 'msrp'],
configuration: {
session_timers: false,
noiseReductionOptions: {
mode: 'dynamic',
noiseThreshold: 0.004
checkEveryMs: 500
noiseCheckInterval: 2000
},
uri: 'sip:extension_user@domain',
// --- Use password or authorization_jwt to authorize
password: 'password',
// or
authorization_jwt: 'token',
},
socketInterfaces: ['wss://domain'],
pnExtraHeaders: {
'pn-provider': 'acme',
'pn-param': 'acme-param',
'pn-prid': 'ZH11Y4ZDJlMNzODE1NgKi0K>',
},
sipDomain: 'domain',
sipOptions: {
session_timers: false,
extraHeaders: ['X-Bar: bar'],
pcConfig: {},
},
modules: ['audio', 'video', 'msrp'],
});

// Use the modules as before
Expand Down Expand Up @@ -223,6 +229,7 @@ Also, there are next public fields on OpensipsJS instance:
- `setSpeakerVolume(value: Number): void` - set volume of callers. Value should be in range from 0 to 1
- `setDND(value: Boolean): void` - set the agent "Do not disturb" status
- `setMetricsConfig(config: WebrtcMetricsConfigType): void` - set the metric config (used for audio quality indicator)
- `setVADConfiguration(options: Partial<Omit<NoiseReductionOptions, 'vadModule'>>): void` - update noise reduction configuration at runtime. **Requires `vadModule` to be passed in the constructor, otherwise throws an error**

### Audio instance fields
- `sipOptions: Object` - returns sip options
Expand All @@ -237,6 +244,83 @@ Also, there are next public fields on OpensipsJS instance:
- `isDND: Boolean` - returns if the agent is in "Do not disturb" status
- `isMuted: Boolean` - returns if the agent is muted

### Noise Reduction Options (VAD)

**Important**: Voice Activity Detection (VAD) is an **optional feature** that requires installing an additional peer dependency. It is **NOT compatible with React Native**.

#### Critical: VAD Module Must Be Passed to Constructor

**If you plan to use noise reduction features (including `setVADConfiguration` in runtime), you MUST pass `vadModule` to the OpenSIPSJS constructor during initialization.**

- ✅ **Required**: Pass `vadModule` in the constructor if you want to use noise reduction
- ❌ **Will throw error**: Calling `setVADConfiguration()` without `vadModule` in the constructor will throw an error
- ⚠️ **Cannot be changed later**: The `vadModule` cannot be set after initialization - it must be provided in the constructor

#### For Web Applications (with VAD support)

Install the VAD library:
```bash
npm install @ricky0123/vad-web
# or
yarn add @ricky0123/vad-web
```

Then import and inject it in your configuration **during initialization**:
```javascript
import OpenSIPSJS from 'opensips-js'
import * as VAD from '@ricky0123/vad-web'

const opensipsJS = new OpenSIPSJS({
configuration: {
// ... other configuration
noiseReductionOptions: {
mode: 'dynamic', // or 'enabled'
vadModule: VAD, // ⚠️ REQUIRED: Must be passed here if you plan to use noise reduction
noiseThreshold: 0.004,
checkEveryMs: 500,
noiseCheckInterval: 2000
}
},
// ... rest of configuration
})

// ✅ Now you can use setVADConfiguration
opensipsJS.audio.setVADConfiguration({
mode: 'enabled',
noiseThreshold: 0.005
})
```

#### For React Native Applications (VAD not supported)

Simply omit the VAD module and disable noise reduction:
```javascript
import OpenSIPSJS from 'opensips-js'

const opensipsJS = new OpenSIPSJS({
configuration: {
// ... other configuration
noiseReductionOptions: {
mode: 'disabled' // or omit noiseReductionOptions entirely
}
// NO vadModule needed
},
// ... rest of configuration
})
```

**See [VAD_USAGE.md](VAD_USAGE.md) and [EXAMPLES.md](EXAMPLES.md) for detailed usage examples.**

#### Configuration Parameters

| Parameter | Type | Default | Description |
|----------------------|----------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `mode` | `disabled \| enabled \| dynamic` | `disabled` | Noise reduction mode. **Note**: `enabled` and `dynamic` modes require `vadModule` to be provided |
| `vadConfig` | `Partial<RealTimeVADOptions>` | `{}` | VAD configuration |
| `noiseThreshold` | `number` | `0.004` | Noise threshold |
| `noiseCheckInterval` | `number` | `2000` | The interval, used to check if we need to disable/enable outgoing audio every N-milliseconds |
| `checkEveryMs` | `number` | `500` | The interval, used inside noiseCheckInterval loop, checks current noise state every N-milliseconds, to define the average noise level. Then on every noiseCheckInterval iteration, the values getting on checkEveryMs will be summed, then divided by it's number and compared to noiseThreshold |

## MSRP

### MSRP methods
Expand Down
11 changes: 4 additions & 7 deletions src/helpers/volume.helper.ts → demo/helpers/volume.helper.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { IntervalType } from '@/types/rtc'
import audioContext from '@/helpers/audioContext'

const height = 20
const lineWidth = 4

let intervals: { [key: string]: IntervalType | undefined } = {}
let intervals: { [key: string]: ReturnType<typeof setInterval> | undefined } = {}

export const runIndicator = (stream: MediaStream, deviceId: string) => {
export const runIndicator = (audioContext: AudioContext, stream: MediaStream, deviceId: string) => {
if (stream && stream.getTracks().length) {
requestAnimationFrame(() => getVolumeLevelBar(stream, deviceId))
requestAnimationFrame(() => getVolumeLevelBar(audioContext, stream, deviceId))
} else {
clearVolumeInterval(deviceId)
}
Expand All @@ -32,7 +29,7 @@ const getMaxSmallIndicatorHeight = (value: number) => {
return value < halfLineHeight ? value : halfLineHeight
}

const getVolumeLevelBar = (stream: MediaStream, deviceId: string) => {
const getVolumeLevelBar = (audioContext: AudioContext, stream: MediaStream, deviceId: string) => {
clearVolumeInterval(deviceId)

const analyser = audioContext.createAnalyser()
Expand Down
8 changes: 8 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ <h3>Audio Calls</h3>

<br>

<select id="vadModeSelect">
<option value="disabled" class="">Disabled</option>
<option value="enabled" class="">Enabled</option>
<option value="dynamic" class="">Dynamic</option>
</select>

<br>

<form id="makeCallForm">
<label>
Your target:
Expand Down
38 changes: 31 additions & 7 deletions demo/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import OpenSIPSJS from '../src/index'
//import OpenSIPSJS from '../dist/opensips-js.es'
import { ICall, IOpenSIPSConfiguration, IRoom, RoomChangeEmitType, UAConfiguration } from '../src/types/rtc'
import { runIndicator } from '../src/helpers/volume.helper'
import { runIndicator } from './helpers/volume.helper'
import { SendMessageOptions } from 'jssip/lib/Message'
import { IMessage, MSRPSessionExtended } from '../src/types/msrp'
import MSRPMessage from '../src/lib/msrp/message'
Expand All @@ -14,6 +14,8 @@ import { ScreenSharePlugin } from '../src/lib/janus/ScreenSharePlugin'
import { ScreenShareWhiteBoardPlugin } from '../src/lib/janus/ScreenShareWhiteBoardPlugin'
//import { StreamMaskPlugin } from '../src/lib/janus/StreamMaskPlugin'
import { WhiteBoardPlugin } from '../src/lib/janus/WhiteBoardPlugin'
import * as VAD from '@ricky0123/vad-web'

//import UA from 'jssip/lib/UA'
//import JsSIP from 'jssip/lib/JsSIP'

Expand All @@ -36,6 +38,7 @@ const webRTCPageEl = document.getElementById('webRTCPage')
const logoutButtonEl = document.getElementById('logoutButton')

const makeCallFormEl = document.getElementById('makeCallForm')
const vadModeSelectEl = document.getElementById('vadModeSelect') as HTMLSelectElement
const videoCallFormEl = document.getElementById('videoCallForm')
const sendMessageFormEl = document.getElementById('sendMessageForm')
const callAddingIndicatorEl = document.getElementById('callAddingIndicator')
Expand Down Expand Up @@ -237,7 +240,7 @@ const upsertRoomData = (room: IRoom, sessions: {[p: string]: ICall}) => {
ulListEl.querySelectorAll('li').forEach(el => el.remove())

const activeCallsInRoom = Object.values(sessions).filter((call) => call.roomId === room.roomId)
activeCallsInRoom.forEach((call, index) => {
activeCallsInRoom.forEach(async (call, index) => {
const listItemEl = document.createElement('li')
listItemEl.setAttribute('key', `${index}`)
listItemEl.setAttribute('id', buildCallElementID(call.id))
Expand Down Expand Up @@ -367,7 +370,7 @@ const upsertRoomData = (room: IRoom, sessions: {[p: string]: ICall}) => {
listItemEl.appendChild(indicatorSpanEl)

if (call.audioTag?.srcObject) {
runIndicator(call.audioTag.srcObject, call._id)
// runIndicator(await openSIPSJS.audio.managedAudioContext.getContext(), call.audioTag.srcObject, call._id)
}

ulListEl.appendChild(listItemEl)
Expand Down Expand Up @@ -557,8 +560,13 @@ loginToAppFormEl?.addEventListener('submit', (event) => {
try {
const configuration: IOpenSIPSConfiguration = {
session_timers: false,
register_expires: 60,
noiseReductionOptions: {
mode: 'dynamic',
vadModule: VAD
},
uri: `sip:${username}@${domain}`,
overrideUserAgent: (userAgent) => userAgent + ' Vue 3.0'
overrideUserAgent: (userAgent) => userAgent + ' Vue 3.0',
}

if (password) {
Expand Down Expand Up @@ -612,10 +620,14 @@ loginToAppFormEl?.addEventListener('submit', (event) => {
imageSrc: base64Image
})

openSIPSJS.use(screenSharePlugin)
/*openSIPSJS.use(screenSharePlugin)
//openSIPSJS.use(streamMaskPlugin)
openSIPSJS.use(whiteBoardPlugin)
openSIPSJS.use(screenShareWhiteBoardPlugin)
openSIPSJS.use(screenShareWhiteBoardPlugin)*/

if (vadModeSelectEl) {
vadModeSelectEl.value = configuration.noiseReductionOptions?.mode || 'disabled'
}

/* openSIPSJS Listeners */
openSIPSJS
Expand Down Expand Up @@ -724,7 +736,7 @@ loginToAppFormEl?.addEventListener('submit', (event) => {
muteContainerEl.appendChild(buttonEl)
})
.on('changeActiveStream', (value: MediaStream) => {
runIndicator(value, 'agent-voice-level')
// runIndicator(value, 'agent-voice-level')
})
.on('changeCallVolume', (data: ChangeVolumeEventType) => {
//console.log('DEMO', data.callId, data.volume)
Expand Down Expand Up @@ -1211,6 +1223,18 @@ makeCallFormEl?.addEventListener(
}
)

vadModeSelectEl?.addEventListener(
'change',
async (event) => {
event.preventDefault()

const target = event.target as HTMLSelectElement
console.log('mode', target.value)
await openSIPSJS.audio.setVADConfiguration({
mode: target.value
})
})

videoCallFormEl?.addEventListener(
'submit',
(event) => {
Expand Down
Loading