Freeswitch实现网页通话
配置 external 中绑定 websocket 地址修改 C:\Program Files\FreeSWITCH\conf\autoload_configs 下的 verto.conf.xml 文件中的default-v4</profile>保存重启服务,或者刷新配置,在控制台中输入命令查看是否绑定成功。
1.配置 Freeswitch 支持websocket
配置 external 中绑定 websocket 地址
<param name="apply-candidate-acl" value="none"/>
<param name="wss-binding" value="0.0.0.0:6075"/>
<param name="ws-binding" value="0.0.0.0:6076"/>
修改 C:\Program Files\FreeSWITCH\conf\autoload_configs 下的 verto.conf.xml 文件中的default-v4
<profile name="default-v4">
<param name="bind-local" value="123.60.78.179:6076"/>
<param name="bind-local" value="123.60.78.179:6075" secure="true"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
<param name="userauth" value="true"/>
<!-- setting this to true will allow anyone to register even with no account so use with care -->
<param name="blind-reg" value="false"/>
<param name="mcast-ip" value="224.1.1.1"/>
<param name="mcast-port" value="1337"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="local-network" value="localnet.auto"/>
<param name="outbound-codec-string" value="opus,h264,vp8"/>
<param name="inbound-codec-string" value="opus,h264,vp8"/><param name="apply-candidate-acl" value="localnet.auto"/>
<param name="apply-candidate-acl" value="wan_v4.auto"/>
<param name="apply-candidate-acl" value="rfc1918.auto"/>
<param name="apply-candidate-acl" value="any_v4.auto"/>
<param name="timer-name" value="soft"/>
</profile>
保存重启服务,或者刷新配置,在控制台中输入命令查看是否绑定成功
sofia status profile external
2.一个页面demo测试是否成功
<!DOCTYPE html>
<html>
<head>
<title>JsSIP WebRTC Test</title>
<script src="https://cdn.jsdelivr.net/npm/jssip@latest/dist/jssip.min.js"></script>
</head>
<body>
<h1>JsSIP WebRTC Test</h1>
<div id="status">Disconnected</div>
<div>
<label for="freeswitchIp">FreeSWITCH IP:</label>
<input type="text" id="freeswitchIp" value="123.60.78.179" placeholder="FreeSWITCH IP">
</div>
<div>
<label for="wsPort">WS Port:</label>
<input type="number" id="wsPort" value="6076" placeholder="WS Port">
</div>
<div>
<label for="stunServer">STUN Server:</label>
<input type="text" id="stunServer" value="stun:123.60.78.179:6074" placeholder="STUN Server">
</div>
<div>
<label for="sipUri">SIP URI:</label>
<input type="text" id="sipUri" value="sip:1004@123.60.78.179" placeholder="sip:1004@domain">
</div>
<div>
<label for="password">Password:</label>
<input type="password" id="password" value="1004" placeholder="Password">
</div>
<button id="connectButton">Connect</button>
<div>
<label for="callee">Callee:</label>
<input type="text" id="callee" value="sip:1003@123.60.78.179" placeholder="sip:callee@domain">
</div>
<button id="callButton" disabled>Call</button>
<div id="localView"></div>
<div id="remoteView"></div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const statusDiv = document.getElementById('status');
const connectButton = document.getElementById('connectButton');
const sipUriInput = document.getElementById('sipUri');
const passwordInput = document.getElementById('password');
const callButton = document.getElementById('callButton');
const calleeInput = document.getElementById('callee');
const localView = document.getElementById('localView');
const remoteView = document.getElementById('remoteView');
const freeswitchIpInput = document.getElementById('freeswitchIp');
const wsPortInput = document.getElementById('wsPort');
const stunServerInput = document.getElementById('stunServer');
let ua = null;
let session = null;
connectButton.addEventListener('click', () => {
const sipUri = sipUriInput.value;
const password = passwordInput.value;
const freeswitchIp = freeswitchIpInput.value;
const wsPort = parseInt(wsPortInput.value) || 6076;
const configuration = {
uri: sipUri,
password: password,
sockets: [new JsSIP.WebSocketInterface(`ws://${freeswitchIp}:${wsPort}`, { protocol: 'sip' })],
register: true,
trace_sip: true
};
ua = new JsSIP.UA(configuration);
console.log('UA object:', ua);
console.log('UA Configuration:', ua.configuration); // 添加这行
ua.on('registered', () => {
statusDiv.innerText = 'Registered';
callButton.disabled = false;
});
ua.on('unregistered', () => {
statusDiv.innerText = 'Unregistered';
callButton.disabled = true;
});
ua.on('registrationFailed', (e) => {
statusDiv.innerText = 'Registration Failed: ' + e.cause;
callButton.disabled = true;
});
ua.on('newRTCSession', (data) => {
session = data.session;
if (session.direction === 'incoming') {
session.answer()
.then(() => {
attachMedia(session);
})
.catch((error) => {
console.error('Error answering call:', error);
});
} else if (session.direction === 'outgoing') {
attachMedia(session);
}
});
ua.start();
statusDiv.innerText = 'Connecting...';
connectButton.disabled = true;
});
callButton.addEventListener('click', () => {
console.log('Call button clicked');
const callee = `sip:1004@${freeswitchIpInput.value}`; // 修改呼叫目标
console.log('Callee:', callee);
console.log('UA:', ua);
if (ua && callee) {
session = ua.call(callee, {
mediaConstraints: { audio: true, video: false },
sessionTimersExpires: 1800
});
console.log('Session object:', session);
console.log('Session status:', session ? session.status : null);
if (session) {
session.on('failed', (e) => {
console.error('Call failed:', e);
});
session.on('connecting', () => {
console.log('Call connecting...');
});
session.on('progress', (response) => {
console.log('Call progress:', response);
});
session.on('accepted', (response) => {
console.log('Call accepted:', response);
});
session.on('ended', (response) => {
console.log('Call ended:', response);
});
}
attachMedia(session);
} else {
console.log('UA not initialized or callee is empty.');
}
});
function attachMedia(session) {
console.log("Not requesting local media.");
}
});
</script>
</body>
</html>
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)