@open-voip-alliance/webphone-lib
v0.1.1
Published
Webphone Lib
Downloads
10
Readme
Open VoIP Alliance Webphone Lib
Goals
Hide the complexities of SIP, SDP and WebRTC from the implementation of the Webphone through an easy to use modern Javascript API.
Uses
Promises
andasync
where possible, use events only where neccessary (not in request/response flows).Export as ESM module.
Error handling is clear and where possible Promise based.
WebphoneLib does not keep state.
Wraps SIP.js in such a way that upgrades are easy.
Abstract over differences between browsers.
Use cases
- Register phone
- Unregister phone
- Accepting an incoming call
- Denying an incoming call
- Creating an outgoing call
- Hanging up a call (in or out)
- Putting a call on hold
- Putting a call out of hold
- Blind transfer of a call
- Attended transfer of a call
- Getting presence updates for contacts (blf)
- Enter DTMF keys in a call
- Muting a call
- Switching audio devices during a call
- To implement Quality of Service
Accidental complexity
Websocket connection to the SIP proxy.
- Connecting/disconnecting
- Handling failures
Setting up the WebRTC channels (SIP.js) does this.
Requesting the audio/video devices to be used (SIP.js)
- Is done by the SessionDescriptionHandler, maybe the audio stream
handling could be decoupled from the SDH. Right now the SDH always
does a
getUserMedia
call to get a microphone.
- Is done by the SessionDescriptionHandler, maybe the audio stream
handling could be decoupled from the SDH. Right now the SDH always
does a
Negotiating the SDP (SIP.js).
Logging..
- Logging all SIP traffic?
WebphoneLib client setup
- Which audio/video devices to use?
- how to switch a/v during a call? Is this possible?
- ice servers (stun)
- transport options (reconnection etc.?)
- user agent
- noanswertimeout?
- etc.
Maybe best to first just pass through the options
to the SIP.UA
constructor?
Example flows
Connecting and registering
import { Client } from '../dist/vialer-web-calling.prod.mjs';
const account = {
user: 'accountId',
password: 'password',
uri: 'sip:[email protected]',
name: 'test'
};
const transport = {
wsServers: 'wss://websocket.voipgrid.nl',
iceServers: ['stun:stun0-grq.voipgrid.nl', 'stun:stun0-ams.voipgrid.nl']
};
const media = {
input: {
id: undefined, // default audio device
audioProcessing: true,
volume: 1.0,
muted: false
},
output: {
id: undefined, // default audio device
volume: 1.0,
muted: false
}
};
const client = new Client({ account, transport, media });
await client.register();
Incoming call
// incoming call below
sessions = {};
client.on('invite', (session) => {
// If DND, session.reject()
sessions[session.id] = session;
// reinvite..
try {
ringer();
let accepted = await session.accepted(); // wait until the call is picked up)
if (!accepted) {
return;
}
showCallScreen();
await session.terminated();
} catch (e) {
showErrorMessage(e)
} finally {
closeCallScreen();
delete sessions[session.id];
}
});
Outgoing call
sessions = {};
const session = client.invite('sip:[email protected]');
sessions[session.id] = session;
try {
showOutgoingCallInProgress();
let isAccepted = await session.accepted();
if (!isAccepted) {
showRejectedScreen();
return;
}
showCallScreen();
await session.terminated();
} catch (e) {
} finally {
closeCallScreen();
delete sessions[session.id];
}
Attended transfer of a call
if (await session.accepted()) {
await session.hold();
const other = client.invite('sip:[email protected]');
if (await other.accepted()) {
await session.attendedTransfer(other);
await session.terminated();
}
}
Audio device selection
- Set a primary input & output device:
const client = new Client({
account,
transport,
media: {
input: {
id: undefined, // default input device
audioProcessing: true,
volume: 1.0,
muted: false
},
output: {
id: undefined, // default output device
volume: 1.0,
muted: false
}
}
});
- Change the primary I/O devices:
client.defaultMedia.output.id = '230988012091820398213';
- Change the media of a session:
const session = await client.invite('123');
session.media.input.volume = 50;
session.media.input.audioProcessing = false;
session.media.input.muted = true;
session.media.output.muted = false;
session.media.setInput({
id: '120398120398123',
audioProcessing: true,
volume: 0.5,
muted: true
});