bugfix
This commit is contained in:
parent
9aed6c656b
commit
db03059228
BIN
bricks/.DS_Store
vendored
BIN
bricks/.DS_Store
vendored
Binary file not shown.
@ -58,12 +58,12 @@ bricks.Image = class extends bricks.JsWidget {
|
||||
|
||||
bricks.Icon = class extends bricks.Image {
|
||||
constructor(opts){
|
||||
var rate = opts.rate || 1;
|
||||
var siz = bricks.app.charsize * rate + 'px';
|
||||
opts.width = siz;
|
||||
opts.height = siz;
|
||||
super(opts);
|
||||
this.rate = rate;
|
||||
}
|
||||
options_parse(){
|
||||
this.rate = this.rate || 1;
|
||||
var siz = bricks.app.charsize * rate + 'px';
|
||||
this.set_url(this.url)
|
||||
this.cwidth = this.opts.cwidth || 1;
|
||||
this.cheight = this.opts.cheight || 1;
|
||||
this.dynsize = this.opts.dynsize || true;
|
||||
@ -71,6 +71,34 @@ bricks.Icon = class extends bricks.Image {
|
||||
}
|
||||
}
|
||||
|
||||
bricks.StatedIcon = class extends bricks.Icon {
|
||||
/*
|
||||
states:[{state:aaa,url:} ,,]
|
||||
state:aaa,
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
}
|
||||
options_parse(){
|
||||
if (! this.states){
|
||||
return;
|
||||
}
|
||||
if (! this.state){
|
||||
this.state = this.states[0].state;
|
||||
}
|
||||
this.set_state(this.state);
|
||||
}
|
||||
set_state(state){
|
||||
this.state = state;
|
||||
this.states.forEach(s => {
|
||||
if(s.state == this.state){
|
||||
this.url = s.url
|
||||
super().options_parse();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bricks.BlankIcon = class extends bricks.JsWidget {
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
@ -83,5 +111,6 @@ bricks.BlankIcon = class extends bricks.JsWidget {
|
||||
}
|
||||
|
||||
bricks.Factory.register('Image', bricks.Image);
|
||||
bricks.Factory.register('StatedIcon', bricks.StatedIcon);
|
||||
bricks.Factory.register('Icon', bricks.Icon);
|
||||
bricks.Factory.register('BlankIcon', bricks.BlankIcon);
|
||||
|
BIN
bricks/imgs/free_phone.png
Normal file
BIN
bricks/imgs/free_phone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
bricks/imgs/lizhaoxing.jpeg
Normal file
BIN
bricks/imgs/lizhaoxing.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
BIN
bricks/imgs/using_phone.png
Normal file
BIN
bricks/imgs/using_phone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -26,6 +26,7 @@ bricks.Menu = class extends bricks.VBox {
|
||||
console.log('menu_clicked(): item=', item, item.opts, item.url);
|
||||
if (!item.url){
|
||||
console.log('itme.url is null');
|
||||
this.bind('command', item.opts);
|
||||
return;
|
||||
}
|
||||
var t = bricks.getWidgetById(this.target);
|
||||
|
166
bricks/rtc.js
166
bricks/rtc.js
@ -20,33 +20,97 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
{
|
||||
"signaling_url":
|
||||
"ice_url":
|
||||
"rtcid":
|
||||
"rtcname"
|
||||
"info":{
|
||||
"id":
|
||||
"name":
|
||||
}
|
||||
}
|
||||
*/
|
||||
constructor(opts){
|
||||
super(opts);
|
||||
this.build_phone();
|
||||
this.videobox = new bricks.ResponsableBox({});
|
||||
this.localVideo = new bricks.VideoBox({});
|
||||
this.remoteVideo = new bricks.VideoBox({});
|
||||
this.videobox.add_widget(this.localVideo);
|
||||
this.videobox.add_widget(this.remoteVideo);
|
||||
this.add_widget(this.videobox);
|
||||
this.peerConnection;
|
||||
this.socket = new WebSocket(this.signaling_url);
|
||||
this.socket.onopen = this.register_myself.bind(this);
|
||||
this.socket.onopen = this.signaling_login.bind(this);
|
||||
this.socket.onclose = null;
|
||||
this.socket.onerror = null;
|
||||
this.socket.onmessage = this.signaling_message_handle.bind(this);
|
||||
}
|
||||
this.signaling_register(){
|
||||
var d = {
|
||||
type:'register',
|
||||
data:{
|
||||
rtcid:this.rtcid,
|
||||
rtcname:this.rtcname
|
||||
build_phone(){
|
||||
opts = {
|
||||
states:[
|
||||
{
|
||||
state:'free',
|
||||
url:bricks_resource('imgs/free_phone.png')
|
||||
},{
|
||||
state:'using',
|
||||
url:bricks_resource('img/using_phone.png')
|
||||
}
|
||||
],
|
||||
state:'free',
|
||||
rate:2
|
||||
}
|
||||
this.phone = new bricks.StatedIcon(opts);
|
||||
this.add_widget(this.phone);
|
||||
this.phone.bind('click', this.phone_action.bind(this));
|
||||
}
|
||||
phone_action(){
|
||||
if (this.phone.state == 'free'){
|
||||
this.choose_peer();
|
||||
} else {
|
||||
this.call_close();
|
||||
this.phone.set_state('free');
|
||||
}
|
||||
}
|
||||
choose_peer(){
|
||||
var items = [];
|
||||
this.onlineList.forEach( p => {
|
||||
var m = {
|
||||
name:p.id,
|
||||
label:p.name
|
||||
}
|
||||
items.push(m);
|
||||
});
|
||||
var menu = new bricks.Menu({
|
||||
width:'300px',
|
||||
height:'400px'
|
||||
items:items
|
||||
});
|
||||
menu.set_css('popup');
|
||||
Bricks.Body.add_widget(menu);
|
||||
menu.bind('command', this.call_peer.bind(this));
|
||||
this.menu = menu;
|
||||
}
|
||||
call_peer(event):
|
||||
bricks.Body.remove(this.menu);
|
||||
var peer_info = {
|
||||
id:event.params.name,
|
||||
name:event.params.label
|
||||
}
|
||||
this.call_request(peer_info);
|
||||
}
|
||||
signaling_login(){
|
||||
var d = {
|
||||
type:'login',
|
||||
info:this.info
|
||||
}
|
||||
this.socket.send(JSON.stringify(d));
|
||||
}
|
||||
signaling_logout(){
|
||||
var d= {
|
||||
type:'logout',
|
||||
info:this.info
|
||||
}
|
||||
this.socket.send(JSON.stringify(d));
|
||||
}
|
||||
// 获取本地媒体流
|
||||
async function getLocalStream() {
|
||||
async getLocalStream() {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
||||
this.localVideo.set_stream(stream);
|
||||
@ -55,12 +119,12 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
console.error('获取本地媒体流失败:', error);
|
||||
}
|
||||
}
|
||||
async call_request(peer_id){
|
||||
async call_request(peer_info){
|
||||
var d = {
|
||||
type:'callrequest',
|
||||
rtcid:peer_id
|
||||
type:'callRequest',
|
||||
to:peer_info
|
||||
}
|
||||
this.peer_id = peer_id;
|
||||
this.peer_info = peer_info;
|
||||
this.role = 'requester';
|
||||
this.socket.send(JSON.stringify(d));
|
||||
}
|
||||
@ -70,35 +134,35 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
this.socket.send(JSON.stringify({
|
||||
type:'offer',
|
||||
offer:this.peerConnection.localDescription,
|
||||
to:this.peer_id
|
||||
to:this.peer_info
|
||||
}));
|
||||
}
|
||||
send_candidate(event){
|
||||
if (event.candidate) {
|
||||
this.socket.send(JSON.stringify({
|
||||
type: 'iceCandidate',
|
||||
to:this.peer_id,
|
||||
to:this.peer_info,
|
||||
candidate: event.candidate
|
||||
}));
|
||||
}
|
||||
}
|
||||
async need_conform_call(peer_id){
|
||||
async need_conform_call(peer_info){
|
||||
var w = new Conform({title:'请确认',
|
||||
message:'来自' + peer_id + '的连接请求');
|
||||
w.bind('conformed', this.call_accepted.bind(this, peer_id));
|
||||
w.bind('cancelled', this.call_hungup.bind(this.peer_id));
|
||||
message:'来自' + peer_info.name + '的连接请求');
|
||||
w.bind('conformed', this.call_accepted.bind(this, peer_info));
|
||||
w.bind('cancelled', this.call_rejected.bind(this.peer_info));
|
||||
w.open();
|
||||
}
|
||||
call_accepted(peer_id){
|
||||
if (this.peer_id){
|
||||
call_accepted(peer_info){
|
||||
if (this.peer_info){
|
||||
this.call_close();
|
||||
}
|
||||
this.peer_id = peer_id
|
||||
this.peer_info = peer_info
|
||||
this.role = 'responser'
|
||||
async this.createPeerConnection();
|
||||
this.socket.send(JSON.stringify({
|
||||
type: 'callAccepted',
|
||||
to: peer_id
|
||||
to: peer_info
|
||||
}));
|
||||
}
|
||||
async call_close(active){
|
||||
@ -108,21 +172,24 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
if (! active){
|
||||
this.socket.send(JSON.stringify({
|
||||
type:'disconnect',
|
||||
to:this.peer_id
|
||||
to:this.peer_info
|
||||
});
|
||||
}
|
||||
this.peer_id = null;
|
||||
this.peer_info = null;
|
||||
this.localVideo.get_stream().getTracks().forEach(track => track.stop());
|
||||
}
|
||||
call_hangup(peer_id){
|
||||
call_rejected(peer_info){
|
||||
this.socket.send(JSON.stringify({
|
||||
type: 'callRejected',
|
||||
to: peer_id
|
||||
to: peer_info
|
||||
}));
|
||||
}
|
||||
async signaling_message_handle(event){
|
||||
var d = event.data;
|
||||
switch (d.type){
|
||||
case 'onlineList':
|
||||
this.onlineList = d.onlineList;
|
||||
break;
|
||||
case 'callRequest':
|
||||
this.need_conform_call(d.from);
|
||||
break;
|
||||
@ -133,25 +200,25 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
this.socket.send(JSON.stringify({
|
||||
type:'answer',
|
||||
answer:answer,
|
||||
to:this.peer_id
|
||||
to:this.peer_info
|
||||
});
|
||||
case 'answer':
|
||||
if (d.from == self.peer_id){
|
||||
if (d.from == self.peer_info){
|
||||
var desc = new RTCSessionDescription(d.answer));
|
||||
this.peerConnection.setRemoteDescription(desc);
|
||||
}
|
||||
break;
|
||||
case 'iceCandidate':
|
||||
if (d.from == self.peer_id){
|
||||
if (d.from == self.peer_info){
|
||||
var candidate = new RTCIceCandidate(d.candidate);
|
||||
this.peerConnection.addIceCandidate(candidate);
|
||||
}
|
||||
break;
|
||||
case 'callAccepted':
|
||||
await this.createPeerConnection(this.peer_id);
|
||||
await this.createPeerConnection(this.peer_info);
|
||||
break;
|
||||
case 'callRejected':
|
||||
this.peer_id = null;
|
||||
this.peer_info = null;
|
||||
break;
|
||||
case 'disconnect':
|
||||
this.call_close(true);
|
||||
@ -160,28 +227,33 @@ bricks.RTCClient = class extends bricks.VBox {
|
||||
}
|
||||
|
||||
// 创建 PeerConnection
|
||||
async createPeerConnection(to_id) {
|
||||
async createPeerConnection(to_info) {
|
||||
this.phone.set_state('using');
|
||||
if (this.role == 'requester'){
|
||||
await this.send_offer();
|
||||
}
|
||||
const configuration = {
|
||||
// iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
||||
const configuration = {
|
||||
iceServers: [
|
||||
{ urls: this.ice_url },
|
||||
{ urls: 'stun:stunserver2024.stunprotocol.org:3478' }
|
||||
]
|
||||
};
|
||||
this.peerConnection = new RTCPeerConnection(configuration);
|
||||
};
|
||||
this.peerConnection = new RTCPeerConnection(configuration);
|
||||
// 处理本地流添加到 PeerConnection
|
||||
this.localVideo
|
||||
.get_stream()
|
||||
.getTracks()
|
||||
.forEach(track => {
|
||||
this.peerConnection.addTrack(track,
|
||||
this.localVideo.stream));
|
||||
}
|
||||
|
||||
// 处理本地流添加到 PeerConnection
|
||||
this.localVideo.stream.getTracks().forEach(track => this.peerConnection.addTrack(track, this.localVideo.stream));
|
||||
// 处理 ICE 候选
|
||||
this.peerConnection.onicecandidate = this.send_candidate.bind(this, to_info);
|
||||
|
||||
// 处理 ICE 候选
|
||||
this.peerConnection.onicecandidate = this.send_candidate.bind(this, to_id);
|
||||
|
||||
// 处理远程流添加
|
||||
this.peerConnection.ontrack = event => {
|
||||
this.remoteVideo.set_stream(event.streams[0]);
|
||||
};
|
||||
// 处理远程流添加
|
||||
this.peerConnection.ontrack = event => {
|
||||
this.remoteVideo.set_stream(event.streams[0]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user