@besovideo/webrtc-player 0.10.42 → 0.10.44
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/dist/{bvmedia-7ZJI3VSG.js → bvmedia-7JPROY4X.js} +15 -1
- package/dist/{chunk-26DTQELB.js → chunk-7SHCWKP3.js} +1 -1
- package/dist/main.browser.js +382 -75
- package/dist/main.es.js +369 -76
- package/dist/types/components/callEndPoint.d.ts +2 -0
- package/dist/types/components/callEndPointUtils.d.ts +2 -0
- package/dist/types/utils/bvrtcRecord.d.ts +25 -1
- package/dist/types/utils/hevcRecord.d.ts +1 -0
- package/dist/types/utils/pcmResampler.d.ts +16 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
__async,
|
|
3
3
|
init_define_processenv,
|
|
4
4
|
init_jsx_shim
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7SHCWKP3.js";
|
|
6
6
|
|
|
7
7
|
// src/lib/bvmedia/index.ts
|
|
8
8
|
init_define_processenv();
|
|
@@ -1028,7 +1028,21 @@ var BVMedia = class {
|
|
|
1028
1028
|
this.webcodecPlayer.decodeAudio(packet.data, packet.pts);
|
|
1029
1029
|
}
|
|
1030
1030
|
}
|
|
1031
|
+
// Recording subscribes independently of playback volume and onaudioData.
|
|
1032
|
+
setDecodedAudioCallback(callback) {
|
|
1033
|
+
this.onDecodedAudioCallback = callback;
|
|
1034
|
+
return Promise.resolve();
|
|
1035
|
+
}
|
|
1031
1036
|
_OnAudioData(frame) {
|
|
1037
|
+
var _a;
|
|
1038
|
+
(_a = this.onDecodedAudioCallback) == null ? void 0 : _a.call(this, {
|
|
1039
|
+
pts: frame.pts / 1e3,
|
|
1040
|
+
// decoded PCM uses milliseconds; recording uses seconds
|
|
1041
|
+
data: frame.data,
|
|
1042
|
+
channels: this.audioInfo.channels,
|
|
1043
|
+
sampleRate: this.audioInfo.sampleRate,
|
|
1044
|
+
format: this.audioInfo.encoding
|
|
1045
|
+
});
|
|
1032
1046
|
if (this.audioPlayer) {
|
|
1033
1047
|
let numberOfFrames = frame.len / this.audioInfo.channels / this.audioPlayer.getNumofSamples(this.audioInfo.encoding);
|
|
1034
1048
|
let ar = new Uint8Array(frame.data);
|
|
@@ -119,7 +119,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
119
119
|
var define_processenv_default;
|
|
120
120
|
var init_define_processenv = __esm({
|
|
121
121
|
"<define:processenv>"() {
|
|
122
|
-
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.10.
|
|
122
|
+
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.10.44", PROJECT_NAMESPACE: "bvplayer", SH_LIB_BUILD_TIME: "2026-09-10 18:05:58" };
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
|
package/dist/main.browser.js
CHANGED
|
@@ -125,7 +125,7 @@ var bvPlayerCore = (() => {
|
|
|
125
125
|
var define_processenv_default;
|
|
126
126
|
var init_define_processenv = __esm({
|
|
127
127
|
"<define:processenv>"() {
|
|
128
|
-
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.10.
|
|
128
|
+
define_processenv_default = { NODE_ENV: "production", SH_LIB_NAME: "@besovideo/webrtc-player", SH_LIB_VERSION: "0.10.44", PROJECT_NAMESPACE: "bvplayer", SH_LIB_BUILD_TIME: "2026-09-10 18:05:58" };
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
131
|
|
|
@@ -14840,7 +14840,21 @@ CustomVideoTrackGeneratorWorker();`;
|
|
|
14840
14840
|
this.webcodecPlayer.decodeAudio(packet.data, packet.pts);
|
|
14841
14841
|
}
|
|
14842
14842
|
}
|
|
14843
|
+
// Recording subscribes independently of playback volume and onaudioData.
|
|
14844
|
+
setDecodedAudioCallback(callback) {
|
|
14845
|
+
this.onDecodedAudioCallback = callback;
|
|
14846
|
+
return Promise.resolve();
|
|
14847
|
+
}
|
|
14843
14848
|
_OnAudioData(frame) {
|
|
14849
|
+
var _a;
|
|
14850
|
+
(_a = this.onDecodedAudioCallback) == null ? void 0 : _a.call(this, {
|
|
14851
|
+
pts: frame.pts / 1e3,
|
|
14852
|
+
// decoded PCM uses milliseconds; recording uses seconds
|
|
14853
|
+
data: frame.data,
|
|
14854
|
+
channels: this.audioInfo.channels,
|
|
14855
|
+
sampleRate: this.audioInfo.sampleRate,
|
|
14856
|
+
format: this.audioInfo.encoding
|
|
14857
|
+
});
|
|
14844
14858
|
if (this.audioPlayer) {
|
|
14845
14859
|
let numberOfFrames = frame.len / this.audioInfo.channels / this.audioPlayer.getNumofSamples(this.audioInfo.encoding);
|
|
14846
14860
|
let ar = new Uint8Array(frame.data);
|
|
@@ -37325,6 +37339,182 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37325
37339
|
// src/utils/bvrtcRecord.ts
|
|
37326
37340
|
init_define_processenv();
|
|
37327
37341
|
init_jsx_shim();
|
|
37342
|
+
|
|
37343
|
+
// src/utils/hevcRecord.ts
|
|
37344
|
+
init_define_processenv();
|
|
37345
|
+
init_jsx_shim();
|
|
37346
|
+
function hevcDecoderConfig(vps, sps, pps) {
|
|
37347
|
+
const rbsp = [];
|
|
37348
|
+
for (let i3 = 2; i3 < sps.length; i3++) {
|
|
37349
|
+
if (i3 >= 4 && sps[i3] === 3 && sps[i3 - 1] === 0 && sps[i3 - 2] === 0)
|
|
37350
|
+
continue;
|
|
37351
|
+
rbsp.push(sps[i3]);
|
|
37352
|
+
}
|
|
37353
|
+
let offset2 = 0;
|
|
37354
|
+
const read2 = (count) => {
|
|
37355
|
+
if (offset2 + count > rbsp.length * 8)
|
|
37356
|
+
throw new Error("Invalid HEVC SPS in BVRTC callback");
|
|
37357
|
+
let value = 0;
|
|
37358
|
+
for (let i3 = 0; i3 < count; i3++, offset2++)
|
|
37359
|
+
value = value * 2 + (rbsp[offset2 >> 3] >> 7 - (offset2 & 7) & 1);
|
|
37360
|
+
return value;
|
|
37361
|
+
};
|
|
37362
|
+
const ue = () => {
|
|
37363
|
+
let zeros = 0;
|
|
37364
|
+
while (read2(1) === 0) {
|
|
37365
|
+
if (++zeros > 31)
|
|
37366
|
+
throw new Error("Invalid HEVC SPS Exp-Golomb value");
|
|
37367
|
+
}
|
|
37368
|
+
return __pow(2, zeros) - 1 + read2(zeros);
|
|
37369
|
+
};
|
|
37370
|
+
read2(4);
|
|
37371
|
+
const subLayers = read2(3);
|
|
37372
|
+
const temporalNested = read2(1);
|
|
37373
|
+
const profileTierLevel = Uint8Array.from({ length: 12 }, () => read2(8));
|
|
37374
|
+
const subProfiles = [];
|
|
37375
|
+
const subLevels = [];
|
|
37376
|
+
for (let i3 = 0; i3 < subLayers; i3++) {
|
|
37377
|
+
subProfiles.push(read2(1));
|
|
37378
|
+
subLevels.push(read2(1));
|
|
37379
|
+
}
|
|
37380
|
+
if (subLayers)
|
|
37381
|
+
read2((8 - subLayers) * 2);
|
|
37382
|
+
for (let i3 = 0; i3 < subLayers; i3++) {
|
|
37383
|
+
if (subProfiles[i3]) {
|
|
37384
|
+
read2(32);
|
|
37385
|
+
read2(32);
|
|
37386
|
+
read2(24);
|
|
37387
|
+
}
|
|
37388
|
+
if (subLevels[i3])
|
|
37389
|
+
read2(8);
|
|
37390
|
+
}
|
|
37391
|
+
ue();
|
|
37392
|
+
const chromaFormat = ue();
|
|
37393
|
+
if (chromaFormat === 3)
|
|
37394
|
+
read2(1);
|
|
37395
|
+
ue();
|
|
37396
|
+
ue();
|
|
37397
|
+
if (read2(1)) {
|
|
37398
|
+
ue();
|
|
37399
|
+
ue();
|
|
37400
|
+
ue();
|
|
37401
|
+
ue();
|
|
37402
|
+
}
|
|
37403
|
+
const bitDepthLuma = ue();
|
|
37404
|
+
const bitDepthChroma = ue();
|
|
37405
|
+
if (chromaFormat > 3 || bitDepthLuma > 7 || bitDepthChroma > 7)
|
|
37406
|
+
throw new Error("Invalid HEVC SPS format");
|
|
37407
|
+
const sets2 = [vps, sps, pps];
|
|
37408
|
+
if (sets2.some((set2) => set2.length < 2 || set2.length > 65535))
|
|
37409
|
+
throw new Error("Invalid HEVC parameter set length");
|
|
37410
|
+
const result = new Uint8Array(23 + sets2.reduce((size, set2) => size + 5 + set2.length, 0));
|
|
37411
|
+
result[0] = 1;
|
|
37412
|
+
result.set(profileTierLevel, 1);
|
|
37413
|
+
result.set([
|
|
37414
|
+
240,
|
|
37415
|
+
0,
|
|
37416
|
+
252,
|
|
37417
|
+
252 | chromaFormat,
|
|
37418
|
+
248 | bitDepthLuma,
|
|
37419
|
+
248 | bitDepthChroma,
|
|
37420
|
+
0,
|
|
37421
|
+
0,
|
|
37422
|
+
subLayers + 1 << 3 | temporalNested << 2 | 3,
|
|
37423
|
+
3
|
|
37424
|
+
], 13);
|
|
37425
|
+
let position = 23;
|
|
37426
|
+
sets2.forEach((set2, index) => {
|
|
37427
|
+
result[position++] = 128 | 32 + index;
|
|
37428
|
+
new DataView(result.buffer).setUint16(position, 1);
|
|
37429
|
+
position += 2;
|
|
37430
|
+
new DataView(result.buffer).setUint16(position, set2.length);
|
|
37431
|
+
position += 2;
|
|
37432
|
+
result.set(set2, position);
|
|
37433
|
+
position += set2.length;
|
|
37434
|
+
});
|
|
37435
|
+
return result;
|
|
37436
|
+
}
|
|
37437
|
+
|
|
37438
|
+
// src/utils/pcmResampler.ts
|
|
37439
|
+
init_define_processenv();
|
|
37440
|
+
init_jsx_shim();
|
|
37441
|
+
var PcmResampler = class {
|
|
37442
|
+
constructor(inputRate, outputRate, channels) {
|
|
37443
|
+
this.inputRate = inputRate;
|
|
37444
|
+
this.outputRate = outputRate;
|
|
37445
|
+
this.channels = channels;
|
|
37446
|
+
this.radius = 32;
|
|
37447
|
+
this.buffer = new Int16Array(0);
|
|
37448
|
+
this.bufferStart = 0;
|
|
37449
|
+
this.inputFrames = 0;
|
|
37450
|
+
this.outputFrames = 0;
|
|
37451
|
+
this.phases = [];
|
|
37452
|
+
if (!Number.isInteger(inputRate) || inputRate <= 0 || !Number.isInteger(outputRate) || outputRate <= 0 || !Number.isInteger(channels) || channels <= 0)
|
|
37453
|
+
throw new Error("Invalid PCM resampler format");
|
|
37454
|
+
const gcd = (a, b2) => b2 ? gcd(b2, a % b2) : a;
|
|
37455
|
+
const count = outputRate / gcd(inputRate, outputRate);
|
|
37456
|
+
const cutoff = Math.min(1, outputRate / inputRate);
|
|
37457
|
+
for (let phase = 0; phase < count; phase++) {
|
|
37458
|
+
const fraction = phase * inputRate % outputRate / outputRate;
|
|
37459
|
+
const weights = [];
|
|
37460
|
+
for (let tap = -this.radius + 1; tap <= this.radius; tap++) {
|
|
37461
|
+
const distance = fraction - tap;
|
|
37462
|
+
const x2 = Math.PI * distance * cutoff;
|
|
37463
|
+
const sinc = Math.abs(x2) < 1e-12 ? 1 : Math.sin(x2) / x2;
|
|
37464
|
+
const window2 = Math.abs(distance) >= this.radius ? 0 : 0.42 + 0.5 * Math.cos(Math.PI * distance / this.radius) + 0.08 * Math.cos(2 * Math.PI * distance / this.radius);
|
|
37465
|
+
weights.push(cutoff * sinc * window2);
|
|
37466
|
+
}
|
|
37467
|
+
const sum = weights.reduce((a, b2) => a + b2, 0);
|
|
37468
|
+
this.phases.push(weights.map((weight) => weight / sum));
|
|
37469
|
+
}
|
|
37470
|
+
}
|
|
37471
|
+
get pendingSeconds() {
|
|
37472
|
+
return this.inputFrames / this.inputRate - this.outputFrames / this.outputRate;
|
|
37473
|
+
}
|
|
37474
|
+
process(input) {
|
|
37475
|
+
if (input.length % this.channels)
|
|
37476
|
+
throw new Error("Incomplete interleaved PCM frame");
|
|
37477
|
+
if (this.inputRate === this.outputRate)
|
|
37478
|
+
return input;
|
|
37479
|
+
const merged = new Int16Array(this.buffer.length + input.length);
|
|
37480
|
+
merged.set(this.buffer);
|
|
37481
|
+
merged.set(input, this.buffer.length);
|
|
37482
|
+
this.buffer = merged;
|
|
37483
|
+
this.inputFrames += input.length / this.channels;
|
|
37484
|
+
return this.render(false);
|
|
37485
|
+
}
|
|
37486
|
+
flush() {
|
|
37487
|
+
return this.inputRate === this.outputRate ? new Int16Array(0) : this.render(true);
|
|
37488
|
+
}
|
|
37489
|
+
render(final) {
|
|
37490
|
+
const limit = Math.round(this.inputFrames * this.outputRate / this.inputRate);
|
|
37491
|
+
const result = [];
|
|
37492
|
+
while (this.outputFrames < limit) {
|
|
37493
|
+
const center = Math.floor(this.outputFrames * this.inputRate / this.outputRate);
|
|
37494
|
+
if (!final && center + this.radius >= this.inputFrames)
|
|
37495
|
+
break;
|
|
37496
|
+
const weights = this.phases[this.outputFrames % this.phases.length];
|
|
37497
|
+
for (let channel = 0; channel < this.channels; channel++) {
|
|
37498
|
+
let value = 0;
|
|
37499
|
+
for (let i3 = 0; i3 < weights.length; i3++) {
|
|
37500
|
+
const frame = center - this.radius + 1 + i3;
|
|
37501
|
+
if (frame >= 0 && frame < this.inputFrames)
|
|
37502
|
+
value += this.buffer[(frame - this.bufferStart) * this.channels + channel] * weights[i3];
|
|
37503
|
+
}
|
|
37504
|
+
result.push(Math.max(-32768, Math.min(32767, Math.round(value))));
|
|
37505
|
+
}
|
|
37506
|
+
this.outputFrames++;
|
|
37507
|
+
}
|
|
37508
|
+
const keepFrom = Math.max(0, Math.floor(this.outputFrames * this.inputRate / this.outputRate) - this.radius);
|
|
37509
|
+
if (keepFrom > this.bufferStart) {
|
|
37510
|
+
this.buffer = this.buffer.slice((keepFrom - this.bufferStart) * this.channels);
|
|
37511
|
+
this.bufferStart = keepFrom;
|
|
37512
|
+
}
|
|
37513
|
+
return Int16Array.from(result);
|
|
37514
|
+
}
|
|
37515
|
+
};
|
|
37516
|
+
|
|
37517
|
+
// src/utils/bvrtcRecord.ts
|
|
37328
37518
|
var startCodeLength = (data, offset2) => data[offset2] === 0 && data[offset2 + 1] === 0 && (data[offset2 + 2] === 1 ? 3 : data[offset2 + 2] === 0 && data[offset2 + 3] === 1 ? 4 : 0);
|
|
37329
37519
|
function splitAnnexB(data) {
|
|
37330
37520
|
const units = [];
|
|
@@ -37385,32 +37575,21 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37385
37575
|
return value & 128 ? pcm : -pcm;
|
|
37386
37576
|
};
|
|
37387
37577
|
var AAC_SAMPLE_RATE = 48e3;
|
|
37388
|
-
function resampleS16(input, channels, inputRate) {
|
|
37389
|
-
if (inputRate === AAC_SAMPLE_RATE)
|
|
37390
|
-
return input;
|
|
37391
|
-
const inputFrames = Math.floor(input.length / channels);
|
|
37392
|
-
if (!inputFrames)
|
|
37393
|
-
return input;
|
|
37394
|
-
const outputFrames = Math.round(inputFrames * AAC_SAMPLE_RATE / inputRate);
|
|
37395
|
-
const output2 = new Int16Array(outputFrames * channels);
|
|
37396
|
-
for (let frame = 0; frame < outputFrames; frame++) {
|
|
37397
|
-
const sourcePosition = frame * inputRate / AAC_SAMPLE_RATE;
|
|
37398
|
-
const lower = Math.floor(sourcePosition);
|
|
37399
|
-
const upper = Math.min(lower + 1, inputFrames - 1);
|
|
37400
|
-
const mix = sourcePosition - lower;
|
|
37401
|
-
for (let channel = 0; channel < channels; channel++) {
|
|
37402
|
-
output2[frame * channels + channel] = input[lower * channels + channel] * (1 - mix) + input[upper * channels + channel] * mix;
|
|
37403
|
-
}
|
|
37404
|
-
}
|
|
37405
|
-
return output2;
|
|
37406
|
-
}
|
|
37407
37578
|
var BvrtcRecorder = class {
|
|
37408
37579
|
constructor(player, fileName) {
|
|
37409
37580
|
this.player = player;
|
|
37410
37581
|
this.fileName = fileName;
|
|
37411
37582
|
this.startedAt = 0;
|
|
37583
|
+
this.hevc = false;
|
|
37584
|
+
this.videoStarted = false;
|
|
37412
37585
|
this.pendingAudio = [];
|
|
37413
37586
|
this.transcodeAlaw = false;
|
|
37587
|
+
this.transcodePcm = false;
|
|
37588
|
+
this.pendingPcmAudio = [];
|
|
37589
|
+
this.pcmChannels = 1;
|
|
37590
|
+
this.recordingClockStart = 0;
|
|
37591
|
+
this.videoClockOffset = 0;
|
|
37592
|
+
this.pcmClockOffset = 0;
|
|
37414
37593
|
this.stopped = false;
|
|
37415
37594
|
this.onVideo = (packet) => {
|
|
37416
37595
|
if (this.stopped)
|
|
@@ -37418,6 +37597,45 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37418
37597
|
const units = splitAnnexB(new Uint8Array(packet.data));
|
|
37419
37598
|
if (!units.length)
|
|
37420
37599
|
return;
|
|
37600
|
+
const hasPicture = units.some((unit) => this.hevc ? (unit[0] >> 1 & 63) < 32 : (unit[0] & 31) >= 1 && (unit[0] & 31) <= 5);
|
|
37601
|
+
if (this.transcodePcm && this.firstPts === void 0 && hasPicture) {
|
|
37602
|
+
this.videoClockOffset = (performance.now() - this.recordingClockStart) * 1e3;
|
|
37603
|
+
this.normalizePts(packet.pts);
|
|
37604
|
+
}
|
|
37605
|
+
if (this.hevc) {
|
|
37606
|
+
for (const unit of units) {
|
|
37607
|
+
const type = unit[0] >> 1 & 63;
|
|
37608
|
+
if (type === 32)
|
|
37609
|
+
this.vps = unit;
|
|
37610
|
+
if (type === 33)
|
|
37611
|
+
this.sps = unit;
|
|
37612
|
+
if (type === 34)
|
|
37613
|
+
this.pps = unit;
|
|
37614
|
+
}
|
|
37615
|
+
const sampleUnits = units.filter((unit) => {
|
|
37616
|
+
const type = unit[0] >> 1 & 63;
|
|
37617
|
+
return type < 32 || type > 34;
|
|
37618
|
+
});
|
|
37619
|
+
if (!sampleUnits.some((unit) => (unit[0] >> 1 & 63) < 32))
|
|
37620
|
+
return;
|
|
37621
|
+
const key2 = sampleUnits.some((unit) => {
|
|
37622
|
+
const type = unit[0] >> 1 & 63;
|
|
37623
|
+
return type >= 16 && type <= 21;
|
|
37624
|
+
});
|
|
37625
|
+
if (!this.videoStarted && !key2)
|
|
37626
|
+
return;
|
|
37627
|
+
this.createMuxer();
|
|
37628
|
+
if (!this.muxer)
|
|
37629
|
+
return;
|
|
37630
|
+
this.videoStarted = true;
|
|
37631
|
+
const pts2 = this.normalizePts(packet.pts);
|
|
37632
|
+
const duration2 = this.lastVideoPts === void 0 ? 0 : Math.max(0, pts2 - this.lastVideoPts);
|
|
37633
|
+
this.lastVideoPts = pts2;
|
|
37634
|
+
this.muxer.addVideoChunkRaw(avcSample(sampleUnits), key2 ? "key" : "delta", pts2, duration2, {
|
|
37635
|
+
decoderConfig: { codec: "hvc1", description: hevcDecoderConfig(this.vps, this.sps, this.pps) }
|
|
37636
|
+
});
|
|
37637
|
+
return;
|
|
37638
|
+
}
|
|
37421
37639
|
for (const unit of units) {
|
|
37422
37640
|
const type = unit[0] & 31;
|
|
37423
37641
|
if (type === 7)
|
|
@@ -37425,13 +37643,19 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37425
37643
|
if (type === 8)
|
|
37426
37644
|
this.pps = unit;
|
|
37427
37645
|
}
|
|
37646
|
+
if (!units.some((unit) => (unit[0] & 31) >= 1 && (unit[0] & 31) <= 5))
|
|
37647
|
+
return;
|
|
37648
|
+
const key = units.some((unit) => (unit[0] & 31) === 5);
|
|
37649
|
+
if (!this.videoStarted && !key)
|
|
37650
|
+
return;
|
|
37428
37651
|
this.createMuxer();
|
|
37429
37652
|
if (!this.muxer)
|
|
37430
37653
|
return;
|
|
37654
|
+
this.videoStarted = true;
|
|
37431
37655
|
const pts = this.normalizePts(packet.pts);
|
|
37432
37656
|
const duration = this.lastVideoPts === void 0 ? 0 : Math.max(0, pts - this.lastVideoPts);
|
|
37433
37657
|
this.lastVideoPts = pts;
|
|
37434
|
-
this.muxer.addVideoChunkRaw(avcSample(units),
|
|
37658
|
+
this.muxer.addVideoChunkRaw(avcSample(units), key ? "key" : "delta", pts, duration, {
|
|
37435
37659
|
decoderConfig: { codec: "avc1", description: avcDecoderConfig(this.sps, this.pps) }
|
|
37436
37660
|
});
|
|
37437
37661
|
};
|
|
@@ -37447,77 +37671,115 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37447
37671
|
}
|
|
37448
37672
|
this.addAudio(packet);
|
|
37449
37673
|
};
|
|
37674
|
+
this.onPcmAudio = (packet) => {
|
|
37675
|
+
if (this.stopped)
|
|
37676
|
+
return;
|
|
37677
|
+
if (this.pcmClockStart === void 0) {
|
|
37678
|
+
this.pcmClockStart = packet.pts;
|
|
37679
|
+
this.pcmClockOffset = (performance.now() - this.recordingClockStart) * 1e3;
|
|
37680
|
+
}
|
|
37681
|
+
if (!this.muxer) {
|
|
37682
|
+
this.pendingPcmAudio.push(packet);
|
|
37683
|
+
return;
|
|
37684
|
+
}
|
|
37685
|
+
this.addPcmAudio(packet);
|
|
37686
|
+
};
|
|
37450
37687
|
}
|
|
37451
37688
|
start() {
|
|
37452
37689
|
return __async(this, null, function* () {
|
|
37453
|
-
var _a, _b;
|
|
37690
|
+
var _a, _b, _c;
|
|
37454
37691
|
const videoCodec = (_a = this.player.getVideoInfo().codec) == null ? void 0 : _a.toLowerCase();
|
|
37455
37692
|
const audioCodec = (_b = this.player.getAudioInfo().codec) == null ? void 0 : _b.toLowerCase();
|
|
37456
|
-
|
|
37693
|
+
this.hevc = /^(hevc|h265|h\.265|hvc1|hev1)$/.test(videoCodec || "");
|
|
37694
|
+
if (videoCodec && videoCodec !== "none" && !/(h264|avc)/.test(videoCodec) && !this.hevc)
|
|
37457
37695
|
throw new Error(`BVRTC passthrough recording does not support video codec: ${videoCodec}`);
|
|
37458
|
-
|
|
37696
|
+
this.transcodePcm = /^(adpcm_)?g726(le)?$/.test(audioCodec || "");
|
|
37697
|
+
if (audioCodec && audioCodec !== "aac" && audioCodec !== "pcm_alaw" && !this.transcodePcm)
|
|
37459
37698
|
throw new Error(`BVRTC passthrough recording does not support audio codec: ${audioCodec}`);
|
|
37460
37699
|
this.transcodeAlaw = audioCodec === "pcm_alaw";
|
|
37461
|
-
if (this.transcodeAlaw
|
|
37462
|
-
|
|
37700
|
+
if (this.transcodeAlaw || this.transcodePcm) {
|
|
37701
|
+
if (!(yield this.createAudioEncoder())) {
|
|
37702
|
+
this.transcodeAlaw = false;
|
|
37703
|
+
this.transcodePcm = false;
|
|
37704
|
+
}
|
|
37705
|
+
}
|
|
37706
|
+
if (this.transcodePcm && !this.player.setDecodedAudioCallback) {
|
|
37707
|
+
(_c = this.audioEncoder) == null ? void 0 : _c.close();
|
|
37708
|
+
throw new Error("BVRTC G.726 recording requires decoded PCM audio callbacks");
|
|
37463
37709
|
}
|
|
37464
37710
|
this.startedAt = Date.now();
|
|
37711
|
+
this.recordingClockStart = performance.now();
|
|
37465
37712
|
if (videoCodec === "none")
|
|
37466
37713
|
this.createMuxer();
|
|
37467
37714
|
yield Promise.all([
|
|
37468
37715
|
this.player.setVideoCallback(this.onVideo),
|
|
37469
|
-
this.player.setAudioCallback(this.onAudio)
|
|
37716
|
+
this.transcodePcm ? this.player.setDecodedAudioCallback(this.onPcmAudio) : this.player.setAudioCallback(this.onAudio)
|
|
37470
37717
|
]);
|
|
37471
37718
|
});
|
|
37472
37719
|
}
|
|
37473
37720
|
createMuxer() {
|
|
37474
37721
|
var _a, _b;
|
|
37475
37722
|
const hasVideo = ((_a = this.player.getVideoInfo().codec) == null ? void 0 : _a.toLowerCase()) !== "none";
|
|
37476
|
-
if (this.muxer || hasVideo && (!this.sps || !this.pps))
|
|
37723
|
+
if (this.muxer || hasVideo && (!this.sps || !this.pps || this.hevc && !this.vps))
|
|
37477
37724
|
return;
|
|
37478
37725
|
const video = this.player.getVideoInfo();
|
|
37479
37726
|
const audio = this.player.getAudioInfo();
|
|
37480
37727
|
this.target = new ArrayBufferTarget2();
|
|
37481
37728
|
this.muxer = new Muxer2({
|
|
37482
37729
|
target: this.target,
|
|
37483
|
-
video: hasVideo ? { codec: "avc", width: video.width || 1, height: video.height || 1 } : void 0,
|
|
37484
|
-
audio: ((_b = audio.codec) == null ? void 0 : _b.toLowerCase()) === "aac" || this.transcodeAlaw ? { codec: "aac", numberOfChannels: audio.channels || 1, sampleRate: this.transcodeAlaw ? AAC_SAMPLE_RATE : audio.sampleRate || 8e3 } : void 0,
|
|
37730
|
+
video: hasVideo ? { codec: this.hevc ? "hevc" : "avc", width: video.width || 1, height: video.height || 1 } : void 0,
|
|
37731
|
+
audio: ((_b = audio.codec) == null ? void 0 : _b.toLowerCase()) === "aac" || this.transcodeAlaw || this.transcodePcm ? { codec: "aac", numberOfChannels: audio.channels || 1, sampleRate: this.transcodeAlaw || this.transcodePcm ? AAC_SAMPLE_RATE : audio.sampleRate || 8e3 } : void 0,
|
|
37485
37732
|
fastStart: "in-memory",
|
|
37486
37733
|
firstTimestampBehavior: "cross-track-offset"
|
|
37487
37734
|
});
|
|
37488
|
-
if (this.transcodeAlaw)
|
|
37489
|
-
this.createAlawEncoder();
|
|
37490
37735
|
for (const packet of this.pendingAudio.splice(0))
|
|
37491
37736
|
this.addAudio(packet);
|
|
37737
|
+
for (const packet of this.pendingPcmAudio.splice(0))
|
|
37738
|
+
this.addPcmAudio(packet);
|
|
37492
37739
|
}
|
|
37493
|
-
|
|
37494
|
-
|
|
37495
|
-
|
|
37496
|
-
|
|
37497
|
-
|
|
37498
|
-
|
|
37499
|
-
|
|
37500
|
-
|
|
37501
|
-
|
|
37502
|
-
|
|
37503
|
-
|
|
37504
|
-
|
|
37505
|
-
|
|
37506
|
-
|
|
37507
|
-
|
|
37508
|
-
|
|
37509
|
-
|
|
37510
|
-
|
|
37511
|
-
|
|
37740
|
+
createAudioEncoder() {
|
|
37741
|
+
return __async(this, null, function* () {
|
|
37742
|
+
var _a, _b;
|
|
37743
|
+
const audio = this.player.getAudioInfo();
|
|
37744
|
+
const Encoder3 = globalThis.AudioEncoder;
|
|
37745
|
+
if (!Encoder3 || !globalThis.AudioData)
|
|
37746
|
+
return false;
|
|
37747
|
+
const config = {
|
|
37748
|
+
codec: "mp4a.40.2",
|
|
37749
|
+
sampleRate: AAC_SAMPLE_RATE,
|
|
37750
|
+
numberOfChannels: audio.channels || 1,
|
|
37751
|
+
// Chromium's AAC WebCodecs implementation currently accepts 96 kbps+
|
|
37752
|
+
// only (even for 8 kHz G.711 input).
|
|
37753
|
+
bitrate: 96e3
|
|
37754
|
+
};
|
|
37755
|
+
try {
|
|
37756
|
+
if (!(yield Encoder3.isConfigSupported(config)).supported)
|
|
37757
|
+
return false;
|
|
37758
|
+
this.audioEncoder = new Encoder3({
|
|
37759
|
+
output: (chunk, meta) => {
|
|
37760
|
+
var _a2;
|
|
37761
|
+
return (_a2 = this.muxer) == null ? void 0 : _a2.addAudioChunk(chunk, meta);
|
|
37762
|
+
},
|
|
37763
|
+
error: (error2) => console.error("BVRTC AAC encoder error", error2)
|
|
37764
|
+
});
|
|
37765
|
+
this.audioEncoder.configure(config);
|
|
37766
|
+
return true;
|
|
37767
|
+
} catch (e) {
|
|
37768
|
+
if (((_a = this.audioEncoder) == null ? void 0 : _a.state) !== "closed")
|
|
37769
|
+
(_b = this.audioEncoder) == null ? void 0 : _b.close();
|
|
37770
|
+
this.audioEncoder = void 0;
|
|
37771
|
+
return false;
|
|
37772
|
+
}
|
|
37512
37773
|
});
|
|
37513
37774
|
}
|
|
37514
37775
|
normalizePts(pts) {
|
|
37515
37776
|
var _a;
|
|
37777
|
+
pts = pts >= 1e11 ? pts / 1e3 : pts;
|
|
37516
37778
|
(_a = this.firstPts) != null ? _a : this.firstPts = pts;
|
|
37517
|
-
return Math.max(0, (pts - this.firstPts) *
|
|
37779
|
+
return Math.max(0, Math.round((pts - this.firstPts) * 1e6 + this.videoClockOffset));
|
|
37518
37780
|
}
|
|
37519
37781
|
addAudio(packet) {
|
|
37520
|
-
var _a
|
|
37782
|
+
var _a;
|
|
37521
37783
|
if (!this.muxer)
|
|
37522
37784
|
return;
|
|
37523
37785
|
if (this.transcodeAlaw) {
|
|
@@ -37526,37 +37788,69 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
37526
37788
|
const decoded = new Int16Array(encoded.byteLength);
|
|
37527
37789
|
for (let i3 = 0; i3 < encoded.byteLength; i3++)
|
|
37528
37790
|
decoded[i3] = alawToS16(encoded[i3]);
|
|
37529
|
-
|
|
37530
|
-
const pcm = resampleS16(decoded, channels, audio.sampleRate || 8e3);
|
|
37531
|
-
const AudioDataCtor = globalThis.AudioData;
|
|
37532
|
-
const frame = new AudioDataCtor({ format: "s16", sampleRate: AAC_SAMPLE_RATE, numberOfFrames: pcm.length / channels, numberOfChannels: channels, timestamp: this.normalizePts(packet.pts), data: pcm });
|
|
37533
|
-
(_a = this.audioEncoder) == null ? void 0 : _a.encode(frame);
|
|
37534
|
-
frame.close();
|
|
37791
|
+
this.encodePcm(decoded, audio.channels || 1, audio.sampleRate || 8e3, packet.pts);
|
|
37535
37792
|
return;
|
|
37536
37793
|
}
|
|
37537
|
-
if (((
|
|
37794
|
+
if (((_a = this.player.getAudioInfo().codec) == null ? void 0 : _a.toLowerCase()) !== "aac")
|
|
37538
37795
|
return;
|
|
37539
|
-
const
|
|
37540
|
-
const
|
|
37796
|
+
const duration = 1024 * 1e6 / (this.player.getAudioInfo().sampleRate || 8e3);
|
|
37797
|
+
const sourcePts = this.normalizePts(packet.pts);
|
|
37798
|
+
const pts = this.lastAudioPts === void 0 ? sourcePts : Math.max(sourcePts, this.lastAudioPts + duration);
|
|
37541
37799
|
this.lastAudioPts = pts;
|
|
37542
37800
|
this.muxer.addAudioChunkRaw(stripAdts(new Uint8Array(packet.data)), "key", pts, duration);
|
|
37543
37801
|
}
|
|
37802
|
+
encodePcm(decoded, channels, sampleRate, sourcePts, normalizedPts = this.normalizePts(sourcePts)) {
|
|
37803
|
+
var _a;
|
|
37804
|
+
(_a = this.pcmResampler) != null ? _a : this.pcmResampler = new PcmResampler(sampleRate, AAC_SAMPLE_RATE, channels);
|
|
37805
|
+
this.pcmChannels = channels;
|
|
37806
|
+
const pendingSeconds = this.pcmResampler.pendingSeconds;
|
|
37807
|
+
const pcm = this.pcmResampler.process(decoded);
|
|
37808
|
+
this.writePcm(pcm, channels, normalizedPts - pendingSeconds * 1e6);
|
|
37809
|
+
}
|
|
37810
|
+
writePcm(pcm, channels, normalizedPts) {
|
|
37811
|
+
var _a;
|
|
37812
|
+
const numberOfFrames = pcm.length / channels;
|
|
37813
|
+
if (!numberOfFrames)
|
|
37814
|
+
return;
|
|
37815
|
+
const timestamp = Math.max(normalizedPts, (_a = this.nextPcmPts) != null ? _a : 0);
|
|
37816
|
+
this.nextPcmPts = timestamp + numberOfFrames * 1e6 / AAC_SAMPLE_RATE;
|
|
37817
|
+
const AudioDataCtor = globalThis.AudioData;
|
|
37818
|
+
const frame = new AudioDataCtor({ format: "s16", sampleRate: AAC_SAMPLE_RATE, numberOfFrames, numberOfChannels: channels, timestamp: Math.round(timestamp), data: pcm });
|
|
37819
|
+
try {
|
|
37820
|
+
this.audioEncoder.encode(frame);
|
|
37821
|
+
} finally {
|
|
37822
|
+
frame.close();
|
|
37823
|
+
}
|
|
37824
|
+
}
|
|
37825
|
+
addPcmAudio(packet) {
|
|
37826
|
+
if (packet.format !== "s16")
|
|
37827
|
+
throw new Error(`Unsupported BVRTC decoded PCM format: ${packet.format}`);
|
|
37828
|
+
const timestamp = (packet.pts - this.pcmClockStart) * 1e6 + this.pcmClockOffset;
|
|
37829
|
+
this.encodePcm(new Int16Array(packet.data), packet.channels, packet.sampleRate, packet.pts, timestamp);
|
|
37830
|
+
}
|
|
37544
37831
|
stop(onRecordInfo) {
|
|
37545
37832
|
return __async(this, null, function* () {
|
|
37546
|
-
var _a, _b, _c;
|
|
37833
|
+
var _a, _b, _c, _d, _e;
|
|
37547
37834
|
if (this.stopped)
|
|
37548
37835
|
return;
|
|
37549
37836
|
this.stopped = true;
|
|
37550
37837
|
const disableCallbacks = Promise.allSettled([
|
|
37551
37838
|
this.player.setVideoCallback(null),
|
|
37552
|
-
this.player.setAudioCallback(null)
|
|
37839
|
+
this.transcodePcm ? this.player.setDecodedAudioCallback(null) : this.player.setAudioCallback(null)
|
|
37553
37840
|
]);
|
|
37554
37841
|
const endTime = Date.now();
|
|
37555
|
-
|
|
37842
|
+
this.pendingAudio = [];
|
|
37843
|
+
this.pendingPcmAudio = [];
|
|
37844
|
+
if (!this.muxer || !this.target) {
|
|
37845
|
+
(_a = this.audioEncoder) == null ? void 0 : _a.close();
|
|
37846
|
+
yield disableCallbacks;
|
|
37556
37847
|
return;
|
|
37557
|
-
|
|
37558
|
-
(
|
|
37559
|
-
|
|
37848
|
+
}
|
|
37849
|
+
if (this.pcmResampler)
|
|
37850
|
+
this.writePcm(this.pcmResampler.flush(), this.pcmChannels, (_b = this.nextPcmPts) != null ? _b : 0);
|
|
37851
|
+
yield (_c = this.audioEncoder) == null ? void 0 : _c.flush();
|
|
37852
|
+
(_d = this.audioEncoder) == null ? void 0 : _d.close();
|
|
37853
|
+
(_e = this.muxer) == null ? void 0 : _e.finalize();
|
|
37560
37854
|
const blob = new Blob([this.target.buffer], { type: "video/mp4" });
|
|
37561
37855
|
const suffix = "mp4";
|
|
37562
37856
|
const download2 = (name) => file_default.downLoadBlob(blob, name || this.fileName, suffix);
|
|
@@ -38656,7 +38950,8 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
38656
38950
|
processHandle.reg(() => __async(this, null, function* () {
|
|
38657
38951
|
yield callApis.avCall(
|
|
38658
38952
|
__spreadProps(__spreadValues({}, callInfo), {
|
|
38659
|
-
|
|
38953
|
+
// 接通前尚未返回远端 ID,取消呼叫时保留原始设备目标。
|
|
38954
|
+
id: remoteUserId || callInfo.id,
|
|
38660
38955
|
status: 6 /* END */
|
|
38661
38956
|
}),
|
|
38662
38957
|
token
|
|
@@ -39090,7 +39385,7 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
39090
39385
|
return {
|
|
39091
39386
|
open(openParams, sinks) {
|
|
39092
39387
|
return __async(this, null, function* () {
|
|
39093
|
-
var _a2, _b, _c, _d, _e;
|
|
39388
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
39094
39389
|
const rc = {
|
|
39095
39390
|
code: "SUCCESS"
|
|
39096
39391
|
};
|
|
@@ -39106,11 +39401,18 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
39106
39401
|
const mediaOpenError = t("huo-qu-ben-di-mei-ti-shi-bai");
|
|
39107
39402
|
SetCode(rc, "GET_MEDIA_ERROR", mediaOpenError);
|
|
39108
39403
|
const hasVideo = !!(openParams.beCall && openParams.beCall.callData.videoCall) || !!((_a2 = openParams.call) == null ? void 0 : _a2.videoCall) || ((_c = (_b = openParams.call) == null ? void 0 : _b.displayMedia) == null ? void 0 : _c.video);
|
|
39109
|
-
let mediaStream = null;
|
|
39404
|
+
let mediaStream = ((_d = openParams.call) == null ? void 0 : _d.mediaStream) || null;
|
|
39405
|
+
let mediaInactiveHandler;
|
|
39110
39406
|
try {
|
|
39111
|
-
if (
|
|
39407
|
+
if (mediaStream) {
|
|
39408
|
+
mediaInactiveHandler = () => {
|
|
39409
|
+
var _a3, _b2;
|
|
39410
|
+
(_b2 = (_a3 = openParams.call) == null ? void 0 : _a3.onMediaInactive) == null ? void 0 : _b2.call(_a3);
|
|
39411
|
+
};
|
|
39412
|
+
mediaStream.addEventListener("inactive", mediaInactiveHandler);
|
|
39413
|
+
} else if ((_e = openParams.call) == null ? void 0 : _e.displayMedia) {
|
|
39112
39414
|
mediaStream = yield navigator.mediaDevices.getDisplayMedia({
|
|
39113
|
-
video: (
|
|
39415
|
+
video: (_f = openParams.call) == null ? void 0 : _f.displayMedia.video,
|
|
39114
39416
|
audio: !!openParams.call.displayMedia.audio
|
|
39115
39417
|
});
|
|
39116
39418
|
mediaStream.addEventListener("inactive", () => {
|
|
@@ -39189,6 +39491,9 @@ ${event.candidate ? event.candidate.candidate : "(null)"}`
|
|
|
39189
39491
|
}
|
|
39190
39492
|
releaseHandle.regRelease(() => __async(this, null, function* () {
|
|
39191
39493
|
var _a3;
|
|
39494
|
+
if (mediaInactiveHandler && mediaStream) {
|
|
39495
|
+
mediaStream.removeEventListener("inactive", mediaInactiveHandler);
|
|
39496
|
+
}
|
|
39192
39497
|
if ((_a3 = openParams.call) == null ? void 0 : _a3.displayMedia) {
|
|
39193
39498
|
delete openParams.call.displayMedia.onInactive;
|
|
39194
39499
|
}
|
|
@@ -39274,7 +39579,7 @@ a=fmtp:${pt} x-google-start-bitrate=${bitrate}`
|
|
|
39274
39579
|
);
|
|
39275
39580
|
const { promise: waitPCConnected, resolve: resolvePCConnected } = Promise.withResolvers();
|
|
39276
39581
|
const onPcStateChange = () => {
|
|
39277
|
-
var _a3, _b2, _c2, _d2, _e2,
|
|
39582
|
+
var _a3, _b2, _c2, _d2, _e2, _f2;
|
|
39278
39583
|
if (pc.connectionState === "connected") {
|
|
39279
39584
|
if (pushResult.code == "WAIT_PEER_CONNECTED_ERROR") {
|
|
39280
39585
|
resolvePCConnected();
|
|
@@ -39290,7 +39595,7 @@ a=fmtp:${pt} x-google-start-bitrate=${bitrate}`
|
|
|
39290
39595
|
if (pc.connectionState === "failed") {
|
|
39291
39596
|
if ((_d2 = openParams.events) == null ? void 0 : _d2.onClose) {
|
|
39292
39597
|
((_e2 = openParams.events) == null ? void 0 : _e2.onClose) && openParams.events.onClose();
|
|
39293
|
-
(
|
|
39598
|
+
(_f2 = openParams.events) == null ? true : delete _f2.onClose;
|
|
39294
39599
|
}
|
|
39295
39600
|
if (pushResult.close) {
|
|
39296
39601
|
pushResult.close();
|
|
@@ -40432,6 +40737,8 @@ a=fmtp:${pt} x-google-start-bitrate=${bitrate}`
|
|
|
40432
40737
|
call: {
|
|
40433
40738
|
videoCall: !!params.video,
|
|
40434
40739
|
name: "",
|
|
40740
|
+
mediaStream: params.mediaStream,
|
|
40741
|
+
onMediaInactive: params.onMediaInactive,
|
|
40435
40742
|
displayMedia: params.displayMedia
|
|
40436
40743
|
},
|
|
40437
40744
|
events: {
|