add wsp SWITCH command

This commit is contained in:
cnotch
2024-11-29 08:13:10 +08:00
parent ae6d1434a8
commit a36242d9a6
4 changed files with 123 additions and 33 deletions

View File

@@ -4288,6 +4288,7 @@
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_SWITCH)
.addTransition(RTSPClientSM.STATE_SWITCH, RTSPClientSM.STATE_SETUP)
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_UDP)
.addTransition(RTSPClientSM.STATE_SWITCH, RTSPClientSM.STATE_UDP)
.addTransition(RTSPClientSM.STATE_UDP, RTSPClientSM.STATE_SETUP)
.addTransition(RTSPClientSM.STATE_SETUP, RTSPClientSM.STATE_STREAMS)
.addTransition(RTSPClientSM.STATE_TEARDOWN, RTSPClientSM.STATE_INITIAL)
@@ -4706,7 +4707,7 @@
if (reason == 461) {
this.transitionTo(RTSPClientSM.STATE_UDP);
} else {
console.error(e);
console.error(reason);
this.stop();
this.reset();
}
@@ -9179,9 +9180,11 @@
// custom close codes
static get WCC_INVALID_DOMAIN() {return 4000;}
static get WCC_DEMO_LIMIT_REACHED() {return 4002;}
constructor(ver){
this.ver = ver;
WSPProtocol.seq = 0;
}
build(cmd, data, payload=''){
@@ -9221,7 +9224,6 @@
return null;
}
}
WSPProtocol.seq = 0;
class WebSocketProxy {
static get CHN_CONTROL() {return 'control';}
@@ -9289,6 +9291,9 @@
err.message = "Invalid Domain (credentials)";
Log$a.error("Invalid domain (credentials)");
this.error(err);
} else if(error.code === WSPProtocol.WCC_DEMO_LIMIT_REACHED){
let err = new SMediaError(error.code);
this.error(err);
}
}
@@ -9394,7 +9399,8 @@
Object.assign(headers, {
host: this.endpoint.host,
port: this.endpoint.port,
client: this.endpoint.client
client: this.endpoint.client,
restreamer: md5(this.endpoint.full),
});
}
let msgLicense = this.builder.build(WSPProtocol.CMD_GET_INFO, headers);
@@ -9606,6 +9612,7 @@
class H265Decoder {
constructor(canvas) {
this.canvas = canvas;
this.canvasHandler = new CanvasHandler(this.canvas);
this.remuxer;
this.decoder;
}
@@ -9673,35 +9680,96 @@
}
displayImage(image) {
var w = image.get_width();
var h = image.get_height();
if (w != this.canvas.width || h != this.canvas.height || !this.image_data) {
this.canvas.width = w;
this.canvas.height = h;
if (!this.image_data) {
let w = image.get_width();
let h = image.get_height();
this.image_data = this.ctx.createImageData(w, h);
var image_data = this.image_data.data;
for (var i=0; i<w*h; i++) {
let image_data = this.image_data.data;
for (let i=0; i<w*h; i++) {
image_data[i*4+3] = 255;
}
}
var that = this;
let that = this;
image.display(this.image_data, function(display_image_data) {
if (window.requestAnimationFrame) {
that.pending_image_data = display_image_data;
window.requestAnimationFrame(function() {
if (that.pending_image_data) {
that.ctx.putImageData(that.pending_image_data, 0, 0);
that.canvasHandler.draw(that.pending_image_data);
that.pending_image_data = null;
}
});
} else {
that.ctx.putImageData(display_image_data, 0, 0);
that.canvasHandler.draw(display_image_data);
}
});
}
}
class CanvasHandler {
constructor(canvas) {
this.canvas = canvas;
this.ctx = this.canvas.getContext("2d");
this.auxiliary_canvas = document.createElement("canvas");
this.auxiliary_ctx = this.auxiliary_canvas.getContext("2d");
this.eventSource = new EventEmitter();
}
draw(imageData) {
let shouldCanvasResize = this.canvas.getAttribute("resize") === "true";
this.trueSizeCheck(imageData);
if (shouldCanvasResize) {
this.drawByImageSize(imageData);
} else {
this.drawByCanvasSize(imageData);
}
}
drawByCanvasSize(imageData) {
this.canvasResize(imageData.width, imageData.height, this.auxiliary_canvas);
this.auxiliary_ctx.putImageData(imageData, 0, 0);
this.restoreCanvasSize(this.canvas);
this.ctx.drawImage(this.auxiliary_canvas, 0, 0, this.canvas.width, this.canvas.height);
}
drawByImageSize(imageData) {
this.canvasResize(imageData.width, imageData.height, this.canvas);
this.ctx.putImageData(imageData, 0, 0);
}
canvasResize(width, height, canvas) {
if (width != canvas.width || height != canvas.height) {
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
}
}
restoreCanvasSize(canvas) {
let resolution = canvas.getAttribute("resolution");
if (resolution) {
let size = resolution.split('x');
this.canvasResize(size[0], size[1], canvas);
}
}
trueSizeCheck(imageData) {
if (this.trueSize === undefined) {
this.trueSize = {
"width": imageData.width,
"height": imageData.height,
};
this.eventSource.dispatchEvent("trueSize", this.trueSize);
}
}
}
const Log$b = getTagged('wsp');
class StreamType {
@@ -9772,6 +9840,7 @@
this.infoHandler = opts.infoHandler || null;
this.dataHandler = opts.dataHandler || null;
this.videoFormatHandler = opts.videoFormatHandler || null;
this.trueSizeHandler = opts.trueSizeHandler || null;
this.queryCredentials = opts.queryCredentials || null;
this.bufferDuration_ = opts.bufferDuration || 120;
@@ -9972,6 +10041,9 @@
this.h265Decoder = new H265Decoder(this.canvas);
this.h265Decoder.attachSource(this.client);
this.h265Decoder.canvasHandler.eventSource.addEventListener("trueSize", (event)=>{
this.truesizeCallback(event.detail);
});
this.continuousRecording.attachSource(this.remuxer);
this.eventRecording.attachSource(this.remuxer);
@@ -10028,6 +10100,12 @@
}
}
truesizeCallback(size) {
if (this.trueSizeHandler) {
this.trueSizeHandler(size);
}
}
mediadata(data, prefix){
if (data !== undefined) {
if (this.dataHandler){
@@ -10121,6 +10199,11 @@
opts.videoFormatHandler(format);
}
},
trueSizeHandler(size) {
if(opts.trueSizeHandler) {
opts.trueSizeHandler(size);
}
},
redirectNativeMediaErrors: opts.redirectNativeMediaErrors,
bufferDuration : opts.bufferDuration,

View File

@@ -84,7 +84,7 @@ To activate key, please, use the activation application that is placed:
<p>For more information go to <a href="https://streamedian.com/docs/">documentation</a></p>
<script src="libde265.js"></script>
<script src="free.player.3.1.js"></script>
<script src="free.player.3.3.js"></script>
<script>
var scrollStatPl = true;
@@ -184,7 +184,7 @@ To activate key, please, use the activation application that is placed:
<script>
if (window.Streamedian) {
let errHandler = function(err){
alert(err.message);
// alert(err.message);
};
let infHandler = function(inf) {

View File

@@ -27,6 +27,7 @@ const (
CmdJoin = "JOIN" // 数据通道使用
CmdWrap = "WRAP" // 包装其他协议的命令
CmdGetInfo = "GET_INFO" // 获取客户及license信息
CmdSwitch = "SWITCH" // 当视频为H265时会发送该命令
)
// WSP 协议字段
@@ -65,6 +66,7 @@ var (
CmdInit: true,
CmdJoin: true,
CmdWrap: true,
CmdSwitch: true,
}
bspool = &sync.Pool{

View File

@@ -201,27 +201,32 @@ func (s *Session) process() {
break
}
if req.Cmd != CmdWrap {
s.logger.Error("must is WRAP command request")
break
}
// 从包装命令中提取 rtsp 请求
var rtspReq *rtsp.Request
rtspReq, err = rtsp.ReadRequest(bufio.NewReader(bytes.NewBufferString(req.Body)))
if err != nil {
break
}
// 处理请求,并获得响应
rtspResp := s.onRequest(rtspReq)
// 发送响应
buf := buffers.Get().(*bytes.Buffer)
buf.Reset()
defer buffers.Put(buf)
req.ResponseOK(buf, map[string]string{FieldChannel: s.channelID}, "")
rtspResp.Write(buf)
teardownReq := false //Teardown RTSP Request
if req.Cmd == CmdWrap {
// 从包装命令中提取 rtsp 请求
var rtspReq *rtsp.Request
rtspReq, err = rtsp.ReadRequest(bufio.NewReader(bytes.NewBufferString(req.Body)))
if err != nil {
break
}
teardownReq = rtspReq.Method == rtsp.MethodTeardown
// 处理请求,并获得响应
rtspResp := s.onRequest(rtspReq)
// 响应写入buf
rtspResp.Write(buf)
} else if req.Cmd == CmdSwitch {
} else {
s.logger.Error("must is WRAP or SWITCH command request")
break
}
// 发送响应
_, err = s.conn.Write(buf.Bytes())
if err != nil {
break
@@ -230,7 +235,7 @@ func (s *Session) process() {
s.logger.Debugf("wsp ===>>>\r\n%s", buf.String())
// 关闭通道
if rtspReq.Method == rtsp.MethodTeardown {
if teardownReq {
break
}
}