mirror of
https://github.com/cnotch/ipchub.git
synced 2025-09-26 19:41:18 +08:00
add wsp SWITCH command
This commit is contained in:
@@ -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,
|
@@ -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) {
|
||||
|
@@ -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{
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user