bugfic
This commit is contained in:
parent
d6bf03bb8d
commit
9aed6c656b
@ -6,7 +6,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
|||||||
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
||||||
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
||||||
floaticonbar.js miniform.js wterm.js dynamicaccordion.js \
|
floaticonbar.js miniform.js wterm.js dynamicaccordion.js \
|
||||||
binstreaming.js streaming_audio.js vadtext.js \
|
binstreaming.js streaming_audio.js vadtext.js rtc.js \
|
||||||
llm_dialog.js llm.js websocket.js datarow.js tabular.js \
|
llm_dialog.js llm.js websocket.js datarow.js tabular.js \
|
||||||
line.js pie.js bar.js gobang.js "
|
line.js pie.js bar.js gobang.js "
|
||||||
echo ${SOURCES}
|
echo ${SOURCES}
|
||||||
|
@ -83,7 +83,7 @@ bricks.FormBody = class extends bricks.VScrollPanel {
|
|||||||
this.fg.build_fields(form, this, form.opts.fields)
|
this.fg.build_fields(form, this, form.opts.fields)
|
||||||
}
|
}
|
||||||
create(){
|
create(){
|
||||||
this.dom_element = this._create('form')
|
this.dom_element = this._create('form');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +299,7 @@ bricks.Form = class extends bricks.FormBase {
|
|||||||
i18n:true});
|
i18n:true});
|
||||||
this.add_widget(d);
|
this.add_widget(d);
|
||||||
}
|
}
|
||||||
|
this.set_css('vcontainer');
|
||||||
var filler = new bricks.Filler({});
|
var filler = new bricks.Filler({});
|
||||||
this.add_widget(filler);
|
this.add_widget(filler);
|
||||||
this.body = new bricks.FormBody(this, opts);
|
this.body = new bricks.FormBody(this, opts);
|
||||||
|
@ -192,6 +192,7 @@ bricks.ModalForm = class extends bricks.Modal {
|
|||||||
}
|
}
|
||||||
build_form(){
|
build_form(){
|
||||||
var opts = {
|
var opts = {
|
||||||
|
height:'100%',
|
||||||
title:this.opts.title,
|
title:this.opts.title,
|
||||||
description:this.opts.description,
|
description:this.opts.description,
|
||||||
fields:this.opts.fields
|
fields:this.opts.fields
|
||||||
|
187
bricks/rtc.js
Normal file
187
bricks/rtc.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
var bricks = window.bricks || {}
|
||||||
|
|
||||||
|
bricks.VideoBox = class extends bricks.JsWidget {
|
||||||
|
create(){
|
||||||
|
this.dom_element = this._create('video');
|
||||||
|
this.set_attribute('autoplay', true);
|
||||||
|
this.set_attribute('muted', true);
|
||||||
|
}
|
||||||
|
get_stream(){
|
||||||
|
return this.stream;
|
||||||
|
}
|
||||||
|
set_stream(stream){
|
||||||
|
this.stream = stream
|
||||||
|
this.dom_element.srcObject = this.stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bricks.RTCClient = class extends bricks.VBox {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"signaling_url":
|
||||||
|
"ice_url":
|
||||||
|
"rtcid":
|
||||||
|
"rtcname"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
super(opts);
|
||||||
|
this.localVideo = new bricks.VideoBox({});
|
||||||
|
this.remoteVideo = new bricks.VideoBox({});
|
||||||
|
this.peerConnection;
|
||||||
|
this.socket = new WebSocket(this.signaling_url);
|
||||||
|
this.socket.onopen = this.register_myself.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.socket.send(JSON.stringify(d));
|
||||||
|
}
|
||||||
|
// 获取本地媒体流
|
||||||
|
async function getLocalStream() {
|
||||||
|
try {
|
||||||
|
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
||||||
|
this.localVideo.set_stream(stream);
|
||||||
|
return stream;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取本地媒体流失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async call_request(peer_id){
|
||||||
|
var d = {
|
||||||
|
type:'callrequest',
|
||||||
|
rtcid:peer_id
|
||||||
|
}
|
||||||
|
this.peer_id = peer_id;
|
||||||
|
this.role = 'requester';
|
||||||
|
this.socket.send(JSON.stringify(d));
|
||||||
|
}
|
||||||
|
async send_offer(){
|
||||||
|
var offer = await this.peerConnection.createOffer();
|
||||||
|
this.peerConnection.setLocalDescription(offer);
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type:'offer',
|
||||||
|
offer:this.peerConnection.localDescription,
|
||||||
|
to:this.peer_id
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
send_candidate(event){
|
||||||
|
if (event.candidate) {
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type: 'iceCandidate',
|
||||||
|
to:this.peer_id,
|
||||||
|
candidate: event.candidate
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async need_conform_call(peer_id){
|
||||||
|
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));
|
||||||
|
w.open();
|
||||||
|
}
|
||||||
|
call_accepted(peer_id){
|
||||||
|
if (this.peer_id){
|
||||||
|
this.call_close();
|
||||||
|
}
|
||||||
|
this.peer_id = peer_id
|
||||||
|
this.role = 'responser'
|
||||||
|
async this.createPeerConnection();
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type: 'callAccepted',
|
||||||
|
to: peer_id
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
async call_close(active){
|
||||||
|
this.peerConnection.onicecandidate = null;
|
||||||
|
this.peerConnection.ontrack = null;
|
||||||
|
this.peerConnection.close();
|
||||||
|
if (! active){
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type:'disconnect',
|
||||||
|
to:this.peer_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.peer_id = null;
|
||||||
|
this.localVideo.get_stream().getTracks().forEach(track => track.stop());
|
||||||
|
}
|
||||||
|
call_hangup(peer_id){
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type: 'callRejected',
|
||||||
|
to: peer_id
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
async signaling_message_handle(event){
|
||||||
|
var d = event.data;
|
||||||
|
switch (d.type){
|
||||||
|
case 'callRequest':
|
||||||
|
this.need_conform_call(d.from);
|
||||||
|
break;
|
||||||
|
case 'offer':
|
||||||
|
var offer = new RTCSessionDescription(d.offer);
|
||||||
|
var answer = await this.peerConnection.setRemoteDescription(offer);
|
||||||
|
this.peerConnection.setLocalDescription(answer);
|
||||||
|
this.socket.send(JSON.stringify({
|
||||||
|
type:'answer',
|
||||||
|
answer:answer,
|
||||||
|
to:this.peer_id
|
||||||
|
});
|
||||||
|
case 'answer':
|
||||||
|
if (d.from == self.peer_id){
|
||||||
|
var desc = new RTCSessionDescription(d.answer));
|
||||||
|
this.peerConnection.setRemoteDescription(desc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'iceCandidate':
|
||||||
|
if (d.from == self.peer_id){
|
||||||
|
var candidate = new RTCIceCandidate(d.candidate);
|
||||||
|
this.peerConnection.addIceCandidate(candidate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'callAccepted':
|
||||||
|
await this.createPeerConnection(this.peer_id);
|
||||||
|
break;
|
||||||
|
case 'callRejected':
|
||||||
|
this.peer_id = null;
|
||||||
|
break;
|
||||||
|
case 'disconnect':
|
||||||
|
this.call_close(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 PeerConnection
|
||||||
|
async createPeerConnection(to_id) {
|
||||||
|
if (this.role == 'requester'){
|
||||||
|
await this.send_offer();
|
||||||
|
}
|
||||||
|
const configuration = {
|
||||||
|
// iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
||||||
|
iceServers: [
|
||||||
|
{ urls: this.ice_url },
|
||||||
|
{ urls: 'stun:stunserver2024.stunprotocol.org:3478' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
this.peerConnection = new RTCPeerConnection(configuration);
|
||||||
|
|
||||||
|
// 处理本地流添加到 PeerConnection
|
||||||
|
this.localVideo.stream.getTracks().forEach(track => this.peerConnection.addTrack(track, this.localVideo.stream));
|
||||||
|
|
||||||
|
// 处理 ICE 候选
|
||||||
|
this.peerConnection.onicecandidate = this.send_candidate.bind(this, to_id);
|
||||||
|
|
||||||
|
// 处理远程流添加
|
||||||
|
this.peerConnection.ontrack = event => {
|
||||||
|
this.remoteVideo.set_stream(event.streams[0]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user