tirtc-devtools-cli 0.2.4 → 0.3.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.
Files changed (31) hide show
  1. package/README.md +9 -2
  2. package/USAGE.md +14 -0
  3. package/dist/cli/src/index.js +7 -0
  4. package/dist/cli/src/role_driver.js +88 -16
  5. package/dist/cli/src/role_live_log.d.ts +17 -0
  6. package/dist/cli/src/role_live_log.js +305 -0
  7. package/package.json +1 -1
  8. package/vendor/devtools/driver/linux-x64/devtools_driver_probe +0 -0
  9. package/vendor/devtools/driver/macos-arm64/devtools_driver_probe +0 -0
  10. package/vendor/runtime/linux-x64/include/tirtc/audio.h +1 -1
  11. package/vendor/runtime/linux-x64/include/tirtc/transport.h +0 -11
  12. package/vendor/runtime/linux-x64/include/tirtc/trp.h +3 -10
  13. package/vendor/runtime/linux-x64/include/tirtc/video_io_apple.h +14 -0
  14. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
  15. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  16. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_media.a +0 -0
  17. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_transport.a +0 -0
  18. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_video.a +0 -0
  19. package/vendor/runtime/linux-x64/manifest.txt +10 -10
  20. package/vendor/runtime/macos-arm64/include/tirtc/audio.h +1 -1
  21. package/vendor/runtime/macos-arm64/include/tirtc/transport.h +0 -11
  22. package/vendor/runtime/macos-arm64/include/tirtc/trp.h +3 -10
  23. package/vendor/runtime/macos-arm64/include/tirtc/video_io_apple.h +14 -0
  24. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
  25. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
  26. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
  27. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  28. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
  29. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
  30. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
  31. package/vendor/runtime/macos-arm64/manifest.txt +12 -12
package/README.md CHANGED
@@ -57,8 +57,10 @@ node products/cli/bin/tirtc-devtools-cli.js --json device start \
57
57
  ```
58
58
 
59
59
  `device start` 默认持续运行直到用户结束进程;需要自动化限时时再显式传
60
- `--duration-ms <ms>`。prepared asset 会按完整音视频轨循环,任一轨到达源文件末尾时
61
- audio/video 同步回到源头并保持 PTS 继续递增。
60
+ `--duration-ms <ms>`。运行期间 CLI 会把启动、listener ready、client 连接 / 断开、
61
+ 首个音视频包与周期运行状态写到 stderr;`--json` 的结构化 envelope 仍只写 stdout。
62
+ prepared asset 会按完整音视频轨循环,任一轨到达源文件末尾时 audio/video 同步回到
63
+ 源头并保持 PTS 继续递增。
62
64
 
63
65
  `device start` 的启动成功条件是 device listener 已就绪;客户端是否已经扫码连接不属于
64
66
  device 启动失败条件。没有 client 时命令会继续常驻,直到用户结束进程或显式
@@ -70,6 +72,11 @@ native role 失败时,`reason_code` 与 `failed_stage` 仍是主失败事实
70
72
  只说明失败现场日志是否已上传。上传成功时,CLI JSON 与 `summary.json` 会包含
71
73
  可用于后续抓取的 `log_id`。
72
74
 
75
+ `device start` 与 `client start` 启动的 native role 默认 echo 收到的 command:
76
+ 收到任意 command 后,用同一个 command id 与同一 payload 原样回发。CLI 不新增
77
+ 额外控制命令或开关;`summary.json` 与 `--json` envelope 会包含 `command_echo`
78
+ evidence,用于确认 command 收发面已被覆盖。
79
+
73
80
  打包入口:
74
81
 
75
82
  ```sh
package/USAGE.md CHANGED
@@ -131,6 +131,11 @@ By default `device start` keeps running until the process is stopped. Use
131
131
  full audio/video source cycle; when either track reaches the source end, both
132
132
  tracks restart from offset 0 while PTS keeps increasing.
133
133
 
134
+ While the device process is running, CLI writes human-readable lifecycle logs to
135
+ stderr: startup, listener readiness, client connect/disconnect, first audio/video
136
+ packet, and periodic running status. With `--json`, the final machine-readable
137
+ envelope remains on stdout.
138
+
134
139
  `device start` is considered started once the device listener is ready. A
135
140
  missing client is not a device startup failure. Without a connected client, the
136
141
  process remains resident until it is stopped or an explicit `--duration-ms`
@@ -141,6 +146,10 @@ provided. That file is a local handoff artifact for CLI client, runtime sample
141
146
  smoke, and validation automation. The token in that bootstrap is intended for
142
147
  one client connection.
143
148
 
149
+ `device start` starts a native role that echoes every received command with the
150
+ same command id and payload. No extra CLI command or option is required.
151
+ `summary.json` and the `--json` envelope include `command_echo` evidence.
152
+
144
153
  `bootstrap.json` is not a mobile SDK connection protocol. For phone debugging,
145
154
  use token/license QR today; a full session QR or deeplink is a separate product
146
155
  slice.
@@ -155,6 +164,11 @@ node products/cli/bin/tirtc-devtools-cli.js --json client start \
155
164
 
156
165
  Client writes `summary.json`, `events.jsonl`, runtime logs, and `render/first-video-frame.*` for `frame_dump`.
157
166
 
167
+ The native client role also echoes every received command with the same command
168
+ id and payload. `summary.json` and the `--json` envelope include `command_echo`
169
+ evidence, so command receive and reply coverage is visible in normal CLI
170
+ artifacts.
171
+
158
172
  `client start --bootstrap` is meant for the local computer-to-computer DevTools
159
173
  flow. Mobile clients should not be required to fetch a local JSON file from the
160
174
  developer machine.
@@ -139,6 +139,10 @@ Missing flags are read from TIRTC_DEVICE_ID, TIRTC_DEVICE_SECRET_KEY, and TIRTC_
139
139
 
140
140
  device start succeeds once the device listener is ready. It keeps running without a client until
141
141
  the process is stopped or an explicit --duration-ms deadline is reached.
142
+ Runtime lifecycle logs are written to stderr. With --json, the final envelope remains on stdout.
143
+
144
+ The native device role echoes every received command with the same command id and payload.
145
+ summary.json and the --json envelope include command_echo evidence.
142
146
 
143
147
  bootstrap.json is a local handoff artifact for client/sample/validation automation.
144
148
  It is only written when --client-token-json is provided.
@@ -170,6 +174,9 @@ Examples:
170
174
 
171
175
  bootstrap.json is expected to come from a local device start run.
172
176
  For mobile device debugging, use token/license QR or a future session QR/deeplink.
177
+
178
+ The native client role echoes every received command with the same command id and payload.
179
+ summary.json and the --json envelope include command_echo evidence.
173
180
  `)
174
181
  .action((commandOptions) => {
175
182
  runAndExit((0, role_driver_1.runClientStart)(commandOptions, getCliOptions()));
@@ -11,6 +11,7 @@ const fs_1 = __importDefault(require("fs"));
11
11
  const os_1 = __importDefault(require("os"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const embedded_paths_1 = require("./embedded_paths");
14
+ const role_live_log_1 = require("./role_live_log");
14
15
  const defaultAudioStreamId = 10;
15
16
  const defaultVideoStreamId = 11;
16
17
  const defaultConnectTimeoutMs = 10000;
@@ -166,7 +167,11 @@ function redactRequestValue(value) {
166
167
  }
167
168
  const result = {};
168
169
  for (const [key, child] of Object.entries(value)) {
169
- if (key === 'license' || key === 'token' || key === 'client_token' || key === 'secret_key') {
170
+ if (key === 'license' ||
171
+ key === 'token' ||
172
+ key === 'client_token' ||
173
+ key === 'device_secret_key' ||
174
+ key === 'secret_key') {
170
175
  result[key] = '[REDACTED]';
171
176
  }
172
177
  else {
@@ -312,8 +317,8 @@ function buildDeviceRequest(roots, artifactRoot, options) {
312
317
  role: 'device',
313
318
  endpoint: deviceIdentity.endpoint,
314
319
  identity: {
315
- license: deviceIdentity.deviceId + ',' + deviceIdentity.deviceSecretKey,
316
320
  device_id: deviceIdentity.deviceId,
321
+ device_secret_key: deviceIdentity.deviceSecretKey,
317
322
  },
318
323
  bootstrap,
319
324
  streams: {
@@ -402,7 +407,58 @@ function buildClientRequest(roots, artifactRoot, options) {
402
407
  probe: { app_id: appId },
403
408
  };
404
409
  }
405
- function runDriver(request, artifactRoot, roots) {
410
+ function installSignalForwarding(child, liveLog) {
411
+ const signals = ['SIGINT', 'SIGTERM'];
412
+ const removers = [];
413
+ let forwardedCount = 0;
414
+ for (const signal of signals) {
415
+ const handler = () => {
416
+ forwardedCount += 1;
417
+ liveLog.signalForwarded(signal);
418
+ if (!child.killed) {
419
+ child.kill(forwardedCount > 1 ? 'SIGKILL' : signal);
420
+ }
421
+ };
422
+ process.on(signal, handler);
423
+ removers.push(() => process.off(signal, handler));
424
+ }
425
+ return () => {
426
+ for (const remove of removers) {
427
+ remove();
428
+ }
429
+ };
430
+ }
431
+ function spawnDriverProcess(driverPath, args, stdoutFd, stderrFd, liveLog) {
432
+ return new Promise((resolve) => {
433
+ let child;
434
+ try {
435
+ child = child_process_1.default.spawn(driverPath, args, {
436
+ stdio: ['ignore', stdoutFd, stderrFd],
437
+ });
438
+ }
439
+ catch (error) {
440
+ const normalized = error instanceof Error ? error : new Error(String(error));
441
+ liveLog.processError(normalized);
442
+ resolve({
443
+ status: null,
444
+ signal: null,
445
+ error: normalized,
446
+ });
447
+ return;
448
+ }
449
+ let spawnError;
450
+ const removeSignalHandlers = installSignalForwarding(child, liveLog);
451
+ child.once('error', (error) => {
452
+ spawnError = error;
453
+ liveLog.processError(error);
454
+ });
455
+ child.once('close', (code, signal) => {
456
+ removeSignalHandlers();
457
+ resolve({ status: code, signal, error: spawnError });
458
+ });
459
+ });
460
+ }
461
+ async function runDriver(role, request, artifactRoot, roots) {
406
462
  const platform = resolveRuntimePlatform();
407
463
  const driverPath = resolveDriverPath(roots, platform);
408
464
  const runtimeRoot = resolveRuntimeRoot(roots, platform);
@@ -428,26 +484,41 @@ function runDriver(request, artifactRoot, roots) {
428
484
  }
429
485
  const requestTempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'tirtc-devtools-cli-request-'));
430
486
  const requestPath = path_1.default.join(requestTempDir, 'request.json');
487
+ const summaryPath = path_1.default.join(artifactRoot, 'summary.json');
488
+ fs_1.default.rmSync(summaryPath, { force: true });
489
+ fs_1.default.rmSync(path_1.default.join(artifactRoot, 'events.jsonl'), { force: true });
431
490
  writeJson(requestPath, request);
432
491
  writeJson(path_1.default.join(artifactRoot, 'request.redacted.json'), redactRequestValue(request));
433
492
  const stdoutFd = fs_1.default.openSync(path_1.default.join(artifactRoot, 'stdout.log'), 'w');
434
493
  const stderrFd = fs_1.default.openSync(path_1.default.join(artifactRoot, 'stderr.log'), 'w');
435
- const result = child_process_1.default.spawnSync(driverPath, [
436
- '--request', requestPath,
437
- '--runtime-root', runtimeRoot,
438
- '--asset-root', assetRoot,
439
- '--artifact-root', artifactRoot,
440
- ], {
441
- stdio: ['ignore', stdoutFd, stderrFd],
494
+ const liveLog = (0, role_live_log_1.startRoleLiveLog)({
495
+ role,
496
+ artifactRoot,
497
+ request,
498
+ runtimeRoot,
499
+ assetRoot,
442
500
  });
443
- fs_1.default.closeSync(stdoutFd);
444
- fs_1.default.closeSync(stderrFd);
445
- fs_1.default.rmSync(requestTempDir, { recursive: true, force: true });
446
- const summaryPath = path_1.default.join(artifactRoot, 'summary.json');
501
+ let result = { status: null, signal: null };
502
+ try {
503
+ result = await spawnDriverProcess(driverPath, [
504
+ '--request', requestPath,
505
+ '--runtime-root', runtimeRoot,
506
+ '--asset-root', assetRoot,
507
+ '--artifact-root', artifactRoot,
508
+ ], stdoutFd, stderrFd, liveLog);
509
+ liveLog.processExit(result.status, result.signal);
510
+ }
511
+ finally {
512
+ fs_1.default.closeSync(stdoutFd);
513
+ fs_1.default.closeSync(stderrFd);
514
+ fs_1.default.rmSync(requestTempDir, { recursive: true, force: true });
515
+ liveLog.stop();
516
+ }
447
517
  if (!pathExists(summaryPath)) {
448
518
  const message = result.error instanceof Error
449
519
  ? result.error.message
450
- : 'driver exited without summary: status=' + String(result.status);
520
+ : 'driver exited without summary: status=' + String(result.status) +
521
+ ' signal=' + String(result.signal ?? 'none');
451
522
  if (result.error) {
452
523
  throw new RoleCommandError('artifact_write_failed', 'artifact', roleFailedExitCode, message);
453
524
  }
@@ -472,7 +543,7 @@ async function runRole(role, commandOptions, options) {
472
543
  const request = role === 'device' ?
473
544
  buildDeviceRequest(roots, artifactRoot, commandOptions) :
474
545
  buildClientRequest(roots, artifactRoot, commandOptions);
475
- const summary = runDriver(request, artifactRoot, roots);
546
+ const summary = await runDriver(role, request, artifactRoot, roots);
476
547
  const summaryPath = path_1.default.join(artifactRoot, 'summary.json');
477
548
  const data = {
478
549
  status: summary.status,
@@ -486,6 +557,7 @@ async function runRole(role, commandOptions, options) {
486
557
  failed_stage: failedStage(summary),
487
558
  log_id: summary.log_upload?.log_id,
488
559
  log_upload: summary.log_upload,
560
+ command_echo: summary.command_echo,
489
561
  };
490
562
  if (summary.exit_code === 0 && summary.status === 'completed') {
491
563
  printEnvelope(options, 0, 'OK', data);
@@ -0,0 +1,17 @@
1
+ export type RoleLiveLogOptions = {
2
+ role: 'device' | 'client';
3
+ artifactRoot: string;
4
+ request: Record<string, unknown>;
5
+ runtimeRoot: string;
6
+ assetRoot: string;
7
+ heartbeatIntervalMs?: number;
8
+ pollIntervalMs?: number;
9
+ emit?: (message: string) => void;
10
+ };
11
+ export type RoleLiveLogHandle = {
12
+ processError(error: Error): void;
13
+ processExit(code: number | null, signal: NodeJS.Signals | null): void;
14
+ signalForwarded(signal: NodeJS.Signals): void;
15
+ stop(): void;
16
+ };
17
+ export declare function startRoleLiveLog(options: RoleLiveLogOptions): RoleLiveLogHandle;
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startRoleLiveLog = startRoleLiveLog;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const defaultHeartbeatIntervalMs = 5000;
10
+ const defaultPollIntervalMs = 500;
11
+ function asRecord(value) {
12
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
13
+ ? value
14
+ : {};
15
+ }
16
+ function nestedRecord(root, key) {
17
+ return asRecord(root[key]);
18
+ }
19
+ function nestedString(root, first, second) {
20
+ const value = second === undefined ? root[first] : nestedRecord(root, first)[second];
21
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
22
+ }
23
+ function nestedNumber(root, first, second) {
24
+ const value = second === undefined ? root[first] : nestedRecord(root, first)[second];
25
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
26
+ }
27
+ function payloadString(payload, key) {
28
+ const value = payload[key];
29
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
30
+ }
31
+ function payloadNumber(payload, key) {
32
+ const value = payload[key];
33
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
34
+ }
35
+ function payloadBoolean(payload, key) {
36
+ const value = payload[key];
37
+ return typeof value === 'boolean' ? value : undefined;
38
+ }
39
+ function formatDurationMs(ms) {
40
+ if (ms < 1000) {
41
+ return String(ms) + 'ms';
42
+ }
43
+ return (ms / 1000).toFixed(1) + 's';
44
+ }
45
+ function formatDurationUs(us) {
46
+ if (us === undefined) {
47
+ return undefined;
48
+ }
49
+ return formatDurationMs(Math.round(us / 1000));
50
+ }
51
+ function sessionIndex(payload) {
52
+ return payloadNumber(payload, 'session_index');
53
+ }
54
+ function appendField(parts, name, value) {
55
+ if (value !== undefined) {
56
+ parts.push(name + '=' + String(value));
57
+ }
58
+ }
59
+ function makeNoopHandle() {
60
+ return {
61
+ processError: () => undefined,
62
+ processExit: () => undefined,
63
+ signalForwarded: () => undefined,
64
+ stop: () => undefined,
65
+ };
66
+ }
67
+ function startRoleLiveLog(options) {
68
+ if (options.role !== 'device') {
69
+ return makeNoopHandle();
70
+ }
71
+ const emit = options.emit ?? ((message) => console.error(message));
72
+ const startedAt = Date.now();
73
+ const eventsPath = path_1.default.join(options.artifactRoot, 'events.jsonl');
74
+ const summaryPath = path_1.default.join(options.artifactRoot, 'summary.json');
75
+ const request = options.request;
76
+ const stats = {
77
+ listenerReady: false,
78
+ sessionsStarted: 0,
79
+ sessionsEnded: 0,
80
+ firstAudioSessions: new Set(),
81
+ firstVideoSessions: new Set(),
82
+ };
83
+ let processedLineCount = 0;
84
+ let stopped = false;
85
+ const log = (message) => {
86
+ emit('[device] ' + message);
87
+ };
88
+ const media = nestedRecord(request, 'media');
89
+ const codec = payloadString(nestedRecord(media, 'video'), 'codec') ??
90
+ nestedString(request, 'video_codec') ?? 'unknown';
91
+ const sourcePath = payloadString(nestedRecord(media, 'source'), 'path') ?? options.assetRoot;
92
+ const durationMs = nestedNumber(request, 'run', 'duration_ms');
93
+ const deviceId = nestedString(request, 'identity', 'device_id') ?? 'unknown';
94
+ const endpoint = nestedString(request, 'endpoint') ?? 'unknown';
95
+ log('starting device driver device_id=' + deviceId +
96
+ ' endpoint=' + endpoint +
97
+ ' codec=' + codec +
98
+ ' artifact_root=' + options.artifactRoot);
99
+ log('source=' + sourcePath + ' runtime_root=' + options.runtimeRoot);
100
+ if (durationMs === undefined) {
101
+ log('resident mode enabled; waiting for client connections until the process is stopped');
102
+ }
103
+ else {
104
+ log('bounded mode enabled duration=' + formatDurationMs(durationMs));
105
+ }
106
+ const emitHeartbeat = () => {
107
+ const elapsed = Date.now() - startedAt;
108
+ const parts = [
109
+ 'running',
110
+ 'elapsed=' + formatDurationMs(elapsed),
111
+ 'listener=' + (stats.listenerReady ? 'ready' : 'starting'),
112
+ 'sessions=' + String(stats.sessionsStarted) + '/' + String(stats.sessionsEnded),
113
+ 'active_session=' + (stats.activeSession ?? 'none'),
114
+ 'first_audio_sessions=' + String(stats.firstAudioSessions.size),
115
+ 'first_video_sessions=' + String(stats.firstVideoSessions.size),
116
+ ];
117
+ appendField(parts, 'last_event', stats.lastEventKind);
118
+ log(parts.join(' '));
119
+ };
120
+ const emitEventLog = (event) => {
121
+ const kind = typeof event.kind === 'string' ? event.kind : undefined;
122
+ if (!kind) {
123
+ return;
124
+ }
125
+ const payload = asRecord(event.payload);
126
+ stats.lastEventKind = kind;
127
+ if (event.level === 'error') {
128
+ const reason = payloadString(payload, 'reason_code') ?? 'unknown';
129
+ log('driver event failed kind=' + kind + ' reason_code=' + reason);
130
+ }
131
+ switch (kind) {
132
+ case 'connection.listen.done':
133
+ stats.listenerReady = true;
134
+ log('listener ready; waiting for client connections');
135
+ break;
136
+ case 'bootstrap.write.done':
137
+ log('bootstrap written path=' + (payloadString(payload, 'path') ?? 'unknown'));
138
+ break;
139
+ case 'connection.connect.done': {
140
+ const session = sessionIndex(payload);
141
+ if (session !== undefined) {
142
+ stats.sessionsStarted = Math.max(stats.sessionsStarted, session);
143
+ stats.activeSession = session;
144
+ }
145
+ log('client connected session=' + (session ?? 'unknown'));
146
+ break;
147
+ }
148
+ case 'connection.session.start': {
149
+ const session = sessionIndex(payload);
150
+ if (session !== undefined) {
151
+ stats.activeSession = session;
152
+ }
153
+ log('media session started session=' + (session ?? 'unknown'));
154
+ break;
155
+ }
156
+ case 'media.audio_send.start': {
157
+ const parts = ['audio input started'];
158
+ appendField(parts, 'session', sessionIndex(payload));
159
+ appendField(parts, 'stream_id', payloadNumber(payload, 'stream_id'));
160
+ appendField(parts, 'codec', payloadString(payload, 'codec'));
161
+ appendField(parts, 'sample_rate_hz', payloadNumber(payload, 'sample_rate_hz'));
162
+ log(parts.join(' '));
163
+ break;
164
+ }
165
+ case 'media.video_send.start': {
166
+ const parts = ['video input started'];
167
+ appendField(parts, 'session', sessionIndex(payload));
168
+ appendField(parts, 'stream_id', payloadNumber(payload, 'stream_id'));
169
+ appendField(parts, 'codec', payloadString(payload, 'codec'));
170
+ log(parts.join(' '));
171
+ break;
172
+ }
173
+ case 'media.asset_cycle.config': {
174
+ const parts = ['asset cycle ready'];
175
+ appendField(parts, 'session', sessionIndex(payload));
176
+ appendField(parts, 'audio_packets', payloadNumber(payload, 'audio_packet_count'));
177
+ appendField(parts, 'video_packets', payloadNumber(payload, 'video_packet_count'));
178
+ appendField(parts, 'cycle_duration', formatDurationUs(payloadNumber(payload, 'cycle_duration_us')));
179
+ log(parts.join(' '));
180
+ break;
181
+ }
182
+ case 'media.audio_send.session_first_packet': {
183
+ const session = sessionIndex(payload);
184
+ if (session !== undefined) {
185
+ stats.firstAudioSessions.add(session);
186
+ }
187
+ const parts = ['first audio packet sent'];
188
+ appendField(parts, 'session', session);
189
+ appendField(parts, 'pts_us', payloadNumber(payload, 'pts_us'));
190
+ appendField(parts, 'bytes', payloadNumber(payload, 'bytes'));
191
+ log(parts.join(' '));
192
+ break;
193
+ }
194
+ case 'media.video_send.session_first_packet': {
195
+ const session = sessionIndex(payload);
196
+ if (session !== undefined) {
197
+ stats.firstVideoSessions.add(session);
198
+ }
199
+ const parts = ['first video packet sent'];
200
+ appendField(parts, 'session', session);
201
+ appendField(parts, 'codec', payloadString(payload, 'codec'));
202
+ appendField(parts, 'key_frame', payloadBoolean(payload, 'is_key_frame'));
203
+ appendField(parts, 'pts_us', payloadNumber(payload, 'pts_us'));
204
+ appendField(parts, 'bytes', payloadNumber(payload, 'bytes'));
205
+ log(parts.join(' '));
206
+ break;
207
+ }
208
+ case 'connection.session.end': {
209
+ const session = sessionIndex(payload);
210
+ if (session !== undefined) {
211
+ stats.sessionsEnded = Math.max(stats.sessionsEnded, session);
212
+ if (stats.activeSession === session) {
213
+ stats.activeSession = undefined;
214
+ }
215
+ }
216
+ const disconnected = payloadBoolean(payload, 'disconnected');
217
+ const elapsed = payloadNumber(payload, 'elapsed_ms');
218
+ const parts = [disconnected ? 'client disconnected' : 'client session ended'];
219
+ appendField(parts, 'session', session);
220
+ appendField(parts, 'first_audio', payloadBoolean(payload, 'sent_first_audio'));
221
+ appendField(parts, 'first_video', payloadBoolean(payload, 'sent_first_video'));
222
+ appendField(parts, 'elapsed', elapsed === undefined ? undefined : formatDurationMs(elapsed));
223
+ log(parts.join(' '));
224
+ break;
225
+ }
226
+ case 'connection.wait.no_client': {
227
+ const reason = payloadString(payload, 'reason') ?? 'unknown';
228
+ const elapsed = payloadNumber(payload, 'elapsed_ms');
229
+ log('no client connected before stop reason=' + reason +
230
+ (elapsed === undefined ? '' : ' elapsed=' + formatDurationMs(elapsed)));
231
+ break;
232
+ }
233
+ case 'driver.execution.finished': {
234
+ const status = payloadString(payload, 'status') ?? 'unknown';
235
+ const exitCode = payloadNumber(payload, 'exit_code');
236
+ const reason = payloadString(payload, 'reason_code') ?? 'unknown';
237
+ log('driver finished status=' + status +
238
+ ' exit_code=' + String(exitCode ?? 'unknown') +
239
+ ' reason_code=' + reason);
240
+ break;
241
+ }
242
+ default:
243
+ break;
244
+ }
245
+ };
246
+ const pollEvents = (flushPartial = false) => {
247
+ if (!fs_1.default.existsSync(eventsPath)) {
248
+ return;
249
+ }
250
+ let text = '';
251
+ try {
252
+ text = fs_1.default.readFileSync(eventsPath, 'utf8');
253
+ }
254
+ catch {
255
+ return;
256
+ }
257
+ const lines = text.split(/\r?\n/);
258
+ const completeLineCount = text.endsWith('\n')
259
+ ? lines.length - 1
260
+ : (flushPartial ? lines.length : lines.length - 1);
261
+ for (let index = processedLineCount; index < completeLineCount; index += 1) {
262
+ const line = lines[index]?.trim();
263
+ if (!line) {
264
+ continue;
265
+ }
266
+ try {
267
+ emitEventLog(JSON.parse(line));
268
+ }
269
+ catch {
270
+ if (flushPartial) {
271
+ log('skipped malformed driver event line=' + String(index + 1));
272
+ }
273
+ }
274
+ }
275
+ processedLineCount = Math.max(processedLineCount, completeLineCount);
276
+ };
277
+ const pollTimer = setInterval(() => pollEvents(false), options.pollIntervalMs ?? defaultPollIntervalMs);
278
+ const heartbeatTimer = setInterval(emitHeartbeat, options.heartbeatIntervalMs ?? defaultHeartbeatIntervalMs);
279
+ return {
280
+ processError: (error) => {
281
+ pollEvents(true);
282
+ log('driver process error message=' + error.message);
283
+ },
284
+ processExit: (code, signal) => {
285
+ pollEvents(true);
286
+ const elapsed = Date.now() - startedAt;
287
+ log('process exited code=' + String(code ?? 'null') +
288
+ ' signal=' + String(signal ?? 'none') +
289
+ ' elapsed=' + formatDurationMs(elapsed) +
290
+ ' summary=' + summaryPath);
291
+ },
292
+ signalForwarded: (signal) => {
293
+ log('forwarding signal=' + signal + ' to native driver');
294
+ },
295
+ stop: () => {
296
+ if (stopped) {
297
+ return;
298
+ }
299
+ stopped = true;
300
+ clearInterval(pollTimer);
301
+ clearInterval(heartbeatTimer);
302
+ pollEvents(true);
303
+ },
304
+ };
305
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirtc-devtools-cli",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "main": "dist/cli/src/index.js",
6
6
  "types": "dist/cli/src/index.d.ts",
@@ -101,7 +101,7 @@ typedef struct TirtcAudioOutputMetricsSnapshot {
101
101
  *
102
102
  * The snapshot is a caller-owned value copy. Zero-initialized fields mean the output has not yet
103
103
  * observed a matching runtime fact or only cached zero-state is available. This diagnostic API is
104
- * intended for UI/debug visibility and logs, not for playback control decisions.
104
+ * intended for UI/debug visibility and logs, not for output control decisions.
105
105
  */
106
106
  typedef struct TirtcAudioOutputDebugSnapshot {
107
107
  TirtcMediaCodec codec;
@@ -289,17 +289,6 @@ typedef struct TirtcTransportConnCallbacks {
289
289
  */
290
290
  TirtcError tirtc_transport_init(void);
291
291
 
292
- /**
293
- * @brief Enable/disable transport debug mode.
294
- *
295
- * When enabled, transport backend sets verbose vendor SDK log level during runtime init
296
- * and applies it immediately if runtime is already initialized.
297
- *
298
- * @param enabled Non-zero to enable debug mode, zero to disable.
299
- * @return Operation status.
300
- */
301
- TirtcError tirtc_transport_enable_debug(uint8_t enabled);
302
-
303
292
  /**
304
293
  * @brief Uninitialize transport runtime.
305
294
  *
@@ -25,19 +25,12 @@ typedef struct TirtcInitOptions {
25
25
 
26
26
  } TirtcInitOptions;
27
27
 
28
- typedef enum TirtcMediaSendPolicy {
29
-
30
- TIRTC_MEDIA_SEND_POLICY_ON_REQUEST = 0,
31
-
32
- TIRTC_MEDIA_SEND_POLICY_AUTO_ON_CONNECTED = 1,
33
- } TirtcMediaSendPolicy;
34
-
35
28
  typedef struct TirtcConnServiceStartOptions {
36
- const char* license;
29
+ const char* device_id;
37
30
 
38
- uint32_t max_connections;
31
+ const char* device_secret_key;
39
32
 
40
- TirtcMediaSendPolicy media_send_policy;
33
+ uint32_t max_connections;
41
34
  } TirtcConnServiceStartOptions;
42
35
 
43
36
  typedef struct TirtcConnConnectOptions {
@@ -20,8 +20,17 @@ typedef enum TirtcVideoAppleWindowSlot {
20
20
  TIRTC_VIDEO_APPLE_WINDOW_SLOT_RIGHT = 2,
21
21
  } TirtcVideoAppleWindowSlot;
22
22
 
23
+ typedef enum TirtcVideoAppleCameraFacing {
24
+ TIRTC_VIDEO_APPLE_CAMERA_FACING_FRONT = 0,
25
+ TIRTC_VIDEO_APPLE_CAMERA_FACING_BACK = 1,
26
+ } TirtcVideoAppleCameraFacing;
27
+
23
28
  typedef int (*TirtcVideoAppleOnPixelBufferFn)(void* pixel_buffer, void* user_data);
24
29
 
30
+ typedef struct TirtcVideoAppleAvFoundationVinOptions {
31
+ TirtcVideoAppleCameraFacing camera_facing;
32
+ } TirtcVideoAppleAvFoundationVinOptions;
33
+
25
34
  typedef struct TirtcVideoAppleCoreVideoVoutOptions {
26
35
  TirtcVideoAppleVoutTarget target;
27
36
  TirtcVideoAppleOnPixelBufferFn on_pixel_buffer;
@@ -35,6 +44,11 @@ typedef struct TirtcVideoAppleCoreVideoVoutOptions {
35
44
  uint32_t window_height;
36
45
  } TirtcVideoAppleCoreVideoVoutOptions;
37
46
 
47
+ TirtcError tirtc_video_apple_create_avfoundation_vin(TirtcVideoVin** out_vin);
48
+ TirtcError tirtc_video_apple_avfoundation_vin_set_options(
49
+ TirtcVideoVin* vin, const TirtcVideoAppleAvFoundationVinOptions* options);
50
+ TirtcError tirtc_video_apple_avfoundation_vin_get_actual_facing(
51
+ TirtcVideoVin* vin, TirtcVideoAppleCameraFacing* out_camera_facing);
38
52
  TirtcError tirtc_video_apple_create_core_video_vout(TirtcVideoVout** out_vout);
39
53
  TirtcError tirtc_video_apple_core_video_vout_set_options(
40
54
  TirtcVideoVout* vout, const TirtcVideoAppleCoreVideoVoutOptions* options);
@@ -1,9 +1,9 @@
1
1
  platform=linux-x64
2
2
  profile=full
3
- staged_at_utc=2026-05-03T15:04:13Z
3
+ staged_at_utc=2026-05-07T08:43:43Z
4
4
  source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/linux-x64
5
5
 
6
- bfc096be1484ac2b1c2776ccabfa2a4c6a982e869abf875192ff06fad85e82ca include/tirtc/audio.h
6
+ 59ba10e0b7cc679d625d3e8c536e3e234b3173091b9859956252fe3dd631b774 include/tirtc/audio.h
7
7
  6d972ccfe150a3b4f2d7f18fa92b3ade9210c1c8bb754d061ac6b7997b59e2cb include/tirtc/audio_codec.h
8
8
  7bacbdb2d8bb10d6444036a8fef42f2a8e3ea34dfc38e165ee678d61f189db41 include/tirtc/audio_frame.h
9
9
  fb8ea35263167c33487bd3aa503c26ed2dfbf97877f7bda92c10065cd5c97c13 include/tirtc/audio_io.h
@@ -21,25 +21,25 @@ ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/
21
21
  7e2f7f81afe37e22f5414d9db32438edd948ff775230c3a0a17ff9ac1a0b560e include/tirtc/media_codec.h
22
22
  ca63fe4fa0c787f20923e264e116fa6d7cb8194a227c03be4e9843d0ce5a9864 include/tirtc/media_downlink.h
23
23
  e64191a39004165cdcd11b2ca824af34d4bfe02f7ec3c3101fa9291f56488c30 include/tirtc/media_uplink.h
24
- 489f6c9caa3e4094566b660ef0a002a39c66c1956ef0a1bdb6eacca3798c849a include/tirtc/transport.h
25
- bb9c1bf46f2ab51a9f7adb211276c8563b09e7968031c0c6abeebc0eddd66acb include/tirtc/trp.h
24
+ 93b85272f8fa606e048e40c0bd353440a46459180afcdaddd15b9a028dc26173 include/tirtc/transport.h
25
+ b932f3e930057843751e66d6b4eb9d8440ecdfd6634fd941abbe260eccfa056c include/tirtc/trp.h
26
26
  92b3db6e2cb02265ad5db01881edce9d4e095b1dadf449dce5d8bb5362957e33 include/tirtc/video_codec.h
27
27
  e51379666c199588cc33279ccf52248035d1cae3d1d468b1615ebf29f0b39c9c include/tirtc/video_frame.h
28
28
  2a02645d82c58d433c7306a9f0bcd31d0f3e560b63822f7e80919761b81a6284 include/tirtc/video_io.h
29
29
  9930dce5e8e2b12a1ab28ee91f3fb46f6cf3487e515ea2b4ec0e00009bd5f070 include/tirtc/video_io_android.h
30
- 005114b9213ec826e18d11eca4b9d65cce2ca0e7c781f03d85292365d9d5dfdd include/tirtc/video_io_apple.h
30
+ f22127424d5978ab0644209b6c25c24e19e320dd2fbda6634e6344597ff7e2be include/tirtc/video_io_apple.h
31
31
  cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/video_io_harmony.h
32
32
  65b5d24fe3a6bc2a299a2220148a153ba4eb0955a49c1c3baabf1fdfed8aabdd include/tirtc/video_io_windows.h
33
33
  8cd6b66bea14890a665cc317f8572429b2c3e4463773f8b77c1e4dc30a4a8747 include/tirtc/video_processing.h
34
34
  ceb7cdd45efae57e5bd53d4177cb20c4a0cb9917fcdd23127b050d69c8b919ac lib/libTiRTC.a
35
35
  b1f4135025cb8e8520a14268d831b9998920a4239f84bb6b409d0e4909fd5bee lib/libcrypto.a
36
36
  296ba0b5efa9d2ac49e3bf278c5d467b31436e73fbc608b736e974bcf9759bde lib/libmatrix_runtime_audio.a
37
- 88f9c545943e4ef80024baf3620e91817ec16a4fea60b0e8c7887a0a41dc9d1b lib/libmatrix_runtime_facade.a
37
+ 695c398eabef4f4227f1e7d7c8a46f3854b66e90d981d2580b664bf244977417 lib/libmatrix_runtime_facade.a
38
38
  ec7bbf8e8744c6645a441a28e24e0645906152cc987d6fcca16af3c3badba940 lib/libmatrix_runtime_foundation_http.a
39
- 71f395eb5a15a8c65a702bb4b7996aebe69d8381fdd540cfc39a339dc148c69b lib/libmatrix_runtime_foundation_logging.a
40
- 8964ab2d93bf0fd4ee6666459ffec53cd35b07288fccc0d46e042e60b8466d4f lib/libmatrix_runtime_media.a
41
- 93dd81cfb9ed8aef29bfa3fb9d18aaed140ac25d00beeff1a0156a9333afa8a5 lib/libmatrix_runtime_transport.a
42
- ac7b85780c75b5d0c3abf1c5293181739a0fceeb2ad8fa930f98bd86bba5daa2 lib/libmatrix_runtime_video.a
39
+ e41012346b8200eb6a722afc2e916f6365d32698768e1d176874a23add644b2c lib/libmatrix_runtime_foundation_logging.a
40
+ 357a15ebff6afcf0c97073d19624434e62454ed463212d0d0298af2f370a7742 lib/libmatrix_runtime_media.a
41
+ 41baae4526a1798e154c0e158a9539adc417d06e0e8193adab0c1a85cf784501 lib/libmatrix_runtime_transport.a
42
+ 59476bb5dc78b9c89cb0663fe4490ad260625332fdc68cd83a3d52abf0f31b10 lib/libmatrix_runtime_video.a
43
43
  511d521f7972df3993e5976d6e2dbcad7a6fbce9be15071274d0cbd9d51157f5 lib/libssl.a
44
44
  a67ec9034848ef24a1b17671e444daa62a8f9e6b8319a1e932593908720ff2a1 lib/libwebrtc_apm.a
45
45
  700e455255897e3cffab13ca593a6e4d9d11383ae609215cbbd6043a63d47161 lib/libxlog.a
@@ -101,7 +101,7 @@ typedef struct TirtcAudioOutputMetricsSnapshot {
101
101
  *
102
102
  * The snapshot is a caller-owned value copy. Zero-initialized fields mean the output has not yet
103
103
  * observed a matching runtime fact or only cached zero-state is available. This diagnostic API is
104
- * intended for UI/debug visibility and logs, not for playback control decisions.
104
+ * intended for UI/debug visibility and logs, not for output control decisions.
105
105
  */
106
106
  typedef struct TirtcAudioOutputDebugSnapshot {
107
107
  TirtcMediaCodec codec;
@@ -289,17 +289,6 @@ typedef struct TirtcTransportConnCallbacks {
289
289
  */
290
290
  TirtcError tirtc_transport_init(void);
291
291
 
292
- /**
293
- * @brief Enable/disable transport debug mode.
294
- *
295
- * When enabled, transport backend sets verbose vendor SDK log level during runtime init
296
- * and applies it immediately if runtime is already initialized.
297
- *
298
- * @param enabled Non-zero to enable debug mode, zero to disable.
299
- * @return Operation status.
300
- */
301
- TirtcError tirtc_transport_enable_debug(uint8_t enabled);
302
-
303
292
  /**
304
293
  * @brief Uninitialize transport runtime.
305
294
  *
@@ -25,19 +25,12 @@ typedef struct TirtcInitOptions {
25
25
 
26
26
  } TirtcInitOptions;
27
27
 
28
- typedef enum TirtcMediaSendPolicy {
29
-
30
- TIRTC_MEDIA_SEND_POLICY_ON_REQUEST = 0,
31
-
32
- TIRTC_MEDIA_SEND_POLICY_AUTO_ON_CONNECTED = 1,
33
- } TirtcMediaSendPolicy;
34
-
35
28
  typedef struct TirtcConnServiceStartOptions {
36
- const char* license;
29
+ const char* device_id;
37
30
 
38
- uint32_t max_connections;
31
+ const char* device_secret_key;
39
32
 
40
- TirtcMediaSendPolicy media_send_policy;
33
+ uint32_t max_connections;
41
34
  } TirtcConnServiceStartOptions;
42
35
 
43
36
  typedef struct TirtcConnConnectOptions {
@@ -20,8 +20,17 @@ typedef enum TirtcVideoAppleWindowSlot {
20
20
  TIRTC_VIDEO_APPLE_WINDOW_SLOT_RIGHT = 2,
21
21
  } TirtcVideoAppleWindowSlot;
22
22
 
23
+ typedef enum TirtcVideoAppleCameraFacing {
24
+ TIRTC_VIDEO_APPLE_CAMERA_FACING_FRONT = 0,
25
+ TIRTC_VIDEO_APPLE_CAMERA_FACING_BACK = 1,
26
+ } TirtcVideoAppleCameraFacing;
27
+
23
28
  typedef int (*TirtcVideoAppleOnPixelBufferFn)(void* pixel_buffer, void* user_data);
24
29
 
30
+ typedef struct TirtcVideoAppleAvFoundationVinOptions {
31
+ TirtcVideoAppleCameraFacing camera_facing;
32
+ } TirtcVideoAppleAvFoundationVinOptions;
33
+
25
34
  typedef struct TirtcVideoAppleCoreVideoVoutOptions {
26
35
  TirtcVideoAppleVoutTarget target;
27
36
  TirtcVideoAppleOnPixelBufferFn on_pixel_buffer;
@@ -35,6 +44,11 @@ typedef struct TirtcVideoAppleCoreVideoVoutOptions {
35
44
  uint32_t window_height;
36
45
  } TirtcVideoAppleCoreVideoVoutOptions;
37
46
 
47
+ TirtcError tirtc_video_apple_create_avfoundation_vin(TirtcVideoVin** out_vin);
48
+ TirtcError tirtc_video_apple_avfoundation_vin_set_options(
49
+ TirtcVideoVin* vin, const TirtcVideoAppleAvFoundationVinOptions* options);
50
+ TirtcError tirtc_video_apple_avfoundation_vin_get_actual_facing(
51
+ TirtcVideoVin* vin, TirtcVideoAppleCameraFacing* out_camera_facing);
38
52
  TirtcError tirtc_video_apple_create_core_video_vout(TirtcVideoVout** out_vout);
39
53
  TirtcError tirtc_video_apple_core_video_vout_set_options(
40
54
  TirtcVideoVout* vout, const TirtcVideoAppleCoreVideoVoutOptions* options);
@@ -1,9 +1,9 @@
1
1
  platform=macos-arm64
2
2
  profile=full
3
- staged_at_utc=2026-05-03T15:02:29Z
3
+ staged_at_utc=2026-05-07T08:41:46Z
4
4
  source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/macos-arm64
5
5
 
6
- bfc096be1484ac2b1c2776ccabfa2a4c6a982e869abf875192ff06fad85e82ca include/tirtc/audio.h
6
+ 59ba10e0b7cc679d625d3e8c536e3e234b3173091b9859956252fe3dd631b774 include/tirtc/audio.h
7
7
  6d972ccfe150a3b4f2d7f18fa92b3ade9210c1c8bb754d061ac6b7997b59e2cb include/tirtc/audio_codec.h
8
8
  7bacbdb2d8bb10d6444036a8fef42f2a8e3ea34dfc38e165ee678d61f189db41 include/tirtc/audio_frame.h
9
9
  fb8ea35263167c33487bd3aa503c26ed2dfbf97877f7bda92c10065cd5c97c13 include/tirtc/audio_io.h
@@ -21,13 +21,13 @@ ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/
21
21
  7e2f7f81afe37e22f5414d9db32438edd948ff775230c3a0a17ff9ac1a0b560e include/tirtc/media_codec.h
22
22
  ca63fe4fa0c787f20923e264e116fa6d7cb8194a227c03be4e9843d0ce5a9864 include/tirtc/media_downlink.h
23
23
  e64191a39004165cdcd11b2ca824af34d4bfe02f7ec3c3101fa9291f56488c30 include/tirtc/media_uplink.h
24
- 489f6c9caa3e4094566b660ef0a002a39c66c1956ef0a1bdb6eacca3798c849a include/tirtc/transport.h
25
- bb9c1bf46f2ab51a9f7adb211276c8563b09e7968031c0c6abeebc0eddd66acb include/tirtc/trp.h
24
+ 93b85272f8fa606e048e40c0bd353440a46459180afcdaddd15b9a028dc26173 include/tirtc/transport.h
25
+ b932f3e930057843751e66d6b4eb9d8440ecdfd6634fd941abbe260eccfa056c include/tirtc/trp.h
26
26
  92b3db6e2cb02265ad5db01881edce9d4e095b1dadf449dce5d8bb5362957e33 include/tirtc/video_codec.h
27
27
  e51379666c199588cc33279ccf52248035d1cae3d1d468b1615ebf29f0b39c9c include/tirtc/video_frame.h
28
28
  2a02645d82c58d433c7306a9f0bcd31d0f3e560b63822f7e80919761b81a6284 include/tirtc/video_io.h
29
29
  9930dce5e8e2b12a1ab28ee91f3fb46f6cf3487e515ea2b4ec0e00009bd5f070 include/tirtc/video_io_android.h
30
- 005114b9213ec826e18d11eca4b9d65cce2ca0e7c781f03d85292365d9d5dfdd include/tirtc/video_io_apple.h
30
+ f22127424d5978ab0644209b6c25c24e19e320dd2fbda6634e6344597ff7e2be include/tirtc/video_io_apple.h
31
31
  cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/video_io_harmony.h
32
32
  65b5d24fe3a6bc2a299a2220148a153ba4eb0955a49c1c3baabf1fdfed8aabdd include/tirtc/video_io_windows.h
33
33
  8cd6b66bea14890a665cc317f8572429b2c3e4463773f8b77c1e4dc30a4a8747 include/tirtc/video_processing.h
@@ -35,13 +35,13 @@ cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/
35
35
  8db86d6714264047e8fd4086ddd7315722d675749719e6175f89eb5a636b48a1 lib/libTiRTC.a
36
36
  b39daee6a3d39bf0ca20c45084601133c4198de8dca848dcff6dd9c70ae99016 lib/libcrypto.a
37
37
  c052857ef315e3d61db9c862cad10709a3a6b2487dc41799cbe4d74a805de875 lib/libcrypto.dylib
38
- 8b75c9fa50c130ba795929904bb623ed5d3431185cc317a9f446d8e57eaaa351 lib/libmatrix_runtime_audio.a
39
- d4b7fe1d7020602511ad464c0b73294d5f9f65805dd8c3a180e58e8a49826be7 lib/libmatrix_runtime_facade.a
40
- 217ecd0bc12629678682848acdfee5b9a4b32c55077d6b60f6b46e142e313717 lib/libmatrix_runtime_foundation_http.a
41
- cc55fc4bcac36a395d594c9085845a418e07f4102c4eb551e4f69fe3297c8df3 lib/libmatrix_runtime_foundation_logging.a
42
- c5e2c47a2dea31abf6ad18be3474f87e1961742672b9ac5f423789d3d09bf0d7 lib/libmatrix_runtime_media.a
43
- 09b6ca2483b2c64d2d8e849d7ea781e7fdfe7f53a05d5ed11ef5e81e6f926fd2 lib/libmatrix_runtime_transport.a
44
- 015e99fcd2ed8cca7b8bd3b98830d2cd5b88ce4801e8080c0cd907d43e42ac38 lib/libmatrix_runtime_video.a
38
+ accd2ae1d507620e79a137fb3251bda8e4fd6323053c520d43cd4b2e8ae6b845 lib/libmatrix_runtime_audio.a
39
+ 22063c50d962a70929ab890ce53c4b66dc166e6e4855b77346619d6547080f1e lib/libmatrix_runtime_facade.a
40
+ 77f99950767a60f8b950acae0988ecc4c835a599f530ad1a158de32d2131f61d lib/libmatrix_runtime_foundation_http.a
41
+ 182c56ff2263a8c5e392e1a49adc367a438cfda61d35b93db3861689fc03ca4c lib/libmatrix_runtime_foundation_logging.a
42
+ fc95129eabfb9cb46e17276cf1814e60d47f67991ea97128a32e6520b5b23674 lib/libmatrix_runtime_media.a
43
+ 1d9ef883017e5a489191b02744aa81a74d4bc7ea2f1379e7e0c593b1e23ac731 lib/libmatrix_runtime_transport.a
44
+ 339c27670947c3a546eedc1464f3d88998ba74434ce8ec0d0090f28bd0a140a3 lib/libmatrix_runtime_video.a
45
45
  c11c65d373a127028350c41fa58cd2d1223f2b5d70a84e13b115d90daaba25ca lib/libssl.a
46
46
  ef1c1104bbdd2528ed7b958fb7252bd6249875f92300b0c9577d6c4bd6c0d88a lib/libssl.dylib
47
47
  e14e846e43d64e240fa0e5745bf4e702b79d0f2442e7f768beb990610735c71b lib/libtgrtc.dylib