@besovideo/webrtc-player 0.8.94 → 0.8.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -2
- package/README.webrtc.md +21 -0
- package/dist/main.browser.js +110 -52
- package/dist/main.es.js +110 -52
- package/dist/types/components/subComponent/playState.d.ts +2 -4
- package/dist/types/plugins/player/event.d.ts +13 -4
- package/dist/types/plugins/player/index.d.ts +1 -0
- package/dist/types/plugins/ptz/index.d.ts +1 -1
- package/dist/types/plugins/video.d.ts +2 -1
- package/dist/types/utils/media.d.ts +11 -1
- package/dist/types/utils/webMCombina.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
## 简介 Introduction
|
|
8
8
|
|
|
9
9
|
> 设备视频播放、对讲封装
|
|
10
|
+
[Webrtc 与 平台接口关系](README.webrtc.md)
|
|
10
11
|
|
|
11
12
|
## 安装 Installation
|
|
12
13
|
|
|
@@ -170,9 +171,49 @@ instance.playerStatus : {
|
|
|
170
171
|
// 设置录像状态
|
|
171
172
|
Set(status: {type: "recordStart" | "recordStop"}): void;
|
|
172
173
|
// 添加事件监听, type == "recordStop" recordInfo 才有值
|
|
173
|
-
addEventListener(handle: ((status: {
|
|
174
|
+
addEventListener(handle: ((status: {
|
|
175
|
+
type: "recordStart" | "recordStop",
|
|
176
|
+
recordInfo?: {
|
|
177
|
+
data: Blob; // 数据
|
|
178
|
+
startTime: number; // 录像开始时间 utc ms
|
|
179
|
+
endTime: number; // 录像结束时间 utc ms
|
|
180
|
+
duration: number; // 录像时长 ms
|
|
181
|
+
fileName: string; // 文件名
|
|
182
|
+
puOptions: {
|
|
183
|
+
id: string; // 设备名称
|
|
184
|
+
index: number; // 通道ID
|
|
185
|
+
name?: string; //设备名称,用于内部UI显示
|
|
186
|
+
indexName?: string; //通道名称,用于内部UI显示
|
|
187
|
+
},
|
|
188
|
+
//调用将取消自动下载,返回下载函数
|
|
189
|
+
cancelAutoDownload: () => {
|
|
190
|
+
//调用该接口,浏览器下载文件, filename 不填为默认的文件名,否则为[filename].webm
|
|
191
|
+
download(filename?: string): void;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}) => void)):void;
|
|
174
195
|
// 移除事件监听
|
|
175
|
-
removeEventListener(handle: ((status: {
|
|
196
|
+
removeEventListener(handle: ((status: {
|
|
197
|
+
type: "recordStart" | "recordStop",
|
|
198
|
+
recordInfo?: {
|
|
199
|
+
data: Blob; // 数据
|
|
200
|
+
startTime: number; // 录像开始时间 utc ms
|
|
201
|
+
endTime: number; // 录像结束时间 utc ms
|
|
202
|
+
duration: number; // 录像时长 ms
|
|
203
|
+
fileName: string; // 文件名
|
|
204
|
+
puOptions: {
|
|
205
|
+
id: string; // 设备名称
|
|
206
|
+
index: number; // 通道ID
|
|
207
|
+
name?: string; //设备名称,用于内部UI显示
|
|
208
|
+
indexName?: string; //通道名称,用于内部UI显示
|
|
209
|
+
},
|
|
210
|
+
//调用将取消自动下载,返回下载函数
|
|
211
|
+
cancelAutoDownload: () => {
|
|
212
|
+
//调用该接口,浏览器下载文件, filename 不填为默认的文件名,否则为[filename].webm
|
|
213
|
+
download(filename?: string): void;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}) => void)):void;
|
|
176
217
|
},
|
|
177
218
|
rotate: {
|
|
178
219
|
// 获取旋转状态,顺时针方向
|
package/README.webrtc.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
这个包封装了[平台接口](https://bvcsp.apifox.cn/)流媒体相关的操作。
|
|
2
|
+
包含 实时视频 对讲 会议的流媒体 操作
|
|
3
|
+
|
|
4
|
+
流媒体基于webrtc 和 bvrtc两种
|
|
5
|
+
|
|
6
|
+
### 先介绍Webrtc,介绍之后说下webrtc和bvrtc的区别:
|
|
7
|
+
|
|
8
|
+
[简介](https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API/Session_lifetime)
|
|
9
|
+
|
|
10
|
+
[Webrtc的信令事务流程](https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API/Signaling_and_video_calling#%E4%BF%A1%E4%BB%A4%E4%BA%8B%E5%8A%A1%E6%B5%81%E7%A8%8B)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
[平台接口打开设备音视频流webrtc](https://bvcsp.apifox.cn/api-171249025)接口用作信令交互,就是上图中交互[SDP](https://developer.mozilla.org/zh-CN/docs/Glossary/SDP)。
|
|
14
|
+
|
|
15
|
+
通过webrtc打开设备实时视频 本包封装的过程就是,
|
|
16
|
+
1、创建 const rtcPC = RTCPeerConnection
|
|
17
|
+
2、创建Offer const {type, sdp} = await [rtcPC.createOffer()](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer)
|
|
18
|
+
3、设置本地SDP await [rtcPC.setLocalDescription](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription)({type, sdp})
|
|
19
|
+
4、通过 [平台接口打开设备音视频流webrtc](https://bvcsp.apifox.cn/api-171249025) 发送SDP到服务器,收到远程SDP, 保存 const remoteSDP = await post('/bvcsp/v1/dialog/device/webrtc', {...});
|
|
20
|
+
5、设置rtcPC的远程SDP [rtcPC.setRemoteDescription()](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription)({type: 'anwser', sdp: remoteSDP})
|
|
21
|
+
|
package/dist/main.browser.js
CHANGED
|
@@ -117,7 +117,7 @@ var bvPlayerCore = (() => {
|
|
|
117
117
|
var define_processenv_default;
|
|
118
118
|
var init_define_processenv = __esm({
|
|
119
119
|
"<define:processenv>"() {
|
|
120
|
-
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.8.
|
|
120
|
+
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.8.96", PROJECT_NAMESPACE: "bvplayer" };
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
|
|
@@ -7125,6 +7125,7 @@ If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'per
|
|
|
7125
7125
|
description: audioCodecPrivate
|
|
7126
7126
|
}
|
|
7127
7127
|
} : void 0;
|
|
7128
|
+
let maxTimestamp = -1;
|
|
7128
7129
|
handleEle((timestamp, data, bVideo, bKeyFrame) => {
|
|
7129
7130
|
if (bVideo) {
|
|
7130
7131
|
muxer.addVideoChunkRaw(data, bKeyFrame ? "key" : "delta", timestamp);
|
|
@@ -7133,9 +7134,15 @@ If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'per
|
|
|
7133
7134
|
muxer.addAudioChunkRaw(data, "key", timestamp, config);
|
|
7134
7135
|
}
|
|
7135
7136
|
}
|
|
7137
|
+
if (maxTimestamp < timestamp) {
|
|
7138
|
+
maxTimestamp = timestamp;
|
|
7139
|
+
}
|
|
7136
7140
|
});
|
|
7137
7141
|
muxer.finalize();
|
|
7138
|
-
return
|
|
7142
|
+
return {
|
|
7143
|
+
blob: new Blob([muxer.target.buffer]),
|
|
7144
|
+
maxTimestamp
|
|
7145
|
+
};
|
|
7139
7146
|
});
|
|
7140
7147
|
}
|
|
7141
7148
|
var createMediaRecorder = (mediaStream, done, mediaRecorderPartner) => {
|
|
@@ -7173,6 +7180,7 @@ If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'per
|
|
|
7173
7180
|
return mediaRecorder;
|
|
7174
7181
|
};
|
|
7175
7182
|
var createRecord = (_mediaStream, fileName, isDownload) => {
|
|
7183
|
+
const startTime = Date.now();
|
|
7176
7184
|
const tempMediaStreams = _mediaStream.getTracks().map((item) => {
|
|
7177
7185
|
const mediaStream2 = new MediaStream([item]);
|
|
7178
7186
|
item.addEventListener("ended", () => {
|
|
@@ -7189,14 +7197,30 @@ If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'per
|
|
|
7189
7197
|
const szWebM = [];
|
|
7190
7198
|
function done(e) {
|
|
7191
7199
|
return __async(this, null, function* () {
|
|
7200
|
+
let maxTimestamp = -1;
|
|
7192
7201
|
szWebM.push(e.data);
|
|
7193
7202
|
if (szWebM.length == mediaStreams.length) {
|
|
7194
|
-
|
|
7203
|
+
const { blob: blobWebM, maxTimestamp: _maxTimestamp } = yield combinaWebM(
|
|
7204
|
+
...szWebM
|
|
7205
|
+
);
|
|
7206
|
+
recordedChunks.push(blobWebM);
|
|
7207
|
+
if (_maxTimestamp > maxTimestamp) {
|
|
7208
|
+
maxTimestamp = _maxTimestamp;
|
|
7209
|
+
}
|
|
7195
7210
|
const blob = new Blob(recordedChunks, {
|
|
7196
7211
|
type: "video/webm"
|
|
7197
7212
|
});
|
|
7198
|
-
|
|
7199
|
-
file_default.downLoadBlob(blob, fileName, "webm");
|
|
7213
|
+
const downloadFile = (inFileName) => {
|
|
7214
|
+
file_default.downLoadBlob(blob, inFileName ? inFileName : fileName, "webm");
|
|
7215
|
+
};
|
|
7216
|
+
if (isDownload(blob, { duration: maxTimestamp / 1e3, startTime, endTime: startTime + maxTimestamp / 1e3, fileName }, () => {
|
|
7217
|
+
return {
|
|
7218
|
+
download(file2) {
|
|
7219
|
+
downloadFile(file2);
|
|
7220
|
+
}
|
|
7221
|
+
};
|
|
7222
|
+
})) {
|
|
7223
|
+
downloadFile(fileName);
|
|
7200
7224
|
}
|
|
7201
7225
|
recordedChunks = [];
|
|
7202
7226
|
}
|
|
@@ -7250,19 +7274,28 @@ If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'per
|
|
|
7250
7274
|
try {
|
|
7251
7275
|
const mediaStream = stream || element.captureStream(25);
|
|
7252
7276
|
let gOnMediaHolder = void 0;
|
|
7253
|
-
const mediaRecorder = createRecord(
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7277
|
+
const mediaRecorder = createRecord(
|
|
7278
|
+
mediaStream,
|
|
7279
|
+
fileName,
|
|
7280
|
+
(blob, metaInfo, downloadRecordGetter) => {
|
|
7281
|
+
if (gOnMediaHolder) {
|
|
7282
|
+
const holder = gOnMediaHolder;
|
|
7283
|
+
gOnMediaHolder = void 0;
|
|
7284
|
+
let bDownload = true;
|
|
7285
|
+
const cancelAutoDownload = () => {
|
|
7286
|
+
bDownload = false;
|
|
7287
|
+
return downloadRecordGetter();
|
|
7288
|
+
};
|
|
7289
|
+
holder(
|
|
7290
|
+
blob,
|
|
7291
|
+
metaInfo,
|
|
7292
|
+
cancelAutoDownload
|
|
7293
|
+
);
|
|
7294
|
+
return bDownload;
|
|
7295
|
+
}
|
|
7296
|
+
return true;
|
|
7263
7297
|
}
|
|
7264
|
-
|
|
7265
|
-
}));
|
|
7298
|
+
);
|
|
7266
7299
|
logger_default.info("\u5F55\u5236\u5B9E\u4F8B", mediaRecorder);
|
|
7267
7300
|
return [
|
|
7268
7301
|
mediaRecorder,
|
|
@@ -12594,8 +12627,9 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
12594
12627
|
this.vSpeed = 50;
|
|
12595
12628
|
this.iPresetPoint = 1;
|
|
12596
12629
|
this._buttons = [];
|
|
12630
|
+
this._toastInject = {};
|
|
12597
12631
|
this._speedSlider = new speedSlider_default(this.hSpeed);
|
|
12598
|
-
this.
|
|
12632
|
+
this._toastInject.toast = params.toast;
|
|
12599
12633
|
}
|
|
12600
12634
|
// 由外界设置设备参数 也可直接通过public字段单独设置
|
|
12601
12635
|
setPuParam(puOption, token) {
|
|
@@ -12607,6 +12641,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
12607
12641
|
if (!operate)
|
|
12608
12642
|
return;
|
|
12609
12643
|
const sendOperate = (stop) => __async(this, null, function* () {
|
|
12644
|
+
var _a;
|
|
12610
12645
|
logger_default.debug("sendOperate", operate, this.vSpeed, this.hSpeed, stop);
|
|
12611
12646
|
if (!this.puOption || !this.token)
|
|
12612
12647
|
return;
|
|
@@ -12624,7 +12659,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
12624
12659
|
);
|
|
12625
12660
|
} catch (e) {
|
|
12626
12661
|
const errCamera = e;
|
|
12627
|
-
this.
|
|
12662
|
+
(_a = this._toastInject.toast) == null ? void 0 : _a.error(errCamera.getErrorCodeDesc());
|
|
12628
12663
|
}
|
|
12629
12664
|
});
|
|
12630
12665
|
button.addEventListener("start", () => sendOperate(false));
|
|
@@ -12912,6 +12947,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
12912
12947
|
this._video = new video_default({
|
|
12913
12948
|
puOptions: options == null ? void 0 : options.puOptions
|
|
12914
12949
|
});
|
|
12950
|
+
this._puOptions = options == null ? void 0 : options.puOptions;
|
|
12915
12951
|
this._spinner = new spinner_default({ spin: false });
|
|
12916
12952
|
this._toast = new toast_default();
|
|
12917
12953
|
this._mask = new mask_default({ visible: false });
|
|
@@ -13187,12 +13223,15 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
13187
13223
|
if ((_a = this._panel) == null ? void 0 : _a.controller.RecordButton) {
|
|
13188
13224
|
(_b = this._panel) == null ? void 0 : _b.controller.RecordButton.dispatch("click");
|
|
13189
13225
|
} else {
|
|
13190
|
-
this._video.recordStop((blob, cancelAutoDownload) => {
|
|
13191
|
-
this.dispatch("recordStop", {
|
|
13226
|
+
this._video.recordStop((blob, mataInfo, cancelAutoDownload) => {
|
|
13227
|
+
this.dispatch("recordStop", __spreadProps(__spreadValues({
|
|
13228
|
+
puOptions: this._puOptions
|
|
13229
|
+
}, mataInfo), {
|
|
13192
13230
|
data: blob,
|
|
13193
13231
|
cancelAutoDownload
|
|
13194
|
-
});
|
|
13232
|
+
}));
|
|
13195
13233
|
this._recordState.dispatch("RecordEnd");
|
|
13234
|
+
return false;
|
|
13196
13235
|
});
|
|
13197
13236
|
}
|
|
13198
13237
|
}
|
|
@@ -13258,12 +13297,15 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
13258
13297
|
this._recordState.dispatch("RecordStart");
|
|
13259
13298
|
});
|
|
13260
13299
|
panel.controller.addEventListener("recordStop", () => {
|
|
13261
|
-
this._video.recordStop((blob, cancelAutoDownload) => {
|
|
13262
|
-
this.dispatch("recordStop", {
|
|
13300
|
+
this._video.recordStop((blob, metaInfo, cancelAutoDownload) => {
|
|
13301
|
+
this.dispatch("recordStop", __spreadProps(__spreadValues({
|
|
13302
|
+
puOptions: this._puOptions
|
|
13303
|
+
}, metaInfo), {
|
|
13263
13304
|
data: blob,
|
|
13264
13305
|
cancelAutoDownload
|
|
13265
|
-
});
|
|
13306
|
+
}));
|
|
13266
13307
|
this._recordState.dispatch("RecordEnd");
|
|
13308
|
+
return false;
|
|
13267
13309
|
});
|
|
13268
13310
|
});
|
|
13269
13311
|
panel.controller.addEventListener("rotate", () => {
|
|
@@ -13571,6 +13613,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
13571
13613
|
// smooth: 播放平滑度。[1,7],值越小越实时。
|
|
13572
13614
|
// algokey: 加解密算法:密钥。格式:算法:base64(密钥)。例如: SM4:MTIzNDU2Nzg=
|
|
13573
13615
|
constructor() {
|
|
13616
|
+
console.log("================== bvrtc version: 1.0.1 20241028 ==================");
|
|
13574
13617
|
this.hplayer = 0;
|
|
13575
13618
|
this.canvas = null;
|
|
13576
13619
|
this.dialogid = "";
|
|
@@ -14499,6 +14542,20 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
14499
14542
|
this.audioCtx.close();
|
|
14500
14543
|
this.audioCtx = null;
|
|
14501
14544
|
};
|
|
14545
|
+
var woker_str = `
|
|
14546
|
+
class BVAudioProcessor extends AudioWorkletProcessor {
|
|
14547
|
+
process(inputs, outputs, parameters) {
|
|
14548
|
+
const inputdata = inputs[0][0];
|
|
14549
|
+
this.port.postMessage(inputdata);
|
|
14550
|
+
return true;
|
|
14551
|
+
}
|
|
14552
|
+
}
|
|
14553
|
+
registerProcessor('bv-audio-processor', BVAudioProcessor);
|
|
14554
|
+
`;
|
|
14555
|
+
var audioProcessorBolb = new Blob([woker_str], {
|
|
14556
|
+
type: "application/javascript"
|
|
14557
|
+
});
|
|
14558
|
+
var audioProcessorUrl = URL.createObjectURL(audioProcessorBolb);
|
|
14502
14559
|
function BVPcmRecorder(config, cb) {
|
|
14503
14560
|
if (!config) {
|
|
14504
14561
|
config = {
|
|
@@ -14510,7 +14567,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
14510
14567
|
};
|
|
14511
14568
|
}
|
|
14512
14569
|
this.config = config;
|
|
14513
|
-
this.sampleRate = new (window.AudioContext || window.webkitAudioContext)().sampleRate;
|
|
14570
|
+
this.sampleRate = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: this.config.sampleRate }).sampleRate;
|
|
14514
14571
|
this.fftSize = 512;
|
|
14515
14572
|
this.analyser = null;
|
|
14516
14573
|
this.audioInput = null;
|
|
@@ -14520,20 +14577,23 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
14520
14577
|
this.audioData = null;
|
|
14521
14578
|
this.audioSize = 0;
|
|
14522
14579
|
this.cb = cb;
|
|
14523
|
-
this.init();
|
|
14524
14580
|
console.log("sampleRate " + this.sampleRate);
|
|
14525
14581
|
}
|
|
14526
14582
|
BVPcmRecorder.prototype.start = function() {
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
|
|
14535
|
-
|
|
14536
|
-
|
|
14583
|
+
return __async(this, null, function* () {
|
|
14584
|
+
yield this.init();
|
|
14585
|
+
navigator.mediaDevices.getUserMedia({
|
|
14586
|
+
audio: true,
|
|
14587
|
+
sampleRate: this.config.sampleRate
|
|
14588
|
+
}).then((stream) => {
|
|
14589
|
+
this.audioInput = this.context.createMediaStreamSource(stream);
|
|
14590
|
+
}, (error2) => {
|
|
14591
|
+
console.error(error2);
|
|
14592
|
+
}).then(() => {
|
|
14593
|
+
this.audioInput.connect(this.analyser);
|
|
14594
|
+
this.analyser.connect(this.recorder);
|
|
14595
|
+
this.recorder.connect(this.context.destination);
|
|
14596
|
+
});
|
|
14537
14597
|
});
|
|
14538
14598
|
};
|
|
14539
14599
|
BVPcmRecorder.prototype.stop = function() {
|
|
@@ -14541,23 +14601,21 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
14541
14601
|
this.audioInput.disconnect();
|
|
14542
14602
|
if (this.recorder)
|
|
14543
14603
|
this.recorder.disconnect();
|
|
14604
|
+
if (this.context)
|
|
14605
|
+
this.context.close();
|
|
14544
14606
|
};
|
|
14545
14607
|
BVPcmRecorder.prototype.init = function() {
|
|
14546
|
-
this
|
|
14547
|
-
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
this.context,
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
if (this.config.numberChannels === 1) {
|
|
14558
|
-
const data = e.inputBuffer.getChannelData(0);
|
|
14559
|
-
this.handlePcm(new Float32Array(data));
|
|
14560
|
-
}
|
|
14608
|
+
return __async(this, null, function* () {
|
|
14609
|
+
this.context = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: this.config.sampleRate });
|
|
14610
|
+
this.analyser = this.context.createAnalyser();
|
|
14611
|
+
this.analyser.fftSize = this.fftSize;
|
|
14612
|
+
yield this.context.audioWorklet.addModule(audioProcessorUrl);
|
|
14613
|
+
this.recorder = new AudioWorkletNode(this.context, "bv-audio-processor");
|
|
14614
|
+
this.recorder.port.onmessage = (e) => {
|
|
14615
|
+
if (e.data)
|
|
14616
|
+
this.handlePcm(e.data);
|
|
14617
|
+
};
|
|
14618
|
+
});
|
|
14561
14619
|
};
|
|
14562
14620
|
BVPcmRecorder.prototype.handlePcm = function(bytes) {
|
|
14563
14621
|
if (bytes[0] === 0 && bytes[1] === 0)
|
package/dist/main.es.js
CHANGED
|
@@ -111,7 +111,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
111
111
|
var define_processenv_default;
|
|
112
112
|
var init_define_processenv = __esm({
|
|
113
113
|
"<define:processenv>"() {
|
|
114
|
-
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.8.
|
|
114
|
+
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.8.96", PROJECT_NAMESPACE: "bvplayer" };
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
117
|
|
|
@@ -7109,6 +7109,7 @@ function combinaWebM(webM1, webM2) {
|
|
|
7109
7109
|
description: audioCodecPrivate
|
|
7110
7110
|
}
|
|
7111
7111
|
} : void 0;
|
|
7112
|
+
let maxTimestamp = -1;
|
|
7112
7113
|
handleEle((timestamp, data, bVideo, bKeyFrame) => {
|
|
7113
7114
|
if (bVideo) {
|
|
7114
7115
|
muxer.addVideoChunkRaw(data, bKeyFrame ? "key" : "delta", timestamp);
|
|
@@ -7117,9 +7118,15 @@ function combinaWebM(webM1, webM2) {
|
|
|
7117
7118
|
muxer.addAudioChunkRaw(data, "key", timestamp, config);
|
|
7118
7119
|
}
|
|
7119
7120
|
}
|
|
7121
|
+
if (maxTimestamp < timestamp) {
|
|
7122
|
+
maxTimestamp = timestamp;
|
|
7123
|
+
}
|
|
7120
7124
|
});
|
|
7121
7125
|
muxer.finalize();
|
|
7122
|
-
return
|
|
7126
|
+
return {
|
|
7127
|
+
blob: new Blob([muxer.target.buffer]),
|
|
7128
|
+
maxTimestamp
|
|
7129
|
+
};
|
|
7123
7130
|
});
|
|
7124
7131
|
}
|
|
7125
7132
|
var createMediaRecorder = (mediaStream, done, mediaRecorderPartner) => {
|
|
@@ -7157,6 +7164,7 @@ var createMediaRecorder = (mediaStream, done, mediaRecorderPartner) => {
|
|
|
7157
7164
|
return mediaRecorder;
|
|
7158
7165
|
};
|
|
7159
7166
|
var createRecord = (_mediaStream, fileName, isDownload) => {
|
|
7167
|
+
const startTime = Date.now();
|
|
7160
7168
|
const tempMediaStreams = _mediaStream.getTracks().map((item) => {
|
|
7161
7169
|
const mediaStream2 = new MediaStream([item]);
|
|
7162
7170
|
item.addEventListener("ended", () => {
|
|
@@ -7173,14 +7181,30 @@ var createRecord = (_mediaStream, fileName, isDownload) => {
|
|
|
7173
7181
|
const szWebM = [];
|
|
7174
7182
|
function done(e) {
|
|
7175
7183
|
return __async(this, null, function* () {
|
|
7184
|
+
let maxTimestamp = -1;
|
|
7176
7185
|
szWebM.push(e.data);
|
|
7177
7186
|
if (szWebM.length == mediaStreams.length) {
|
|
7178
|
-
|
|
7187
|
+
const { blob: blobWebM, maxTimestamp: _maxTimestamp } = yield combinaWebM(
|
|
7188
|
+
...szWebM
|
|
7189
|
+
);
|
|
7190
|
+
recordedChunks.push(blobWebM);
|
|
7191
|
+
if (_maxTimestamp > maxTimestamp) {
|
|
7192
|
+
maxTimestamp = _maxTimestamp;
|
|
7193
|
+
}
|
|
7179
7194
|
const blob = new Blob(recordedChunks, {
|
|
7180
7195
|
type: "video/webm"
|
|
7181
7196
|
});
|
|
7182
|
-
|
|
7183
|
-
file_default.downLoadBlob(blob, fileName, "webm");
|
|
7197
|
+
const downloadFile = (inFileName) => {
|
|
7198
|
+
file_default.downLoadBlob(blob, inFileName ? inFileName : fileName, "webm");
|
|
7199
|
+
};
|
|
7200
|
+
if (isDownload(blob, { duration: maxTimestamp / 1e3, startTime, endTime: startTime + maxTimestamp / 1e3, fileName }, () => {
|
|
7201
|
+
return {
|
|
7202
|
+
download(file2) {
|
|
7203
|
+
downloadFile(file2);
|
|
7204
|
+
}
|
|
7205
|
+
};
|
|
7206
|
+
})) {
|
|
7207
|
+
downloadFile(fileName);
|
|
7184
7208
|
}
|
|
7185
7209
|
recordedChunks = [];
|
|
7186
7210
|
}
|
|
@@ -7234,19 +7258,28 @@ var record = (element, stream, fileName = `record_${Date.now()}`) => {
|
|
|
7234
7258
|
try {
|
|
7235
7259
|
const mediaStream = stream || element.captureStream(25);
|
|
7236
7260
|
let gOnMediaHolder = void 0;
|
|
7237
|
-
const mediaRecorder = createRecord(
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7261
|
+
const mediaRecorder = createRecord(
|
|
7262
|
+
mediaStream,
|
|
7263
|
+
fileName,
|
|
7264
|
+
(blob, metaInfo, downloadRecordGetter) => {
|
|
7265
|
+
if (gOnMediaHolder) {
|
|
7266
|
+
const holder = gOnMediaHolder;
|
|
7267
|
+
gOnMediaHolder = void 0;
|
|
7268
|
+
let bDownload = true;
|
|
7269
|
+
const cancelAutoDownload = () => {
|
|
7270
|
+
bDownload = false;
|
|
7271
|
+
return downloadRecordGetter();
|
|
7272
|
+
};
|
|
7273
|
+
holder(
|
|
7274
|
+
blob,
|
|
7275
|
+
metaInfo,
|
|
7276
|
+
cancelAutoDownload
|
|
7277
|
+
);
|
|
7278
|
+
return bDownload;
|
|
7279
|
+
}
|
|
7280
|
+
return true;
|
|
7247
7281
|
}
|
|
7248
|
-
|
|
7249
|
-
}));
|
|
7282
|
+
);
|
|
7250
7283
|
logger_default.info("\u5F55\u5236\u5B9E\u4F8B", mediaRecorder);
|
|
7251
7284
|
return [
|
|
7252
7285
|
mediaRecorder,
|
|
@@ -12578,8 +12611,9 @@ var PtzPluginBase = class extends Plugin {
|
|
|
12578
12611
|
this.vSpeed = 50;
|
|
12579
12612
|
this.iPresetPoint = 1;
|
|
12580
12613
|
this._buttons = [];
|
|
12614
|
+
this._toastInject = {};
|
|
12581
12615
|
this._speedSlider = new speedSlider_default(this.hSpeed);
|
|
12582
|
-
this.
|
|
12616
|
+
this._toastInject.toast = params.toast;
|
|
12583
12617
|
}
|
|
12584
12618
|
// 由外界设置设备参数 也可直接通过public字段单独设置
|
|
12585
12619
|
setPuParam(puOption, token) {
|
|
@@ -12591,6 +12625,7 @@ var PtzPluginBase = class extends Plugin {
|
|
|
12591
12625
|
if (!operate)
|
|
12592
12626
|
return;
|
|
12593
12627
|
const sendOperate = (stop) => __async(this, null, function* () {
|
|
12628
|
+
var _a;
|
|
12594
12629
|
logger_default.debug("sendOperate", operate, this.vSpeed, this.hSpeed, stop);
|
|
12595
12630
|
if (!this.puOption || !this.token)
|
|
12596
12631
|
return;
|
|
@@ -12608,7 +12643,7 @@ var PtzPluginBase = class extends Plugin {
|
|
|
12608
12643
|
);
|
|
12609
12644
|
} catch (e) {
|
|
12610
12645
|
const errCamera = e;
|
|
12611
|
-
this.
|
|
12646
|
+
(_a = this._toastInject.toast) == null ? void 0 : _a.error(errCamera.getErrorCodeDesc());
|
|
12612
12647
|
}
|
|
12613
12648
|
});
|
|
12614
12649
|
button.addEventListener("start", () => sendOperate(false));
|
|
@@ -12896,6 +12931,7 @@ var PlayerPlugin = class extends Plugin {
|
|
|
12896
12931
|
this._video = new video_default({
|
|
12897
12932
|
puOptions: options == null ? void 0 : options.puOptions
|
|
12898
12933
|
});
|
|
12934
|
+
this._puOptions = options == null ? void 0 : options.puOptions;
|
|
12899
12935
|
this._spinner = new spinner_default({ spin: false });
|
|
12900
12936
|
this._toast = new toast_default();
|
|
12901
12937
|
this._mask = new mask_default({ visible: false });
|
|
@@ -13171,12 +13207,15 @@ var PlayerPlugin = class extends Plugin {
|
|
|
13171
13207
|
if ((_a = this._panel) == null ? void 0 : _a.controller.RecordButton) {
|
|
13172
13208
|
(_b = this._panel) == null ? void 0 : _b.controller.RecordButton.dispatch("click");
|
|
13173
13209
|
} else {
|
|
13174
|
-
this._video.recordStop((blob, cancelAutoDownload) => {
|
|
13175
|
-
this.dispatch("recordStop", {
|
|
13210
|
+
this._video.recordStop((blob, mataInfo, cancelAutoDownload) => {
|
|
13211
|
+
this.dispatch("recordStop", __spreadProps(__spreadValues({
|
|
13212
|
+
puOptions: this._puOptions
|
|
13213
|
+
}, mataInfo), {
|
|
13176
13214
|
data: blob,
|
|
13177
13215
|
cancelAutoDownload
|
|
13178
|
-
});
|
|
13216
|
+
}));
|
|
13179
13217
|
this._recordState.dispatch("RecordEnd");
|
|
13218
|
+
return false;
|
|
13180
13219
|
});
|
|
13181
13220
|
}
|
|
13182
13221
|
}
|
|
@@ -13242,12 +13281,15 @@ var PlayerPlugin = class extends Plugin {
|
|
|
13242
13281
|
this._recordState.dispatch("RecordStart");
|
|
13243
13282
|
});
|
|
13244
13283
|
panel.controller.addEventListener("recordStop", () => {
|
|
13245
|
-
this._video.recordStop((blob, cancelAutoDownload) => {
|
|
13246
|
-
this.dispatch("recordStop", {
|
|
13284
|
+
this._video.recordStop((blob, metaInfo, cancelAutoDownload) => {
|
|
13285
|
+
this.dispatch("recordStop", __spreadProps(__spreadValues({
|
|
13286
|
+
puOptions: this._puOptions
|
|
13287
|
+
}, metaInfo), {
|
|
13247
13288
|
data: blob,
|
|
13248
13289
|
cancelAutoDownload
|
|
13249
|
-
});
|
|
13290
|
+
}));
|
|
13250
13291
|
this._recordState.dispatch("RecordEnd");
|
|
13292
|
+
return false;
|
|
13251
13293
|
});
|
|
13252
13294
|
});
|
|
13253
13295
|
panel.controller.addEventListener("rotate", () => {
|
|
@@ -13555,6 +13597,7 @@ var BVMedia = class {
|
|
|
13555
13597
|
// smooth: 播放平滑度。[1,7],值越小越实时。
|
|
13556
13598
|
// algokey: 加解密算法:密钥。格式:算法:base64(密钥)。例如: SM4:MTIzNDU2Nzg=
|
|
13557
13599
|
constructor() {
|
|
13600
|
+
console.log("================== bvrtc version: 1.0.1 20241028 ==================");
|
|
13558
13601
|
this.hplayer = 0;
|
|
13559
13602
|
this.canvas = null;
|
|
13560
13603
|
this.dialogid = "";
|
|
@@ -14483,6 +14526,20 @@ BVPCMPlayer.prototype.destroy = function() {
|
|
|
14483
14526
|
this.audioCtx.close();
|
|
14484
14527
|
this.audioCtx = null;
|
|
14485
14528
|
};
|
|
14529
|
+
var woker_str = `
|
|
14530
|
+
class BVAudioProcessor extends AudioWorkletProcessor {
|
|
14531
|
+
process(inputs, outputs, parameters) {
|
|
14532
|
+
const inputdata = inputs[0][0];
|
|
14533
|
+
this.port.postMessage(inputdata);
|
|
14534
|
+
return true;
|
|
14535
|
+
}
|
|
14536
|
+
}
|
|
14537
|
+
registerProcessor('bv-audio-processor', BVAudioProcessor);
|
|
14538
|
+
`;
|
|
14539
|
+
var audioProcessorBolb = new Blob([woker_str], {
|
|
14540
|
+
type: "application/javascript"
|
|
14541
|
+
});
|
|
14542
|
+
var audioProcessorUrl = URL.createObjectURL(audioProcessorBolb);
|
|
14486
14543
|
function BVPcmRecorder(config, cb) {
|
|
14487
14544
|
if (!config) {
|
|
14488
14545
|
config = {
|
|
@@ -14494,7 +14551,7 @@ function BVPcmRecorder(config, cb) {
|
|
|
14494
14551
|
};
|
|
14495
14552
|
}
|
|
14496
14553
|
this.config = config;
|
|
14497
|
-
this.sampleRate = new (window.AudioContext || window.webkitAudioContext)().sampleRate;
|
|
14554
|
+
this.sampleRate = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: this.config.sampleRate }).sampleRate;
|
|
14498
14555
|
this.fftSize = 512;
|
|
14499
14556
|
this.analyser = null;
|
|
14500
14557
|
this.audioInput = null;
|
|
@@ -14504,20 +14561,23 @@ function BVPcmRecorder(config, cb) {
|
|
|
14504
14561
|
this.audioData = null;
|
|
14505
14562
|
this.audioSize = 0;
|
|
14506
14563
|
this.cb = cb;
|
|
14507
|
-
this.init();
|
|
14508
14564
|
console.log("sampleRate " + this.sampleRate);
|
|
14509
14565
|
}
|
|
14510
14566
|
BVPcmRecorder.prototype.start = function() {
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14567
|
+
return __async(this, null, function* () {
|
|
14568
|
+
yield this.init();
|
|
14569
|
+
navigator.mediaDevices.getUserMedia({
|
|
14570
|
+
audio: true,
|
|
14571
|
+
sampleRate: this.config.sampleRate
|
|
14572
|
+
}).then((stream) => {
|
|
14573
|
+
this.audioInput = this.context.createMediaStreamSource(stream);
|
|
14574
|
+
}, (error2) => {
|
|
14575
|
+
console.error(error2);
|
|
14576
|
+
}).then(() => {
|
|
14577
|
+
this.audioInput.connect(this.analyser);
|
|
14578
|
+
this.analyser.connect(this.recorder);
|
|
14579
|
+
this.recorder.connect(this.context.destination);
|
|
14580
|
+
});
|
|
14521
14581
|
});
|
|
14522
14582
|
};
|
|
14523
14583
|
BVPcmRecorder.prototype.stop = function() {
|
|
@@ -14525,23 +14585,21 @@ BVPcmRecorder.prototype.stop = function() {
|
|
|
14525
14585
|
this.audioInput.disconnect();
|
|
14526
14586
|
if (this.recorder)
|
|
14527
14587
|
this.recorder.disconnect();
|
|
14588
|
+
if (this.context)
|
|
14589
|
+
this.context.close();
|
|
14528
14590
|
};
|
|
14529
14591
|
BVPcmRecorder.prototype.init = function() {
|
|
14530
|
-
this
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
|
|
14535
|
-
this.context,
|
|
14536
|
-
|
|
14537
|
-
|
|
14538
|
-
|
|
14539
|
-
};
|
|
14540
|
-
|
|
14541
|
-
if (this.config.numberChannels === 1) {
|
|
14542
|
-
const data = e.inputBuffer.getChannelData(0);
|
|
14543
|
-
this.handlePcm(new Float32Array(data));
|
|
14544
|
-
}
|
|
14592
|
+
return __async(this, null, function* () {
|
|
14593
|
+
this.context = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: this.config.sampleRate });
|
|
14594
|
+
this.analyser = this.context.createAnalyser();
|
|
14595
|
+
this.analyser.fftSize = this.fftSize;
|
|
14596
|
+
yield this.context.audioWorklet.addModule(audioProcessorUrl);
|
|
14597
|
+
this.recorder = new AudioWorkletNode(this.context, "bv-audio-processor");
|
|
14598
|
+
this.recorder.port.onmessage = (e) => {
|
|
14599
|
+
if (e.data)
|
|
14600
|
+
this.handlePcm(e.data);
|
|
14601
|
+
};
|
|
14602
|
+
});
|
|
14545
14603
|
};
|
|
14546
14604
|
BVPcmRecorder.prototype.handlePcm = function(bytes) {
|
|
14547
14605
|
if (bytes[0] === 0 && bytes[1] === 0)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PlayerPlugin from "../../plugins/player";
|
|
2
2
|
import { IDataHandle } from "src/core/events";
|
|
3
|
+
import { IRecordStopInfo } from "src/plugins/player/event";
|
|
3
4
|
type EnumRotate = "Rotate0" | "Rotate90" | "Rotate180" | "Rotate270";
|
|
4
5
|
export type IPlayerState = ReturnType<typeof CreatePlayerState>;
|
|
5
6
|
export declare function CreatePlayerState(player: PlayerPlugin): {
|
|
@@ -8,10 +9,7 @@ export declare function CreatePlayerState(player: PlayerPlugin): {
|
|
|
8
9
|
information: IDataHandle<boolean>;
|
|
9
10
|
record: IDataHandle<{
|
|
10
11
|
type: "recordStart" | "recordStop";
|
|
11
|
-
recordInfo?:
|
|
12
|
-
data: Blob;
|
|
13
|
-
cancelAutoDownload: () => void;
|
|
14
|
-
} | undefined;
|
|
12
|
+
recordInfo?: IRecordStopInfo | undefined;
|
|
15
13
|
}>;
|
|
16
14
|
rotate: IDataHandle<{
|
|
17
15
|
type: EnumRotate;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IPuOption } from "src/main";
|
|
1
2
|
import { IPluginEvent, IPluginEventMap } from "../../plugins/types";
|
|
2
3
|
import PlayerPlugin, { PLAYER_MODES } from "./index";
|
|
3
4
|
interface IPlayerEvent extends IPluginEvent {
|
|
@@ -15,6 +16,17 @@ interface IRotateEvent extends IPlayerEvent {
|
|
|
15
16
|
name: "rotateEvent";
|
|
16
17
|
rotateDeg: number;
|
|
17
18
|
}
|
|
19
|
+
export interface IRecordStopInfo {
|
|
20
|
+
data: Blob;
|
|
21
|
+
startTime: number;
|
|
22
|
+
endTime: number;
|
|
23
|
+
duration: number;
|
|
24
|
+
puOptions: IPuOption;
|
|
25
|
+
fileName: string;
|
|
26
|
+
cancelAutoDownload: () => {
|
|
27
|
+
download(filename?: string): void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
18
30
|
export interface IPlayerPluginEventMap extends IPluginEventMap {
|
|
19
31
|
init: IInitEvent;
|
|
20
32
|
closeWebrtc: ICloseWebrtcEvent;
|
|
@@ -22,10 +34,7 @@ export interface IPlayerPluginEventMap extends IPluginEventMap {
|
|
|
22
34
|
close: IPlayerEvent;
|
|
23
35
|
contextmenu: Event;
|
|
24
36
|
recordStart: undefined;
|
|
25
|
-
recordStop:
|
|
26
|
-
data: Blob;
|
|
27
|
-
cancelAutoDownload: () => void;
|
|
28
|
-
};
|
|
37
|
+
recordStop: IRecordStopInfo;
|
|
29
38
|
screenshot: undefined | {
|
|
30
39
|
img: Blob;
|
|
31
40
|
cancelAutoDownload: () => void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IOnMediaRecordHandle } from "src/utils/media";
|
|
1
2
|
import { IPluginEvent, IPluginEventMap, Plugin } from "./types";
|
|
2
3
|
import { IPuOption } from "src/main";
|
|
3
4
|
interface IVideoPluginEvent extends IPluginEvent {
|
|
@@ -52,7 +53,7 @@ declare class VideoPlugin extends Plugin<HTMLDivElement, IVideoPluginEventMap> {
|
|
|
52
53
|
} | undefined>;
|
|
53
54
|
private _genFileName;
|
|
54
55
|
recordStart(): void;
|
|
55
|
-
recordStop(onRecordInfo?:
|
|
56
|
+
recordStop(onRecordInfo?: IOnMediaRecordHandle): void;
|
|
56
57
|
rotate(degStep: number): void;
|
|
57
58
|
beforeDestroy(): void;
|
|
58
59
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
interface IStreamProvider {
|
|
2
2
|
captureStream(frameRate?: number): MediaStream;
|
|
3
3
|
}
|
|
4
|
+
export interface IOnMediaRecordHandle {
|
|
5
|
+
(blob: Blob, metaInfo: {
|
|
6
|
+
duration: number;
|
|
7
|
+
startTime: number;
|
|
8
|
+
endTime: number;
|
|
9
|
+
fileName: string;
|
|
10
|
+
}, cancelAutoDownload: () => {
|
|
11
|
+
download(fileName?: string): void;
|
|
12
|
+
}): boolean;
|
|
13
|
+
}
|
|
4
14
|
interface IMediaOption {
|
|
5
15
|
video?: boolean;
|
|
6
16
|
audio?: boolean;
|
|
@@ -42,7 +52,7 @@ declare const media: {
|
|
|
42
52
|
download(): void;
|
|
43
53
|
} | undefined>;
|
|
44
54
|
record: (element: IStreamProvider, stream?: MediaStream | null, fileName?: string) => [(MediaRecorder | undefined)?, (MediaStream | undefined)?, ({
|
|
45
|
-
setOnMedia(onMedia:
|
|
55
|
+
setOnMedia(onMedia: IOnMediaRecordHandle): void;
|
|
46
56
|
} | undefined)?];
|
|
47
57
|
getMediaDir: (option: IMediaOption) => number;
|
|
48
58
|
video2Canvas: (video: HTMLVideoElement, opts: IVideo2CanvasOptions) => ICanvasControl;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { IOnMediaRecordHandle } from "./media";
|
|
2
|
+
export declare const createRecord: (_mediaStream: MediaStream, fileName: string, isDownload: IOnMediaRecordHandle) => MediaRecorder;
|