我正在开发一个将 React.js 集成为前端框架的 Electron 应用程序,它更像是一个调用应用程序。在那个应用程序特定的用户可以有多个呼入、呼出、静音 | 取消静音,保持 | 挂断电话等。为了实现这个功能,我们有自己的 sip 服务器,为了集成该 SIP 服务器,我们在前端使用了一个名为SIP.JS的库。SIP.JS 为我们提供了几乎所有预定义的功能来拨打电话、接听电话、静音、取消静音、盲转接、出席转接等。但是在召开电话会议时,它没有相应的文档. SIP.JS 向我们说明我们可以使用FreeSWITCH以及ASTERISK为了实现功能,但根据我们的具体要求,不需要集成额外的服务器。我们还参考了电话会议的rfc 文档,但没有这样的进展。
到目前为止,我们所做的是:
- 注册了userAgent
- 集成来电代码
- 集成拨出电话代码
- 实现多个会话处理,用于多个调用
- 静音 | 取消静音,按住 | 取消持有。
- DTMF 功能
- 盲转,参加转
- 振铃所有设备
在这种电话会议的场景中,我想我们必须对传入和传出会话处理函数进行更改。
- 对于上下文中的注册和来电:
const getUAConfig = async (_extension, _name) => {
let alreadyLogin = '';
try {
alreadyLogin = 'yes';
if (alreadyLogin == 'yes') {
_displayname = _name;
_sipUsername = _extension;
_sipServer = 'SIP SERVER';
_sipPassword = 'SIP PASSWORD';
_wssServer = 'WSS SERVER;
const uri = UserAgent.makeURI('sip:' + _sipUsername + '@' + _sipServer);
const transportOptions = {
wsServers: 'WSS SERVER',
traceSip: true,
maxReconnectionAttempts: 1,
};
const userAgentOptions = {
uri: uri,
transportOptions: transportOptions,
userAgentString: 'App name',
authorizationPassword: _sipPassword,
sipExtension100rel: 'Supported',
sipExtensionReplaces: 'Supported',
register: true,
contactTransport: 'wss',
dtmfType: 'info',
displayName: _name,
sessionDescriptionHandlerFactoryOptions: {
peerConnectionOptions: {
rtcpMuxPolicy: 'negotiate',
iceCheckingTimeout: 1000,
iceTransportPolicy: 'all',
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
},
},
};
userAgent = await new UserAgent(userAgentOptions);
const registerOptions = {
extraContactHeaderParams: [],
};
registerer = await new Registerer(userAgent, registerOptions);
registerer.stateChange.addListener((newState) => {
});
userAgent.start().then(async () => {
console.log('Connected with WebSocket.');
// Send REGISTER
await registerer
.register()
.then((request) => {
console.log('Successfully sent REGISTER, object is here');
dispatch({
type: USER_REGISTERED,
payload: true,
});
})
.catch((error) => {
console.log('Failed to send REGISTER');
});
});
return { userAgent, registerer };
} else {
return null;
}
} catch (error) {
console.log(error.message + '');
return null;
}
};
- 传出功能:
const dilaerFun = (inputNumber, userAgentInfo) => {
var session;
var uri = UserAgent.makeURI(
`URI which we wanna call (sip number)`
);
session = new Inviter(userAgentInfo, uri);
session
.invite()
.then((request) => {
console.log('Successfully sent INVITE');
sessionInfoAdd(session);
session.stateChange.addListener(async (state) => {
switch (state) {
case 'Established':
setMissedStatus(null);
console.log('established outgoing....');
//outgoing call log-----
const mediaElement = document.getElementById(
`mediaElement${session._id}`
);
const remoteStream = new MediaStream();
session.sessionDescriptionHandler.peerConnection
.getReceivers()
.forEach((receiver) => {
if (receiver.track) {
remoteStream.addTrack(receiver.track);
}
});
mediaElement.srcObject = remoteStream;
mediaElement.play();
break;
case 'Terminated':
console.log('terminated');
dispatch({
type: DEMO_STATE,
payload: session._id,
});
break;
default:
break;
}
});
})
.catch((error) => {
console.error(' Failed to INVITE');
console.error(error.toString());
});
};
- 会话数组由以下人员维护:
const sessionInfoAdd = (session) => {
dispatch({
type: SESSION_STORE,
payload: session,
});
};
- 存储所有会话的变量是:
sessionInfo:[]
注意: getUAConfig() 会在应用程序启动后立即调用。dialerFun() 当我们想拨打一个特定的号码时被调用。在 getUAConfig 和 dialerFun 中都会调用 sessionInfoAdd(),因为它们是用于呼入和呼出的代码。当 sessionInfoAdd() 被触发时,我们返回的特定会话被添加到 sessionInfo (Array) 中以维护会话。