具体请先看nginx的webrtc配置WebRTC - FreeSWITCH - Confluence
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
server_name wss.somedomain.com.ua;
ssl on;
ssl_certificate /etc/nginx/cert.pem;
ssl_certificate_key /etc/nginx/private.key;
location / {
proxy_pass http://127.0.0.1:5066;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400s;
}
access_log /var/log/nginx/wss_access;
error_log /var/log/nginx/wss_error debug; }
配置好后,就可以使用前端连接sip.js配置了
具体源码如下:sipjs-demo.7z-Web开发文档类资源-CSDN下载
这个是在csdn下载的sip.js测试代码,具体地址提供忘记了,所以用了我上传的资源
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>sipjstest</title>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<div>
<input id="number" value="1000" type="text"/>
<button id="startCall">Start Call</button>
<button id="endCall">End Call</button>
<button id="transfer">transfer</button>
<button id="hold">hold</button>
<button id="unhold">unhold</button>
<button id="mute">mute</button>
<button id="unmute">unmute</button>
</div>
<br>
<div>
<input id="msg" value="你好" type="text"/>
<button id="sendMessage">Send Message</button>
<audio id="ringtone" loop src="./sounds/ringtone.wav"></audio> <!--//来电提示音-->
<audio id="ringbacktone" loop src="./sounds/ringbacktone.wav"></audio> <!--//电话呼叫后声音-->
<audio id="dtmfTone" src="./sounds/dtmf.wav"></audio>
<video id="remoteVideo" autoplay="autoplay"></video>
<video id="localVideo" autoplay="autoplay" muted="muted"></video>
<!-- DTMF -->
<div id="dtmf-buttons">
<button onclick="sendDtmf('1');">1</button>
<button onclick="sendDtmf('2');">2</button>
<button onclick="sendDtmf('3');">3</button>
<button onclick="sendDtmf('4');">4</button>
<button onclick="sendDtmf('5');">5</button>
<button onclick="sendDtmf('6');">6</button>
<button onclick="sendDtmf('7');">7</button>
<button onclick="sendDtmf('8');">8</button>
<button onclick="sendDtmf('9');">9</button>
<button onclick="sendDtmf('0');">0</button>
<button onclick="sendDtmf('#');">#</button>
<button onclick="sendDtmf('*');">*</button>
</div>
</div>
<script src="./js/sip-0.15.6.js"></script>
<script>
var extCode = "1004"; //分机号
var extPass = "123456"; //分机密码
var config = {
//uri: "sip:" +extCode + '@testfs.com.cn',
uri: "sip:" +extCode + '@192.168.61.140:11889',
//uri: "sip:" +extCode + '@192.168.61.73.com',
authorizationUser: extCode,
password: extPass,
displayName: extCode,
log: {
builtinEnabled: true,
level: 3 // log日志级别
},
transportOptions: {
//wsServers: ['wss://你的域名:11443'], // wss 目前chrome 必须使用https才可以调起媒体 服务使用https 连接fs则相应需要使用wss 本地测试可以配套自签证书使用(如果没有真实的证书)
wsServers: ['wss://zhaoxin.tech'],
traceSip: true //开启sip日志,用于排查问题
},
allowLegacyNotifications: true,
hackWssInTransport: false, // 设置为true 则注册时 transport=wss; false:transport=ws;
/**
* sip.js生成的随机contact字符串 设置后会以此为后缀 可以搭配 cusContactName使用,根据自身业务进行使用
* 设置前: sofia/internal/sip:asdasdfawg@df7jal23ls0d.invalid;
* 设置后: sofia/internal/sip:asdasdfawg@192.168.0.253;
*
*/
userAgentString: "sipJsDemo",
//hackIpInContact: "192.168.61.140",
/*
registerOptions: {
expires: 300,
registrar: 'sip:iscc.yonyou.com',
},
*/
/**
* 此处是笔者自定义的参数,因为注册到fs时,sip.js会随机生成contact字符串,如:sofia/internal/sip:admin10@df7jal23ls0d.invalid;
* 笔者自己添加了一个参数,对sip.js的源码进行了修改 ,修改后效果 sofia/internal/sip:1012@192.168.0.253 不需要的可以不理会此参数
*/
cusContactName: extCode,
// rel100: SIP.C.supported.UNSUPPORTED,
// dtmfType: SIP.C.dtmfType.RTP,
};
//var ua = new SIP.UA(config);
var ua = new SIP.UA(config);
var sessionall;
var startCall = document.getElementById('startCall');
var endCall = document.getElementById('endCall');
var transfer = document.getElementById('transfer');
var hold = document.getElementById('hold');
var unhold = document.getElementById('unhold');
var sendMessage = document.getElementById('sendMessage');
var mute = document.getElementById('mute');
var unmute = document.getElementById('unmute');
var Ring={
/**
* 振铃
*/
startRingTone: function () {
document.getElementById("ringtone").play();
/*
let play = document.getElementById("ringtone").play();
play.then(()=>{
}).catch((err)=>{
});
*/
},
/**
* 停止振铃
*/
stopRingTone: function () {
document.getElementById("ringtone").pause();
},
startRingbackTone: function () {
document.getElementById("ringbacktone").play();
/*
let play = document.getElementById("ringbacktone").play();
play.then(()=>{
}).catch((err)=>{
});
*/
},
stopRingbackTone: function () {
document.getElementById("ringbacktone").pause();
}
};
/**
* 绑定方法
* @param obj 要绑定事件的元素
* @param ev 绑定的事件
* @param fn 绑定事件的函数
*/
function bindEvent(obj, ev, fn) {
if (obj.attachEvent) {
obj.attachEvent("on" + ev, fn);
}
else {
obj.addEventListener(ev, fn, false);
}
}
/**
* 发送DTMF
* @param num 按键
*/
function sendDtmf(num) {
sessionall.dtmf(num);
}
/**
* 拨打电话
*/
bindEvent(startCall, 'click', function () {
var number = document.getElementById("number").value;
//创建一个新的出站(用户代理客户端)会话
sessionall = ua.invite(number, {
sessionDescriptionHandlerOptions: {
constraints: {
audio: true,
video: false
},
alwaysAcquireMediaFirst: true // 此参数是sip.js官方修复在firefox遇到的bug所设置
}
});
//开始嘟嘟嘟
Ring.startRingbackTone();
var remoteVideo = document.getElementById('remoteVideo');
var localVideo = document.getElementById('localVideo');
//每次收到成功的最终(200-299)响应时都会触发。
sessionall.on("accepted", function (response, cause) {
console.log(response);
Ring.stopRingbackTone();
var pc = this.sessionDescriptionHandler.peerConnection;
var remoteStream;
if (pc.getReceivers) {
remoteStream = new window.MediaStream();
pc.getReceivers().forEach(function (receiver) {
var track = receiver.track;
if (track) {
remoteStream.addTrack(track);
}
});
} else {
remoteStream = pc.getRemoteStreams()[0];
}
remoteVideo.srcObject = remoteStream;
var localStream_1;
if (pc.getSenders) {
localStream_1 = new window.MediaStream();
pc.getSenders().forEach(function (sender) {
var track = sender.track;
if (track && track.kind === "video") {
localStream_1.addTrack(track);
}
});
}
else {
localStream_1 = pc.getLocalStreams()[0];
}
localVideo.srcObject = localStream_1;
});
sessionall.on('progress', function (response, cause) {
console.log(response);
Ring.stopRingbackTone();
console.warn('开始振铃!。。');
console.warn(response.statusCode);
if (response.statusCode === 183) {
sessionall.createDialog(response, 'UAC');
sessionall.hasAnswer = true;
sessionall.status = 11;
sessionall.sessionDescriptionHandler.setDescription(response.body)
.catch(function (exception) {
sessionall.logger.warn(exception);
sessionall.failed(response, C.causes.BAD_MEDIA_DESCRIPTION);
sessionall.acceptAndTerminate({status_code: 488, reason_phrase: 'Bad Media Description'});
});
}});
//每次收到成功的最终(200-299)响应时都会触发。
sessionall.on("accepted", function (response, cause) {
console.log(response);
Ring.stopRingbackTone();
var pc = this.sessionDescriptionHandler.peerConnection;
var remoteStream;
if (pc.getReceivers) {
remoteStream = new window.MediaStream();
pc.getReceivers().forEach(function (receiver) {
var track = receiver.track;
if (track) {
remoteStream.addTrack(track);
}
});
} else {
remoteStream = pc.getRemoteStreams()[0];
}
remoteVideo.srcObject = remoteStream;
var localStream_1;
if (pc.getSenders) {
localStream_1 = new window.MediaStream();
pc.getSenders().forEach(function (sender) {
var track = sender.track;
if (track && track.kind === "video") {
localStream_1.addTrack(track);
}
});
}
else {
localStream_1 = pc.getLocalStreams()[0];
}
localVideo.srcObject = localStream_1;
})
//挂机时会触发
sessionall.on("bye", function (response, cause) {
Ring.stopRingbackTone();
console.log(response);
})
//请求失败时触发,无论是由于最终响应失败,还是由于超时,传输或其他错误。
sessionall.on("failed", function (response, cause) {
Ring.stopRingbackTone();
console.log(response);
})
/**
*
*/
sessionall.on("terminated", function (message, cause) {
Ring.stopRingbackTone();
})
/**
* 对方拒绝
*/
sessionall.on('rejected', function (response, cause) {
Ring.stopRingbackTone();
})
})
//挂断事件
bindEvent(endCall, 'click', function () {
if (!sessionall) {
return;
} else if (sessionall.startTime) { // Connected
sessionall.bye();
} else if (sessionall.reject) { // Incoming
sessionall.reject();
} else if (sessionall.cancel) { // Outbound
sessionall.cancel();
}
})
//电话转移盲转
bindEvent(transfer, 'click', function () {
if (!sessionall) {
return;
}
var number = document.getElementById("number").value;
sessionall.refer(number, {
receiveResponse: function (msg, ss) {
console.info(msg);
console.info(ss);
}
});
})
//电话保持
bindEvent(hold, 'click', function () {
if (!sessionall) {
return;
}
sessionall.hold();
})
//恢复电话保持
bindEvent(unhold, 'click', function () {
if (!sessionall) {
return;
}
sessionall.unhold();
})
//发送消息
bindEvent(sendMessage, 'click', function () {
// Sends a new message
var number = document.getElementById("number").value;
var message = document.getElementById("msg").value;
ua.message(number, message);
// When receiving a message, prints it out
ua.on('message', function (message) {
console.log(message.body);
});
})
// 静音
bindEvent(mute, 'click', function () {
if (!sessionall) {
console.warn("No session to toggle mute");
return;
}
var pc = sessionall.sessionDescriptionHandler.peerConnection;
if (pc.getSenders) {
pc.getSenders().forEach(function (sender) {
if (sender.track) {
sender.track.enabled = false;
}
});
} else {
pc.getLocalStreams().forEach(function (stream) {
stream.getAudioTracks().forEach(function (track) {
track.enabled = false;
});
stream.getVideoTracks().forEach(function (track) {
track.enabled = false;
});
});
}
})
// 解除静音
bindEvent(unmute, 'click', function () {
if (!sessionall) {
console.warn("No session to toggle mute");
return;
}
var pc = sessionall.sessionDescriptionHandler.peerConnection;
if (pc.getSenders) {
pc.getSenders().forEach(function (sender) {
if (sender.track) {
sender.track.enabled = true;
}
});
} else {
pc.getLocalStreams().forEach(function (stream) {
stream.getAudioTracks().forEach(function (track) {
track.enabled = true;
});
stream.getVideoTracks().forEach(function (track) {
track.enabled = true;
});
});
}
})
// 接受入站(用户代理服务器)会话
ua.on('invite', function (session) {
// 开始振铃
Ring.startRingTone();
var url = session.remoteIdentity.uri.toString() + "来电了,是否接听";
var remoteVideo = document.getElementById('remoteVideo');
var localVideo = document.getElementById('localVideo');
session.on("terminated", function (message, cause) {
Ring.stopRingTone();
console.info(message);
})
/**
*
*/
session.on('accepted', function (response, cause) {
console.info(response);
console.info(session);
Ring.stopRingTone();
// If there is a video track, it will attach the video and audio to the same element
var pc = this.sessionDescriptionHandler.peerConnection;
console.info(this.sessionDescriptionHandler);
var remoteStream;
if (pc.getReceivers) {
remoteStream = new window.MediaStream();
pc.getReceivers().forEach(function (receiver) {
var track = receiver.track;
if (track) {
remoteStream.addTrack(track);
}
});
} else {
remoteStream = pc.getRemoteStreams()[0];
}
remoteVideo.srcObject = remoteStream;
var localStream_1;
if (pc.getSenders) {
localStream_1 = new window.MediaStream();
pc.getSenders().forEach(function (sender) {
var track = sender.track;
if (track && track.kind === "video") {
localStream_1.addTrack(track);
}
});
}
else {
localStream_1 = pc.getLocalStreams()[0];
}
localVideo.srcObject = localStream_1;
localVideo.volume = 0;
})
session.on('bye', function (resp, cause) {
Ring.stopRingTone();
});
var isaccept = confirm(url);
if (isaccept) {
//接受来电
session.accept({
sessionDescriptionHandlerOptions: {
constraints: {
audio: true,
video: false
}
}
});
sessionall = session;
}
else {
//拒绝来电
session.reject();
}
});
</script>
</body>
</html>
修改sip-0.15.6.js
将
//var via = "SIP/2.0/" + scheme;
改成
var via = "SIP/2.0/WS";
OutgoingRequestMessage.prototype.setViaHeader = function (branch, scheme) {
if (scheme === void 0) { scheme = "WSS"; }
// FIXME: Hack
if (this.options.hackViaTcp) {
scheme = "TCP";
}
//var via = "SIP/2.0/" + scheme;
var via = "SIP/2.0/WS";
via += " " + this.options.viaHost + ";branch=" + branch;
if (this.options.forceRport) {
via += ";rport";
}
this.setHeader("via", via);
this.branch = branch;
};