im-rtc-call-engine 1.0.0
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/LICENSE +21 -0
- package/dist/bytes.d.ts +11 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/bytes.js +20 -0
- package/dist/bytes.js.map +1 -0
- package/dist/callOptions.d.ts +27 -0
- package/dist/callOptions.d.ts.map +1 -0
- package/dist/callOptions.js +19 -0
- package/dist/callOptions.js.map +1 -0
- package/dist/deviceId.d.ts +10 -0
- package/dist/deviceId.d.ts.map +1 -0
- package/dist/deviceId.js +55 -0
- package/dist/deviceId.js.map +1 -0
- package/dist/engine.d.ts +302 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +489 -0
- package/dist/engine.js.map +1 -0
- package/dist/engineBus.d.ts +16 -0
- package/dist/engineBus.d.ts.map +1 -0
- package/dist/engineBus.js +89 -0
- package/dist/engineBus.js.map +1 -0
- package/dist/engineWiring.d.ts +40 -0
- package/dist/engineWiring.d.ts.map +1 -0
- package/dist/engineWiring.js +57 -0
- package/dist/engineWiring.js.map +1 -0
- package/dist/errors.d.ts +185 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +253 -0
- package/dist/errors.js.map +1 -0
- package/dist/eventBus.d.ts +24 -0
- package/dist/eventBus.d.ts.map +1 -0
- package/dist/eventBus.js +50 -0
- package/dist/eventBus.js.map +1 -0
- package/dist/events.d.ts +220 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +35 -0
- package/dist/events.js.map +1 -0
- package/dist/frameLoop.d.ts +93 -0
- package/dist/frameLoop.d.ts.map +1 -0
- package/dist/frameLoop.js +346 -0
- package/dist/frameLoop.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +64 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +101 -0
- package/dist/logger.js.map +1 -0
- package/dist/media/engineMediaApi.d.ts +40 -0
- package/dist/media/engineMediaApi.d.ts.map +1 -0
- package/dist/media/engineMediaApi.js +71 -0
- package/dist/media/engineMediaApi.js.map +1 -0
- package/dist/media/firstFrameGate.d.ts +47 -0
- package/dist/media/firstFrameGate.d.ts.map +1 -0
- package/dist/media/firstFrameGate.js +117 -0
- package/dist/media/firstFrameGate.js.map +1 -0
- package/dist/media/mediaAdapter.d.ts +135 -0
- package/dist/media/mediaAdapter.d.ts.map +1 -0
- package/dist/media/mediaAdapter.js +2 -0
- package/dist/media/mediaAdapter.js.map +1 -0
- package/dist/media/mediaBridge.d.ts +99 -0
- package/dist/media/mediaBridge.d.ts.map +1 -0
- package/dist/media/mediaBridge.js +186 -0
- package/dist/media/mediaBridge.js.map +1 -0
- package/dist/media/mediaPlane.d.ts +58 -0
- package/dist/media/mediaPlane.d.ts.map +1 -0
- package/dist/media/mediaPlane.js +119 -0
- package/dist/media/mediaPlane.js.map +1 -0
- package/dist/media/videoProfile.d.ts +79 -0
- package/dist/media/videoProfile.d.ts.map +1 -0
- package/dist/media/videoProfile.js +46 -0
- package/dist/media/videoProfile.js.map +1 -0
- package/dist/media/videoProfile.test.d.ts +2 -0
- package/dist/media/videoProfile.test.d.ts.map +1 -0
- package/dist/media/videoProfile.test.js +26 -0
- package/dist/media/videoProfile.test.js.map +1 -0
- package/dist/media/viewRegistry.d.ts +75 -0
- package/dist/media/viewRegistry.d.ts.map +1 -0
- package/dist/media/viewRegistry.js +130 -0
- package/dist/media/viewRegistry.js.map +1 -0
- package/dist/media/webrtcAdapter.d.ts +158 -0
- package/dist/media/webrtcAdapter.d.ts.map +1 -0
- package/dist/media/webrtcAdapter.js +502 -0
- package/dist/media/webrtcAdapter.js.map +1 -0
- package/dist/protocolId.d.ts +14 -0
- package/dist/protocolId.d.ts.map +1 -0
- package/dist/protocolId.js +109 -0
- package/dist/protocolId.js.map +1 -0
- package/dist/reasons.d.ts +63 -0
- package/dist/reasons.d.ts.map +1 -0
- package/dist/reasons.js +81 -0
- package/dist/reasons.js.map +1 -0
- package/dist/redact.d.ts +19 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +50 -0
- package/dist/redact.js.map +1 -0
- package/dist/signaling/backoff.d.ts +17 -0
- package/dist/signaling/backoff.d.ts.map +1 -0
- package/dist/signaling/backoff.js +23 -0
- package/dist/signaling/backoff.js.map +1 -0
- package/dist/signaling/candidate.d.ts +19 -0
- package/dist/signaling/candidate.d.ts.map +1 -0
- package/dist/signaling/candidate.js +22 -0
- package/dist/signaling/candidate.js.map +1 -0
- package/dist/signaling/caseMapping.d.ts +19 -0
- package/dist/signaling/caseMapping.d.ts.map +1 -0
- package/dist/signaling/caseMapping.js +34 -0
- package/dist/signaling/caseMapping.js.map +1 -0
- package/dist/signaling/connection.d.ts +110 -0
- package/dist/signaling/connection.d.ts.map +1 -0
- package/dist/signaling/connection.js +365 -0
- package/dist/signaling/connection.js.map +1 -0
- package/dist/signaling/connectionFactory.d.ts +55 -0
- package/dist/signaling/connectionFactory.d.ts.map +1 -0
- package/dist/signaling/connectionFactory.js +29 -0
- package/dist/signaling/connectionFactory.js.map +1 -0
- package/dist/signaling/connectionTypes.d.ts +94 -0
- package/dist/signaling/connectionTypes.d.ts.map +1 -0
- package/dist/signaling/connectionTypes.js +2 -0
- package/dist/signaling/connectionTypes.js.map +1 -0
- package/dist/signaling/discipline.d.ts +6 -0
- package/dist/signaling/discipline.d.ts.map +1 -0
- package/dist/signaling/discipline.js +100 -0
- package/dist/signaling/discipline.js.map +1 -0
- package/dist/signaling/enums.d.ts +53 -0
- package/dist/signaling/enums.d.ts.map +1 -0
- package/dist/signaling/enums.js +52 -0
- package/dist/signaling/enums.js.map +1 -0
- package/dist/signaling/envelope.d.ts +31 -0
- package/dist/signaling/envelope.d.ts.map +1 -0
- package/dist/signaling/envelope.js +91 -0
- package/dist/signaling/envelope.js.map +1 -0
- package/dist/signaling/fieldSpec.d.ts +101 -0
- package/dist/signaling/fieldSpec.d.ts.map +1 -0
- package/dist/signaling/fieldSpec.js +130 -0
- package/dist/signaling/fieldSpec.js.map +1 -0
- package/dist/signaling/frameSender.d.ts +34 -0
- package/dist/signaling/frameSender.d.ts.map +1 -0
- package/dist/signaling/frameSender.js +57 -0
- package/dist/signaling/frameSender.js.map +1 -0
- package/dist/signaling/frames.call.d.ts +299 -0
- package/dist/signaling/frames.call.d.ts.map +1 -0
- package/dist/signaling/frames.call.js +149 -0
- package/dist/signaling/frames.call.js.map +1 -0
- package/dist/signaling/frames.room.d.ts +566 -0
- package/dist/signaling/frames.room.d.ts.map +1 -0
- package/dist/signaling/frames.room.js +165 -0
- package/dist/signaling/frames.room.js.map +1 -0
- package/dist/signaling/frames.sys.d.ts +145 -0
- package/dist/signaling/frames.sys.d.ts.map +1 -0
- package/dist/signaling/frames.sys.js +53 -0
- package/dist/signaling/frames.sys.js.map +1 -0
- package/dist/signaling/handshakeGiveUp.d.ts +36 -0
- package/dist/signaling/handshakeGiveUp.d.ts.map +1 -0
- package/dist/signaling/handshakeGiveUp.js +48 -0
- package/dist/signaling/handshakeGiveUp.js.map +1 -0
- package/dist/signaling/heartbeat.d.ts +34 -0
- package/dist/signaling/heartbeat.d.ts.map +1 -0
- package/dist/signaling/heartbeat.js +52 -0
- package/dist/signaling/heartbeat.js.map +1 -0
- package/dist/signaling/pendingRequests.d.ts +33 -0
- package/dist/signaling/pendingRequests.d.ts.map +1 -0
- package/dist/signaling/pendingRequests.js +57 -0
- package/dist/signaling/pendingRequests.js.map +1 -0
- package/dist/signaling/reconnector.d.ts +43 -0
- package/dist/signaling/reconnector.d.ts.map +1 -0
- package/dist/signaling/reconnector.js +76 -0
- package/dist/signaling/reconnector.js.map +1 -0
- package/dist/signaling/registry.d.ts +100 -0
- package/dist/signaling/registry.d.ts.map +1 -0
- package/dist/signaling/registry.js +217 -0
- package/dist/signaling/registry.js.map +1 -0
- package/dist/signaling/resumeDeadline.d.ts +48 -0
- package/dist/signaling/resumeDeadline.d.ts.map +1 -0
- package/dist/signaling/resumeDeadline.js +89 -0
- package/dist/signaling/resumeDeadline.js.map +1 -0
- package/dist/signaling/tokenExpiry.d.ts +89 -0
- package/dist/signaling/tokenExpiry.d.ts.map +1 -0
- package/dist/signaling/tokenExpiry.js +106 -0
- package/dist/signaling/tokenExpiry.js.map +1 -0
- package/dist/signaling/webSocket.d.ts +59 -0
- package/dist/signaling/webSocket.d.ts.map +1 -0
- package/dist/signaling/webSocket.js +50 -0
- package/dist/signaling/webSocket.js.map +1 -0
- package/dist/state/callMachine.d.ts +56 -0
- package/dist/state/callMachine.d.ts.map +1 -0
- package/dist/state/callMachine.js +176 -0
- package/dist/state/callMachine.js.map +1 -0
- package/dist/state/callRecv.d.ts +12 -0
- package/dist/state/callRecv.d.ts.map +1 -0
- package/dist/state/callRecv.js +255 -0
- package/dist/state/callRecv.js.map +1 -0
- package/dist/state/engineMachine.d.ts +41 -0
- package/dist/state/engineMachine.d.ts.map +1 -0
- package/dist/state/engineMachine.js +210 -0
- package/dist/state/engineMachine.js.map +1 -0
- package/dist/state/forceEnd.d.ts +44 -0
- package/dist/state/forceEnd.d.ts.map +1 -0
- package/dist/state/forceEnd.js +96 -0
- package/dist/state/forceEnd.js.map +1 -0
- package/dist/state/roomMachine.d.ts +92 -0
- package/dist/state/roomMachine.d.ts.map +1 -0
- package/dist/state/roomMachine.js +319 -0
- package/dist/state/roomMachine.js.map +1 -0
- package/dist/state/roomRecv.d.ts +7 -0
- package/dist/state/roomRecv.d.ts.map +1 -0
- package/dist/state/roomRecv.js +209 -0
- package/dist/state/roomRecv.js.map +1 -0
- package/dist/state/types.d.ts +61 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +30 -0
- package/dist/state/types.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +35 -0
package/dist/logger.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志:**engine / uikit / demo 的唯一日志入口**(CONVENTIONS §6)。
|
|
3
|
+
*
|
|
4
|
+
* 机制与取舍见 `im-rtc-server/docs/mechanism/LOGGING.md`——那份文档是四仓统一的。
|
|
5
|
+
* 三条要点:
|
|
6
|
+
* - **三条管道分开**:诊断日志(这里)/ 业务事件(engine 回调)/ 质量指标(onNetworkQuality)。
|
|
7
|
+
* - **级别按「谁该被叫醒」分**:断线是 `warn` 不是 `error`(那是常态);
|
|
8
|
+
* `info` 只记状态跃迁,一次通话个位数条。
|
|
9
|
+
* - **不提供任何兼容桥接**——想打日志只有这一条路。姊妹项目上正是因为有桥接兜底,
|
|
10
|
+
* 54 处违规才能长期无人察觉。`scripts/check-logging.sh` 会拦住直接用 console 的写法。
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* LogField 是必带字段的名字,**与服务端 internal/observability 的常量一一对应**。
|
|
14
|
+
*
|
|
15
|
+
* 别写字符串字面量:`room_id` / `roomId` / `room` 三种写法同时出现在一份日志里,
|
|
16
|
+
* 就没法按字段检索了。
|
|
17
|
+
*/
|
|
18
|
+
export const LogField = {
|
|
19
|
+
requestId: 'request_id',
|
|
20
|
+
sessionId: 'session_id',
|
|
21
|
+
roomId: 'room_id',
|
|
22
|
+
callId: 'call_id',
|
|
23
|
+
uid: 'uid',
|
|
24
|
+
deviceId: 'device_id',
|
|
25
|
+
trackId: 'track_id',
|
|
26
|
+
code: 'code',
|
|
27
|
+
};
|
|
28
|
+
const LEVEL_ORDER = {
|
|
29
|
+
debug: 10,
|
|
30
|
+
info: 20,
|
|
31
|
+
warn: 30,
|
|
32
|
+
error: 40,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* DIAGNOSTIC_CAPACITY 是诊断环形缓冲的容量。
|
|
36
|
+
*
|
|
37
|
+
* RTC 的报障几乎都是「刚才那通电话很卡」——没有那一段的日志就无从查起。
|
|
38
|
+
* 512 条够覆盖一次通话的全部状态跃迁与告警,又不至于把内存吃掉。
|
|
39
|
+
*/
|
|
40
|
+
const DIAGNOSTIC_CAPACITY = 512;
|
|
41
|
+
/* eslint-disable no-console */
|
|
42
|
+
const defaultSink = (level, message, fields) => {
|
|
43
|
+
// 这里是**唯一**允许碰 console 的地方;业务代码一律走 logger。
|
|
44
|
+
const payload = { level, message, ...fields };
|
|
45
|
+
if (level === 'error')
|
|
46
|
+
console.error(payload);
|
|
47
|
+
else if (level === 'warn')
|
|
48
|
+
console.warn(payload);
|
|
49
|
+
else
|
|
50
|
+
console.log(payload);
|
|
51
|
+
};
|
|
52
|
+
/* eslint-enable no-console */
|
|
53
|
+
let sink = defaultSink;
|
|
54
|
+
let minLevel = 'info';
|
|
55
|
+
let ring = [];
|
|
56
|
+
let nowFn = Date.now;
|
|
57
|
+
/** setLogSink 替换日志出口。传 null 恢复默认。 */
|
|
58
|
+
export function setLogSink(next) {
|
|
59
|
+
sink = next ?? defaultSink;
|
|
60
|
+
}
|
|
61
|
+
/** setLogLevel 设置最低输出级别。生产建议 'info'。 */
|
|
62
|
+
export function setLogLevel(level) {
|
|
63
|
+
minLevel = level;
|
|
64
|
+
}
|
|
65
|
+
/** setLogClock 注入时钟,仅供测试。 */
|
|
66
|
+
export function setLogClock(next) {
|
|
67
|
+
nowFn = next ?? Date.now;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* exportDiagnostics 导出最近的日志,供宿主做「报告问题」按钮。
|
|
71
|
+
*
|
|
72
|
+
* **不受 setLogLevel 影响**:环形缓冲永远记 `info` 及以上,
|
|
73
|
+
* 否则用户报障时正好没开 debug,等于什么都没有。
|
|
74
|
+
*/
|
|
75
|
+
export function exportDiagnostics() {
|
|
76
|
+
return [...ring];
|
|
77
|
+
}
|
|
78
|
+
/** clearDiagnostics 清空环形缓冲(通话结束或宿主登出时)。 */
|
|
79
|
+
export function clearDiagnostics() {
|
|
80
|
+
ring = [];
|
|
81
|
+
}
|
|
82
|
+
function emit(level, message, fields) {
|
|
83
|
+
// 环形缓冲先记:它的门槛是 info,与 setLogLevel 无关。
|
|
84
|
+
if (LEVEL_ORDER[level] >= LEVEL_ORDER.info) {
|
|
85
|
+
ring.push({ atMs: nowFn(), level, message, fields });
|
|
86
|
+
if (ring.length > DIAGNOSTIC_CAPACITY)
|
|
87
|
+
ring.shift();
|
|
88
|
+
}
|
|
89
|
+
if (LEVEL_ORDER[level] < LEVEL_ORDER[minLevel])
|
|
90
|
+
return;
|
|
91
|
+
sink(level, message, fields);
|
|
92
|
+
}
|
|
93
|
+
/** logger 是日志的公开入口。 */
|
|
94
|
+
export const logger = {
|
|
95
|
+
debug: (message, fields = {}) => emit('debug', message, fields),
|
|
96
|
+
info: (message, fields = {}) => emit('info', message, fields),
|
|
97
|
+
warn: (message, fields = {}) => emit('warn', message, fields),
|
|
98
|
+
error: (message, fields = {}) => emit('error', message, fields),
|
|
99
|
+
};
|
|
100
|
+
export { redact, redactCandidate, redactSdp } from './redact.js';
|
|
101
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { EngineBus } from '../engineBus.js';
|
|
2
|
+
import type { FrameLoop } from '../frameLoop.js';
|
|
3
|
+
import type { Layer } from '../signaling/enums.js';
|
|
4
|
+
import type { MediaAdapter } from './mediaAdapter.js';
|
|
5
|
+
/**
|
|
6
|
+
* 门面那几个媒体方法的**方法体**。
|
|
7
|
+
*
|
|
8
|
+
* 公开签名与文档留在 `CallEngine` 上——那是宿主读的东西,不该为了行数搬走。
|
|
9
|
+
* 搬过来的是它们的**编排**:拿轨道 → 把 cid / kind / simulcast 喂给状态机。
|
|
10
|
+
* 这件事本来就属于媒体层(`mediaPlane` / `mediaBridge` 做的是同一类事),
|
|
11
|
+
* 放在门面里只是让那个文件一直贴着 400 行的红线。
|
|
12
|
+
*/
|
|
13
|
+
/** MediaApiDeps 是这些编排要用到的那一把东西。 */
|
|
14
|
+
export interface MediaApiDeps {
|
|
15
|
+
media: MediaAdapter;
|
|
16
|
+
loop: FrameLoop;
|
|
17
|
+
bus: EngineBus;
|
|
18
|
+
}
|
|
19
|
+
/** 探麦克风。失败**也走一遍 error 事件**再抛——宿主的契约见 CallEngine.probeMicrophone。 */
|
|
20
|
+
export declare function probeMicrophone(d: MediaApiDeps): Promise<void>;
|
|
21
|
+
/** 探摄像头。与 probeMicrophone 同一个契约:失败先报 error 事件再抛。 */
|
|
22
|
+
export declare function probeCamera(d: MediaApiDeps): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* 发布麦克风。顺序是**先拿轨道再拿 cid**:浏览器不允许自定义 track.id,
|
|
25
|
+
* 而服务端靠 msid 里的 cid 认领 m-line(协议 §3.2)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function publishMicrophone(d: MediaApiDeps): Promise<string>;
|
|
28
|
+
/** 发布摄像头。`simulcast` **同时喂给媒体面与信令**——只喂一边就是「报了三层、实际发一层」。 */
|
|
29
|
+
export declare function publishCamera(d: MediaApiDeps, simulcast: boolean): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* 开关本端某条轨道。还没拿到 track_id(publish.ok 没回来)时只动本端,不发帧。
|
|
32
|
+
*
|
|
33
|
+
* **先动本端、再发帧**:打开摄像头要重新采集,可能失败(权限被收回 / 设备被占)——
|
|
34
|
+
* 失败时抛出去,帧就不发,免得告诉对端「开了」却一帧画面都没有。
|
|
35
|
+
* 关的时候本端也先停:帧要等 `room.mute.ok`,不能让指示灯多亮这一个来回。
|
|
36
|
+
*/
|
|
37
|
+
export declare function setMuted(d: MediaApiDeps, cid: string, muted: boolean): Promise<void>;
|
|
38
|
+
/** 报某人画面的层上界。一个 uid 可能有多条视频轨道,逐条报。 */
|
|
39
|
+
export declare function setRemoteLayer(d: MediaApiDeps, uid: string, layer: Layer): Promise<void>;
|
|
40
|
+
//# sourceMappingURL=engineMediaApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineMediaApi.d.ts","sourceRoot":"","sources":["../../src/media/engineMediaApi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;;;GAOG;AAEH,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,qEAAqE;AACrE,wBAAsB,eAAe,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAQpE;AAED,oDAAoD;AACpD,wBAAsB,WAAW,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxE;AAED,4DAA4D;AAC5D,wBAAsB,aAAa,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxF;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1F;AAED,sCAAsC;AACtC,wBAAsB,cAAc,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9F"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** 探麦克风。失败**也走一遍 error 事件**再抛——宿主的契约见 CallEngine.probeMicrophone。 */
|
|
2
|
+
export async function probeMicrophone(d) {
|
|
3
|
+
try {
|
|
4
|
+
await d.media.probeMicrophone();
|
|
5
|
+
}
|
|
6
|
+
catch (err) {
|
|
7
|
+
// 宿主只监听事件表也该知道「这通电话是因为没权限才没打出去」。
|
|
8
|
+
d.bus.emitError(err);
|
|
9
|
+
throw err;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** 探摄像头。与 probeMicrophone 同一个契约:失败先报 error 事件再抛。 */
|
|
13
|
+
export async function probeCamera(d) {
|
|
14
|
+
try {
|
|
15
|
+
await d.media.probeCamera();
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
d.bus.emitError(err);
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 发布麦克风。顺序是**先拿轨道再拿 cid**:浏览器不允许自定义 track.id,
|
|
24
|
+
* 而服务端靠 msid 里的 cid 认领 m-line(协议 §3.2)。
|
|
25
|
+
*/
|
|
26
|
+
export async function publishMicrophone(d) {
|
|
27
|
+
const info = await d.media.acquireMicrophone();
|
|
28
|
+
await d.loop.dispatch({
|
|
29
|
+
kind: 'act',
|
|
30
|
+
op: 'publish',
|
|
31
|
+
args: { cid: info.cid, kind: info.kind, source: info.source, simulcast: false },
|
|
32
|
+
});
|
|
33
|
+
return info.cid;
|
|
34
|
+
}
|
|
35
|
+
/** 发布摄像头。`simulcast` **同时喂给媒体面与信令**——只喂一边就是「报了三层、实际发一层」。 */
|
|
36
|
+
export async function publishCamera(d, simulcast) {
|
|
37
|
+
const info = await d.media.acquireCamera(simulcast);
|
|
38
|
+
await d.loop.dispatch({
|
|
39
|
+
kind: 'act',
|
|
40
|
+
op: 'publish',
|
|
41
|
+
args: { cid: info.cid, kind: info.kind, source: info.source, simulcast },
|
|
42
|
+
});
|
|
43
|
+
return info.cid;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 开关本端某条轨道。还没拿到 track_id(publish.ok 没回来)时只动本端,不发帧。
|
|
47
|
+
*
|
|
48
|
+
* **先动本端、再发帧**:打开摄像头要重新采集,可能失败(权限被收回 / 设备被占)——
|
|
49
|
+
* 失败时抛出去,帧就不发,免得告诉对端「开了」却一帧画面都没有。
|
|
50
|
+
* 关的时候本端也先停:帧要等 `room.mute.ok`,不能让指示灯多亮这一个来回。
|
|
51
|
+
*/
|
|
52
|
+
export async function setMuted(d, cid, muted) {
|
|
53
|
+
await d.media.setMuted(cid, muted);
|
|
54
|
+
const trackId = d.loop.state.room.publishTrackIds[cid];
|
|
55
|
+
if (trackId === undefined)
|
|
56
|
+
return;
|
|
57
|
+
await d.loop.dispatch({ kind: 'act', op: 'mute', args: { track_id: trackId, muted } });
|
|
58
|
+
}
|
|
59
|
+
/** 报某人画面的层上界。一个 uid 可能有多条视频轨道,逐条报。 */
|
|
60
|
+
export async function setRemoteLayer(d, uid, layer) {
|
|
61
|
+
for (const [trackId, info] of Object.entries(d.loop.state.room.remoteTracks)) {
|
|
62
|
+
if (info.uid !== uid || info.kind !== 'video')
|
|
63
|
+
continue;
|
|
64
|
+
await d.loop.dispatch({
|
|
65
|
+
kind: 'act',
|
|
66
|
+
op: 'update_layer',
|
|
67
|
+
args: { track_id: trackId, max_layer: layer },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=engineMediaApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineMediaApi.js","sourceRoot":"","sources":["../../src/media/engineMediaApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ViewElement } from './viewRegistry.js';
|
|
2
|
+
/**
|
|
3
|
+
* FirstFrameGate 等「某人开摄像头之后,**新画面真的上屏**」这一刻。
|
|
4
|
+
*
|
|
5
|
+
* # 为什么要等
|
|
6
|
+
*
|
|
7
|
+
* 对端关摄像头走的是 `room.track_muted`:轨道不摘,`<video>` 也整通复用,
|
|
8
|
+
* 于是元素上**定格着关之前的最后一帧**。按 `userVideoAvailable(true)` 立刻揭示格子,
|
|
9
|
+
* 露出来的先是那张旧画面、几百毫秒后才换成新画面——看上去就是「刷新了一下」。
|
|
10
|
+
* `MediaBridge.waitForVideo` 那条首帧判据帮不上忙:它按轨道只抛一次,
|
|
11
|
+
* 同一条轨道 mute 再 unmute 不会再抛(2026-09-11 web bob 看 iOS carol 的日志:
|
|
12
|
+
* 开关摄像头十来次,`firstVideoFrame` 只有进房那一条)。
|
|
13
|
+
*
|
|
14
|
+
* # 判据
|
|
15
|
+
*
|
|
16
|
+
* `HTMLVideoElement.requestVideoFrameCallback`:**一帧交给合成器时**回调一次。
|
|
17
|
+
* 这是浏览器上与 Android `SurfaceViewRenderer.addFrameListener`(`IMFirstFrameGate`)对应的那个口子。
|
|
18
|
+
* 元素不支持(老 Firefox / 测试替身)就立刻放行——退回原来「开了就揭示」的行为,不会更差。
|
|
19
|
+
*
|
|
20
|
+
* **「交给合成器」不等于「是新画面」**(2026-09-11 20:49 实测):关摄像头时格子把 `<video>` 藏起来,
|
|
21
|
+
* 路上还没到的最后几帧落地时元素不可见、没上屏;一开摄像头元素可见,浏览器马上把这张积压的旧帧补上屏,
|
|
22
|
+
* 回调在一两个刷新周期内就来了(`wait_ms` 7 / 20 / 29),而 iOS 那边本端首帧要 180ms 才出——
|
|
23
|
+
* 闸门放行的正是旧画面,紧接着新帧一到又闪一下。所以还要看**这一帧是什么时候收到的**:
|
|
24
|
+
* - 有 `receiveTime`(WebRTC 远端帧,与 `performance.now()` 同一时基):早于开始等的一律不算,接着等下一帧;
|
|
25
|
+
* - 没有:跳过第一张,`mediaTime` 变了才算(多等一帧,换不闪)。
|
|
26
|
+
*
|
|
27
|
+
* **uikit 那边还有 2 秒兜底**:页面在后台时浏览器不出帧,这里可能迟迟不回调。
|
|
28
|
+
*/
|
|
29
|
+
export declare class FirstFrameGate {
|
|
30
|
+
/** uid → 这一轮等待。同一个人再开一次会顶掉上一轮,旧回调认出自己过期就不作数。 */
|
|
31
|
+
private readonly waiting;
|
|
32
|
+
/** arm 开始等 uid 的下一帧上屏。`el` 是他此刻挂着的元素;还没挂就等 `attached`。 */
|
|
33
|
+
arm(uid: string, el: ViewElement | undefined, onFrame: () => void): void;
|
|
34
|
+
/**
|
|
35
|
+
* attached 是 uid 挂上了(新的)元素。
|
|
36
|
+
*
|
|
37
|
+
* **「人先进来、格子后摆」是常态**:事件抛出去的那一刻 React 还没提交,格子里的 `<video>`
|
|
38
|
+
* 还不存在。不在挂载时补等,这一轮就只能靠 uikit 的兜底计时器揭示。
|
|
39
|
+
*/
|
|
40
|
+
attached(uid: string, el: ViewElement): void;
|
|
41
|
+
/** clear 忘掉全部等待(一轮房间结束)。 */
|
|
42
|
+
clear(): void;
|
|
43
|
+
private watch;
|
|
44
|
+
private nextFrame;
|
|
45
|
+
private settle;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=firstFrameGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firstFrameGate.d.ts","sourceRoot":"","sources":["../../src/media/firstFrameGate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,cAAc;IACzB,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IAEtD,0DAA0D;IAC1D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAQxE;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI;IAK5C,4BAA4B;IAC5B,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,KAAK;IAYb,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,MAAM;CAMf"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { logger } from '../logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* FirstFrameGate 等「某人开摄像头之后,**新画面真的上屏**」这一刻。
|
|
4
|
+
*
|
|
5
|
+
* # 为什么要等
|
|
6
|
+
*
|
|
7
|
+
* 对端关摄像头走的是 `room.track_muted`:轨道不摘,`<video>` 也整通复用,
|
|
8
|
+
* 于是元素上**定格着关之前的最后一帧**。按 `userVideoAvailable(true)` 立刻揭示格子,
|
|
9
|
+
* 露出来的先是那张旧画面、几百毫秒后才换成新画面——看上去就是「刷新了一下」。
|
|
10
|
+
* `MediaBridge.waitForVideo` 那条首帧判据帮不上忙:它按轨道只抛一次,
|
|
11
|
+
* 同一条轨道 mute 再 unmute 不会再抛(2026-09-11 web bob 看 iOS carol 的日志:
|
|
12
|
+
* 开关摄像头十来次,`firstVideoFrame` 只有进房那一条)。
|
|
13
|
+
*
|
|
14
|
+
* # 判据
|
|
15
|
+
*
|
|
16
|
+
* `HTMLVideoElement.requestVideoFrameCallback`:**一帧交给合成器时**回调一次。
|
|
17
|
+
* 这是浏览器上与 Android `SurfaceViewRenderer.addFrameListener`(`IMFirstFrameGate`)对应的那个口子。
|
|
18
|
+
* 元素不支持(老 Firefox / 测试替身)就立刻放行——退回原来「开了就揭示」的行为,不会更差。
|
|
19
|
+
*
|
|
20
|
+
* **「交给合成器」不等于「是新画面」**(2026-09-11 20:49 实测):关摄像头时格子把 `<video>` 藏起来,
|
|
21
|
+
* 路上还没到的最后几帧落地时元素不可见、没上屏;一开摄像头元素可见,浏览器马上把这张积压的旧帧补上屏,
|
|
22
|
+
* 回调在一两个刷新周期内就来了(`wait_ms` 7 / 20 / 29),而 iOS 那边本端首帧要 180ms 才出——
|
|
23
|
+
* 闸门放行的正是旧画面,紧接着新帧一到又闪一下。所以还要看**这一帧是什么时候收到的**:
|
|
24
|
+
* - 有 `receiveTime`(WebRTC 远端帧,与 `performance.now()` 同一时基):早于开始等的一律不算,接着等下一帧;
|
|
25
|
+
* - 没有:跳过第一张,`mediaTime` 变了才算(多等一帧,换不闪)。
|
|
26
|
+
*
|
|
27
|
+
* **uikit 那边还有 2 秒兜底**:页面在后台时浏览器不出帧,这里可能迟迟不回调。
|
|
28
|
+
*/
|
|
29
|
+
export class FirstFrameGate {
|
|
30
|
+
/** uid → 这一轮等待。同一个人再开一次会顶掉上一轮,旧回调认出自己过期就不作数。 */
|
|
31
|
+
waiting = new Map();
|
|
32
|
+
/** arm 开始等 uid 的下一帧上屏。`el` 是他此刻挂着的元素;还没挂就等 `attached`。 */
|
|
33
|
+
arm(uid, el, onFrame) {
|
|
34
|
+
const entry = {
|
|
35
|
+
sinceMs: Date.now(), armedAt: performance.now(), onFrame, watched: new Set(), skipped: 0, firstMediaTime: undefined,
|
|
36
|
+
};
|
|
37
|
+
this.waiting.set(uid, entry);
|
|
38
|
+
if (el !== undefined)
|
|
39
|
+
this.watch(uid, entry, el);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* attached 是 uid 挂上了(新的)元素。
|
|
43
|
+
*
|
|
44
|
+
* **「人先进来、格子后摆」是常态**:事件抛出去的那一刻 React 还没提交,格子里的 `<video>`
|
|
45
|
+
* 还不存在。不在挂载时补等,这一轮就只能靠 uikit 的兜底计时器揭示。
|
|
46
|
+
*/
|
|
47
|
+
attached(uid, el) {
|
|
48
|
+
const entry = this.waiting.get(uid);
|
|
49
|
+
if (entry !== undefined)
|
|
50
|
+
this.watch(uid, entry, el);
|
|
51
|
+
}
|
|
52
|
+
/** clear 忘掉全部等待(一轮房间结束)。 */
|
|
53
|
+
clear() {
|
|
54
|
+
this.waiting.clear();
|
|
55
|
+
}
|
|
56
|
+
watch(uid, entry, el) {
|
|
57
|
+
// 同一个元素重挂不重复登记:每条登记都会逐帧续约,重一条就多一条链。
|
|
58
|
+
if (entry.watched.has(el))
|
|
59
|
+
return;
|
|
60
|
+
entry.watched.add(el);
|
|
61
|
+
if (!reportsFrames(el)) {
|
|
62
|
+
logger.info('浏览器报不了画面上屏,开摄像头即揭示', { uid });
|
|
63
|
+
this.settle(uid, entry);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.nextFrame(uid, entry, el);
|
|
67
|
+
}
|
|
68
|
+
nextFrame(uid, entry, el) {
|
|
69
|
+
el.requestVideoFrameCallback((now, frame) => {
|
|
70
|
+
if (this.waiting.get(uid) !== entry)
|
|
71
|
+
return;
|
|
72
|
+
if (isStale(entry, frame)) {
|
|
73
|
+
entry.skipped += 1;
|
|
74
|
+
this.nextFrame(uid, entry, el);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
logger.info('远端开摄像头后新画面上屏', {
|
|
78
|
+
uid,
|
|
79
|
+
wait_ms: Date.now() - entry.sinceMs,
|
|
80
|
+
skipped: entry.skipped,
|
|
81
|
+
judged_by: judgedBy(frame),
|
|
82
|
+
received_ago_ms: typeof frame?.receiveTime === 'number' ? Math.round(now - frame.receiveTime) : -1,
|
|
83
|
+
});
|
|
84
|
+
this.settle(uid, entry);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
settle(uid, entry) {
|
|
88
|
+
// 已经落定、被新一轮顶掉、或整轮清掉了:都不作数。
|
|
89
|
+
if (this.waiting.get(uid) !== entry)
|
|
90
|
+
return;
|
|
91
|
+
this.waiting.delete(uid);
|
|
92
|
+
entry.onFrame();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function reportsFrames(el) {
|
|
96
|
+
return typeof el.requestVideoFrameCallback === 'function';
|
|
97
|
+
}
|
|
98
|
+
/** isStale 判这一帧是不是关摄像头之前的旧画面。拿不到任何元数据就当新帧,不拖住揭示。 */
|
|
99
|
+
function isStale(entry, frame) {
|
|
100
|
+
if (frame === undefined)
|
|
101
|
+
return false;
|
|
102
|
+
if (typeof frame.receiveTime === 'number')
|
|
103
|
+
return frame.receiveTime < entry.armedAt;
|
|
104
|
+
if (typeof frame.mediaTime !== 'number')
|
|
105
|
+
return false;
|
|
106
|
+
if (entry.firstMediaTime === undefined) {
|
|
107
|
+
entry.firstMediaTime = frame.mediaTime;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return frame.mediaTime === entry.firstMediaTime;
|
|
111
|
+
}
|
|
112
|
+
function judgedBy(frame) {
|
|
113
|
+
if (typeof frame?.receiveTime === 'number')
|
|
114
|
+
return 'receive_time';
|
|
115
|
+
return typeof frame?.mediaTime === 'number' ? 'media_time' : 'none';
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=firstFrameGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firstFrameGate.js","sourceRoot":"","sources":["../../src/media/firstFrameGate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { PcRole } from '../signaling/enums.js';
|
|
2
|
+
/**
|
|
3
|
+
* 媒体适配器:**engine 里唯一碰 WebRTC 与 DOM 的地方**(CONVENTIONS §1)。
|
|
4
|
+
*
|
|
5
|
+
* 抽成接口有两个理由:
|
|
6
|
+
* 1. engine 的其余部分必须能在无 DOM 的环境构造——一致性向量与时序测试都跑在 Node 里;
|
|
7
|
+
* 2. 将来换媒体实现(或做 P2P 隐私模式)只动这一层,状态机与信令一行不用改。
|
|
8
|
+
*/
|
|
9
|
+
/** LocalTrackInfo 是一条本端轨道。 */
|
|
10
|
+
export interface LocalTrackInfo {
|
|
11
|
+
/**
|
|
12
|
+
* cid **等于本地轨道的 id**。
|
|
13
|
+
*
|
|
14
|
+
* 浏览器不允许自定义 `MediaStreamTrack.id`,而 msid 的第二段就是它,
|
|
15
|
+
* 服务端靠它认领 m-line(协议 §3.2)。所以顺序是先拿轨道、再拿 cid、
|
|
16
|
+
* 最后才发 `room.publish`——不能先想一个 cid。
|
|
17
|
+
*/
|
|
18
|
+
readonly cid: string;
|
|
19
|
+
readonly kind: 'audio' | 'video';
|
|
20
|
+
readonly source: 'microphone' | 'camera';
|
|
21
|
+
}
|
|
22
|
+
/** MediaAdapterEvents 是媒体层回给 engine 的出口。 */
|
|
23
|
+
export interface MediaAdapterEvents {
|
|
24
|
+
/** 本端收集到一个 ICE 候选,engine 要把它发成 room.ice_candidate。 */
|
|
25
|
+
onLocalCandidate: (pc: PcRole, candidate: RTCIceCandidateInit) => void;
|
|
26
|
+
/** 收到一条下行轨道。trackId 就是协议里的 track_id(msid 第二段)。 */
|
|
27
|
+
onRemoteTrack: (trackId: string, track: MediaStreamTrack) => void;
|
|
28
|
+
/** 某条 PC 的连接状态变了。engine 据此判断「媒体就绪」。 */
|
|
29
|
+
onConnectionStateChange: (pc: PcRole, state: RTCPeerConnectionState) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* MediaSource 是「轨道从哪来」的接缝。
|
|
33
|
+
*
|
|
34
|
+
* 默认实现就是 `navigator.mediaDevices`。抽出来是为了两件事:
|
|
35
|
+
* 1. **浏览器端到端测试**:用 canvas / AudioContext 造合成轨道,不需要真摄像头,
|
|
36
|
+
* 也不需要用户点权限弹窗;
|
|
37
|
+
* 2. 将来做虚拟背景之类的处理链时,只换这一层。
|
|
38
|
+
*/
|
|
39
|
+
export interface MediaSource {
|
|
40
|
+
getStream(constraints: MediaStreamConstraints): Promise<MediaStream>;
|
|
41
|
+
}
|
|
42
|
+
/** MediaAdapter 是媒体层的契约。 */
|
|
43
|
+
export interface MediaAdapter {
|
|
44
|
+
/** open 建立两条 PeerConnection。**每个参与者最多两条**(CONVENTIONS §8)。 */
|
|
45
|
+
open(events: MediaAdapterEvents): void;
|
|
46
|
+
/** acquireMicrophone 拿麦克风轨道并挂到 pub PC 上,返回它的 cid。 */
|
|
47
|
+
acquireMicrophone(): Promise<LocalTrackInfo>;
|
|
48
|
+
/**
|
|
49
|
+
* probeMicrophone **只探一下麦克风权限**,拿到就立刻放掉,不挂到任何 PC 上。
|
|
50
|
+
*
|
|
51
|
+
* 权限申请的时机规则(交互稿 §01):主叫在发 `call.invite` **之前**、被叫在发
|
|
52
|
+
* `call.accept` **之前**就得知道麦克风拿不拿得到——拿不到就不该去响别人的铃,
|
|
53
|
+
* 也不该让对方那边显示已接通却听不到人。而 `acquireMicrophone` 要等房间开了
|
|
54
|
+
* (pub PC 存在)才能调,那时早就过了该问的时刻。
|
|
55
|
+
*
|
|
56
|
+
* 探过之后浏览器会记住这次授权,稍后真正的 `acquireMicrophone` 不会再弹框。
|
|
57
|
+
* 被拒抛 `2001 device_permission_denied`,没设备抛 `2002 device_not_found`。
|
|
58
|
+
*/
|
|
59
|
+
probeMicrophone(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* probeCamera **只探一下摄像头权限**,拿到就放掉——不起预览、不留轨道。
|
|
62
|
+
*
|
|
63
|
+
* 群通话默认关着摄像头进来,可接听前照样要问摄像头权限(交互稿 §01)。
|
|
64
|
+
* 原先拿 `startLocalPreview` 当探针,探完摄像头就真的开着,指示灯亮、
|
|
65
|
+
* 按钮也跟着被点亮——等于替用户开了摄像头。错误码同 `probeMicrophone`。
|
|
66
|
+
*/
|
|
67
|
+
probeCamera(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* startLocalPreview 只**起采集**,不发布(设计文档 §7.5 的 `startLocalPreview`)。
|
|
70
|
+
*
|
|
71
|
+
* 拨出中还没有房间,推流无从谈起,但界面这时就该让人看见自己(草图 §03-E)。
|
|
72
|
+
* 所以「采集」与「发布」必须是两件事:这个方法起摄像头并返回 cid,
|
|
73
|
+
* 随后的 `acquireCamera` **复用同一条轨道**再挂到 pub 上——否则会把摄像头开两次
|
|
74
|
+
* (浏览器上表现为第二次 `getUserMedia` 抢设备,画面闪一下甚至直接失败)。
|
|
75
|
+
*
|
|
76
|
+
* 幂等:已经在预览就返回同一条。
|
|
77
|
+
*/
|
|
78
|
+
startLocalPreview(): Promise<LocalTrackInfo>;
|
|
79
|
+
/**
|
|
80
|
+
* stopLocalPreview 进房前关摄像头:**真的停采集**(摄像头指示灯灭),设计文档 §7.5。
|
|
81
|
+
*
|
|
82
|
+
* 只停「还没发布」的预览——已经挂上 pub 的那条归 `setMuted` 管,这里碰都不碰。
|
|
83
|
+
* 最新意图为准:等在途的预览起完再判;这期间又调了 `startLocalPreview`
|
|
84
|
+
* 或 `acquireCamera` 的话就不停。没有预览时什么也不做。
|
|
85
|
+
*/
|
|
86
|
+
stopLocalPreview(): Promise<void>;
|
|
87
|
+
/** acquireCamera 拿摄像头轨道并挂到 pub PC 上,返回它的 cid。
|
|
88
|
+
* 已经在预览的话**复用那条轨道**,不重开摄像头。
|
|
89
|
+
*
|
|
90
|
+
* simulcast 必须与随后 `room.publish` 帧里报的值一致:那一位是告诉服务端
|
|
91
|
+
* 「这条流有几层」,报了不发就等于骗它——层选择会按不存在的层去挑。 */
|
|
92
|
+
acquireCamera(simulcast?: boolean): Promise<LocalTrackInfo>;
|
|
93
|
+
/**
|
|
94
|
+
* publishedMicrophoneCid 返回**已经拿到并挂在 pub 上**的麦克风轨道 cid;没有则 `null`。
|
|
95
|
+
*
|
|
96
|
+
* 给 `CallEngine.openMicrophone` / `closeMicrophone` 按类型判断"发不发布"用——**必须问
|
|
97
|
+
* 适配器本身**,不能在门面另开一份账:宿主先直接调 `publishMicrophone()` 发布过、
|
|
98
|
+
* 再调 `openMicrophone()` 的话,门面自己那份账不知道已经发布过,会在 pub PC 上
|
|
99
|
+
* 再挂一条 sender(同一路麦克风重复发布)。
|
|
100
|
+
*/
|
|
101
|
+
publishedMicrophoneCid(): string | null;
|
|
102
|
+
/**
|
|
103
|
+
* publishedCameraCid 返回**已经发布**(不是只在预览)的摄像头轨道 cid;没有则 `null`。
|
|
104
|
+
* 语义与 {@link publishedMicrophoneCid} 相同,只是摄像头多一个"只预览没发布"的中间态
|
|
105
|
+
* 不算数——`openCamera` 的"没发布就发布"要走 `acquireCamera` 复用预览那条轨道,
|
|
106
|
+
* 而不是把预览误判成已发布。
|
|
107
|
+
*/
|
|
108
|
+
publishedCameraCid(): string | null;
|
|
109
|
+
/** createPubOffer 生成上行 offer。**pub 的 offerer 恒为本端**(协议 §3.3)。 */
|
|
110
|
+
createPubOffer(): Promise<string>;
|
|
111
|
+
/** 让下一个上行 offer 带上 ICE restart。见 webrtcAdapter 里的说明。 */
|
|
112
|
+
restartPubICE(): void;
|
|
113
|
+
/** applyPubAnswer 应用服务端对上行 offer 的应答。 */
|
|
114
|
+
applyPubAnswer(sdp: string): Promise<void>;
|
|
115
|
+
/** answerSubOffer 应答服务端下发的下行 offer。**sub 的 offerer 恒为服务端**。 */
|
|
116
|
+
answerSubOffer(sdp: string): Promise<string>;
|
|
117
|
+
/** addRemoteCandidate 加一个远端候选。乱序到达是常态,实现要容忍。 */
|
|
118
|
+
addRemoteCandidate(pc: PcRole, candidate: RTCIceCandidateInit): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* setMuted 开关本端某条轨道。
|
|
121
|
+
*
|
|
122
|
+
* **这不是 unpublish**:轨道与协商都保留,只是停止发包。
|
|
123
|
+
* 反复开关摄像头走 unpublish 会触发重协商风暴。
|
|
124
|
+
*
|
|
125
|
+
* 已发布的摄像头关掉时**连采集一起停**(指示灯灭),打开时重新采集并 `replaceTrack`
|
|
126
|
+
* 换到原来的 sender 上——cid 不变、协商不动。重新采集可能失败(权限被收回 / 设备被占),
|
|
127
|
+
* 所以返回 promise,失败以 RtcError 拒绝。
|
|
128
|
+
*/
|
|
129
|
+
setMuted(cid: string, muted: boolean): void | Promise<void>;
|
|
130
|
+
/** localTrack 取一条本端轨道,供 UI 做本地预览。 */
|
|
131
|
+
localTrack(cid: string): MediaStreamTrack | undefined;
|
|
132
|
+
/** close 关掉两条 PC 并停掉所有本端轨道。 */
|
|
133
|
+
close(): void;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=mediaAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaAdapter.d.ts","sourceRoot":"","sources":["../../src/media/mediaAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;;;;;GAMG;AAEH,8BAA8B;AAC9B,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,QAAQ,CAAC;CAC1C;AAED,4CAA4C;AAC5C,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACvE,kDAAkD;IAClD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,uCAAuC;IACvC,uBAAuB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC9E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,WAAW,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACtE;AAED,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,IAAI,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAEvC,qDAAqD;IACrD,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAE7C;;;;;;;;;;OAUG;IACH,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC;;;;;;OAMG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;;;;;;;;OASG;IACH,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAE7C;;;;;;OAMG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;;4CAIwC;IACxC,aAAa,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAE5D;;;;;;;OAOG;IACH,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAAC;IAExC;;;;;OAKG;IACH,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAAC;IAEpC,iEAAiE;IACjE,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,wDAAwD;IACxD,aAAa,IAAI,IAAI,CAAC;IAEtB,yCAAyC;IACzC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,+DAA+D;IAC/D,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,gDAAgD;IAChD,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9E;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D,qCAAqC;IACrC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAEtD,+BAA+B;IAC/B,KAAK,IAAI,IAAI,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaAdapter.js","sourceRoot":"","sources":["../../src/media/mediaAdapter.ts"],"names":[],"mappings":""}
|