tirtc-devtools-cli 0.1.1 → 0.2.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 (29) hide show
  1. package/README.md +7 -7
  2. package/USAGE.md +40 -23
  3. package/dist/cli/src/index.js +35 -21
  4. package/dist/cli/src/media_assets.d.ts +2 -0
  5. package/dist/cli/src/media_assets.js +125 -7
  6. package/dist/cli/src/role_driver.d.ts +11 -10
  7. package/dist/cli/src/role_driver.js +77 -81
  8. package/package.json +1 -1
  9. package/vendor/devtools/driver/linux-x64/devtools_driver_probe +0 -0
  10. package/vendor/devtools/driver/macos-arm64/devtools_driver_probe +0 -0
  11. package/vendor/runtime/linux-x64/include/tirtc/error.h +22 -0
  12. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_audio.a +0 -0
  13. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
  14. package/vendor/runtime/linux-x64/lib/libmatrix_runtime_foundation_http.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 +9 -9
  20. package/vendor/runtime/macos-arm64/include/tirtc/error.h +22 -0
  21. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
  22. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
  23. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
  24. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  25. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
  26. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
  27. package/vendor/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
  28. package/vendor/runtime/macos-arm64/manifest.txt +9 -9
  29. package/vendor/runtime/script/prepare_runtime_media_dataset.sh +17 -0
package/README.md CHANGED
@@ -6,8 +6,8 @@
6
6
 
7
7
  - `token issue` / `license qrcode`:本地联调的凭据与二维码工具。
8
8
  - `assets prepare`:把默认资产或任意 MP4 准备成 native role driver 使用的媒体资产。
9
- - `send start`:作为标准上行端启动 native DevTools driver,送出音视频,产出 `bootstrap.json` 与 execution evidence。
10
- - `receive start`:作为标准下行端消费本机 `bootstrap.json` 或显式 `remote/token`,产出 `frame_dump` 与 summary。
9
+ - `device start`:作为标准上行 device 启动 native DevTools driver,送出音视频,按需产出本机 `bootstrap.json` 与 execution evidence。
10
+ - `client start`:作为标准下行 client 消费本机 `bootstrap.json` 或显式 device/token,产出 `frame_dump` 与 summary。
11
11
  - CLI 负责参数、环境变量、token 签发、JSON envelope、artifact 摘要与打包定位;真实 TiRTC lifecycle 由 `products/devtools/driver/` 承接。
12
12
 
13
13
  ## 不负责什么
@@ -21,7 +21,7 @@
21
21
  ## 依赖方向
22
22
 
23
23
  - token/license 工具由 CLI 自己承接;仓库级 token helper 入口为 `./script/issue_devtools_token.sh`。
24
- - send/receive 通过本地 native driver executable 执行,默认查找 `.build/devtools-driver/bin/<platform>/devtools_driver_probe` 或 `vendor/devtools/driver/<platform>/devtools_driver_probe`。
24
+ - device/client 通过本地 native driver executable 执行,默认查找 `.build/devtools-driver/bin/<platform>/devtools_driver_probe` 或 `vendor/devtools/driver/<platform>/devtools_driver_probe`。
25
25
  - runtime bundle 默认查找 `.build/products/runtime/<platform>` 或 `vendor/runtime/<platform>`。
26
26
 
27
27
  ## 常用命令
@@ -38,7 +38,7 @@ node products/cli/bin/tirtc-devtools-cli.js --help
38
38
  ./script/issue_devtools_token.sh --token-only
39
39
  ```
40
40
 
41
- 真实 send/receive 闭环优先走:
41
+ 真实 device/client 闭环优先走:
42
42
 
43
43
  ```sh
44
44
  products/devtools/driver/script/run_capability_probe.sh
@@ -50,13 +50,13 @@ products/devtools/driver/script/run_capability_probe.sh
50
50
  node products/cli/bin/tirtc-devtools-cli.js --json assets prepare \
51
51
  --source ./movie.mp4 \
52
52
  --output-root .build/tirtc-assets
53
- node products/cli/bin/tirtc-devtools-cli.js --json send start \
53
+ node products/cli/bin/tirtc-devtools-cli.js --json device start \
54
54
  --source .build/tirtc-assets/manifest.json \
55
55
  --video-codec h264 \
56
- --artifact-root .build/devtools-cli/send-movie-h264
56
+ --artifact-root .build/devtools-cli/device-movie-h264
57
57
  ```
58
58
 
59
- `send start` 默认持续运行直到用户结束进程;需要自动化限时时再显式传
59
+ `device start` 默认持续运行直到用户结束进程;需要自动化限时时再显式传
60
60
  `--duration-ms <ms>`。prepared asset 会按完整音视频轨循环,任一轨到达源文件末尾时
61
61
  audio/video 同步回到源头并保持 PTS 继续递增。
62
62
 
package/USAGE.md CHANGED
@@ -15,8 +15,8 @@ node products/cli/bin/tirtc-devtools-cli.js --help
15
15
 
16
16
  ## Platform Support
17
17
 
18
- - `macos-arm64`: supported for token, assets prepare, send, receive, package smoke, and native send+receive qualification.
19
- - `linux-x64`: supported for token, assets prepare, send, receive, package smoke, and native driver packaging. Linux native send/receive runs through the packaged headless driver on Linux hosts or `linux/amd64` containers.
18
+ - `macos-arm64`: supported for token, assets prepare, device, client, package smoke, and native device+client qualification.
19
+ - `linux-x64`: supported for token, assets prepare, device, client, package smoke, and native driver packaging. Linux native device/client runs through the packaged headless driver on Linux hosts or `linux/amd64` containers.
20
20
 
21
21
  ## Token
22
22
 
@@ -71,7 +71,7 @@ node products/cli/bin/tirtc-devtools-cli.js --json assets prepare
71
71
  node products/cli/bin/tirtc-devtools-cli.js --json assets prepare --source runtime/assets/source.mp4
72
72
  ```
73
73
 
74
- Prepare any MP4 and use the returned `data.manifest_path` as `send start --source`:
74
+ Prepare any MP4 and use the returned `data.manifest_path` as `device start --source`:
75
75
 
76
76
  ```sh
77
77
  node products/cli/bin/tirtc-devtools-cli.js --json assets prepare \
@@ -79,61 +79,78 @@ node products/cli/bin/tirtc-devtools-cli.js --json assets prepare \
79
79
  --output-root .build/tirtc-assets
80
80
  ```
81
81
 
82
- ## Send
82
+ ## Device
83
83
 
84
- Required environment:
84
+ Device startup requires:
85
85
 
86
86
  ```sh
87
87
  export TIRTC_DEVICE_ID="<DEVICE_ID>"
88
88
  export TIRTC_DEVICE_SECRET_KEY="<DEVICE_SECRET_KEY>"
89
+ export TIRTC_ENDPOINT="<SERVICE_ENTRY>"
90
+ ```
91
+
92
+ These can also be passed explicitly with `--device-id`, `--device-secret-key`,
93
+ and `--endpoint`. Missing values fail during CLI preflight before the native
94
+ driver starts.
95
+
96
+ If the local `client start --bootstrap` flow is needed, issue a fresh client
97
+ token first:
98
+
99
+ ```sh
89
100
  export TIRTC_ACCESS_KEY_ID="<ACCESS_KEY_ID>"
90
101
  export TIRTC_SECRET_KEY_ID="<SECRET_KEY_ID>"
91
102
  export TIRTC_APP_ID="<APP_ID>"
92
- export TIRTC_ENDPOINT="<SERVICE_ENTRY>"
93
103
  export TIRTC_OPEN_API_ENDPOINT="<OPENAPI_ENDPOINT>"
104
+
105
+ node products/cli/bin/tirtc-devtools-cli.js --json token issue "$TIRTC_DEVICE_ID" \
106
+ --endpoint "$TIRTC_ENDPOINT" \
107
+ --openapi-endpoint "$TIRTC_OPEN_API_ENDPOINT" \
108
+ > .build/devtools-client-token.json
94
109
  ```
95
110
 
96
- Run one send role with the default prepared asset:
111
+ Run one device with the default prepared asset:
97
112
 
98
113
  ```sh
99
- node products/cli/bin/tirtc-devtools-cli.js --json send start \
114
+ node products/cli/bin/tirtc-devtools-cli.js --json device start \
100
115
  --video-codec h264 \
101
- --artifact-root .build/devtools-cli/send-h264
116
+ --artifact-root .build/devtools-cli/device-h264
102
117
  ```
103
118
 
104
- Run one send role from a prepared MP4:
119
+ Run one device from a prepared MP4 and write a local client bootstrap:
105
120
 
106
121
  ```sh
107
- node products/cli/bin/tirtc-devtools-cli.js --json send start \
122
+ node products/cli/bin/tirtc-devtools-cli.js --json device start \
108
123
  --source .build/tirtc-assets/manifest.json \
109
124
  --video-codec h264 \
110
- --artifact-root .build/devtools-cli/send-movie-h264
125
+ --client-token-json .build/devtools-client-token.json \
126
+ --artifact-root .build/devtools-cli/device-movie-h264
111
127
  ```
112
128
 
113
- By default `send start` keeps running until the process is stopped. Use
129
+ By default `device start` keeps running until the process is stopped. Use
114
130
  `--duration-ms <ms>` only for bounded automation. Prepared assets loop over the
115
131
  full audio/video source cycle; when either track reaches the source end, both
116
132
  tracks restart from offset 0 while PTS keeps increasing.
117
133
 
118
- The send role writes `bootstrap.json`. That file is a local handoff artifact for
119
- CLI receive, runtime sample smoke, and validation automation. The token in that
120
- bootstrap is intended for one receive connection.
134
+ `device start` writes `bootstrap.json` only when `--client-token-json` is
135
+ provided. That file is a local handoff artifact for CLI client, runtime sample
136
+ smoke, and validation automation. The token in that bootstrap is intended for
137
+ one client connection.
121
138
 
122
139
  `bootstrap.json` is not a mobile SDK connection protocol. For phone debugging,
123
140
  use token/license QR today; a full session QR or deeplink is a separate product
124
141
  slice.
125
142
 
126
- ## Receive
143
+ ## Client
127
144
 
128
145
  ```sh
129
- node products/cli/bin/tirtc-devtools-cli.js --json receive start \
130
- --bootstrap .build/devtools-cli/send-h264/bootstrap.json \
131
- --artifact-root .build/devtools-cli/receive-h264
146
+ node products/cli/bin/tirtc-devtools-cli.js --json client start \
147
+ --bootstrap .build/devtools-cli/device-h264/bootstrap.json \
148
+ --artifact-root .build/devtools-cli/client-h264
132
149
  ```
133
150
 
134
- Receive writes `summary.json`, `events.jsonl`, runtime logs, and `render/first-video-frame.*` for `frame_dump`.
151
+ Client writes `summary.json`, `events.jsonl`, runtime logs, and `render/first-video-frame.*` for `frame_dump`.
135
152
 
136
- `receive start --bootstrap` is meant for the local computer-to-computer DevTools
153
+ `client start --bootstrap` is meant for the local computer-to-computer DevTools
137
154
  flow. Mobile clients should not be required to fetch a local JSON file from the
138
155
  developer machine.
139
156
 
@@ -145,4 +162,4 @@ For the current macOS gate, use the native capability runner:
145
162
  products/devtools/driver/script/run_capability_probe.sh
146
163
  ```
147
164
 
148
- It runs H264, H265, and MJPEG send+receive with a fresh token per case.
165
+ It runs H264, H265, and MJPEG device+client with a fresh token per case.
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const embedded_paths_1 = require("./embedded_paths");
10
10
  const media_assets_1 = require("./media_assets");
11
+ const progress_1 = require("./progress");
11
12
  const token_command_1 = require("./token_command");
12
13
  const role_driver_1 = require("./role_driver");
13
14
  function resolveCliVersion() {
@@ -69,12 +70,19 @@ function printError(error, options) {
69
70
  return 1;
70
71
  }
71
72
  async function runAssetsPrepare(commandOptions, options) {
73
+ const progress = new progress_1.ProgressIndicator();
74
+ progress.start('Preparing media assets');
72
75
  try {
73
76
  const result = await (0, media_assets_1.prepareMediaAssets)({
74
77
  source: commandOptions.source ?? 'runtime/assets/source.mp4',
75
78
  outputRoot: commandOptions.outputRoot ?? 'runtime/assets/.workspace',
76
79
  overwrite: false,
80
+ }, {
81
+ progress: (message) => {
82
+ progress.update(message);
83
+ },
77
84
  });
85
+ progress.succeed(result.cache_hit ? 'Media assets cache hit' : 'Prepared media assets');
78
86
  if (options.json) {
79
87
  console.log(JSON.stringify({ code: 0, message: 'OK', data: result }));
80
88
  }
@@ -84,6 +92,7 @@ async function runAssetsPrepare(commandOptions, options) {
84
92
  return 0;
85
93
  }
86
94
  catch (error) {
95
+ progress.fail('Media assets prepare failed');
87
96
  return printError(error, options);
88
97
  }
89
98
  }
@@ -97,48 +106,53 @@ program.name('tirtc-devtools-cli')
97
106
  const assets = program.command('assets').description('准备 DevTools driver 使用的媒体资产');
98
107
  assets.command('prepare')
99
108
  .description('准备默认 runtime assets 或把显式 source 写入 output root')
100
- .option('--source <path>', '输入 MP4 路径;send start 使用输出的 manifest_path')
109
+ .option('--source <path>', '输入 MP4 路径;device start 使用输出的 manifest_path')
101
110
  .option('--output-root <dir>', 'prepared assets 输出根目录')
102
111
  .addHelpText('after', `
103
112
  Examples:
104
113
  $ tirtc-devtools-cli --json assets prepare --source ./movie.mp4 --output-root .build/tirtc-assets
105
- $ tirtc-devtools-cli --json send start --source .build/tirtc-assets/manifest.json --video-codec h264
114
+ $ tirtc-devtools-cli --json device start --source .build/tirtc-assets/manifest.json --video-codec h264
106
115
  `)
107
116
  .action((commandOptions) => {
108
117
  runAndExit(runAssetsPrepare(commandOptions, getCliOptions()));
109
118
  });
110
- const send = program.command('send').description('作为标准上行端运行 native DevTools driver');
111
- send.command('start')
112
- .description('启动 send role,产出 bootstrap.json 与 summary.json')
113
- .option('--execution-id <id>', 'runtime validation execution id')
114
- .option('--case-id <id>', 'runtime validation case id')
115
- .option('--app-id <id>', 'runtime validation app id')
119
+ const device = program.command('device').description('作为标准上行 device 运行 native DevTools driver');
120
+ device.command('start')
121
+ .description('启动上行 device,读取 prepared asset 并送出音视频')
116
122
  .option('--artifact-root <dir>', 'artifact 输出目录')
117
- .option('--remote-id <id>', 'server remote id;默认读取 TIRTC_DEVICE_ID')
123
+ .option('--device-id <id>', 'device id;不传时读取 TIRTC_DEVICE_ID')
124
+ .option('--device-secret-key <key>', 'device secret key;不传时读取 TIRTC_DEVICE_SECRET_KEY')
125
+ .option('--endpoint <url>', 'TiRTC endpoint;不传时读取 TIRTC_ENDPOINT')
118
126
  .option('--source <path>', 'prepared asset root、manifest_path 或 encoded track;MP4 先运行 assets prepare')
119
127
  .option('--video-codec <codec>', 'h264|h265|mjpeg', 'h264')
120
128
  .option('--duration-ms <ms>', '可选自动结束时长;默认持续运行直到用户结束进程')
121
129
  .option('--connect-timeout-ms <ms>', 'service ready / connect 最大等待')
122
130
  .option('--first-packet-timeout-ms <ms>', '首包最大等待')
123
- .option('--bootstrap-token-json <path>', 'script/issue_devtools_token.sh --json 输出文件')
131
+ .option('--client-token-json <path>', 'token issue --json 输出文件;传入时写出本机 bootstrap.json')
124
132
  .addHelpText('after', `
125
133
  Examples:
126
134
  $ tirtc-devtools-cli --json assets prepare --source ./movie.mp4 --output-root .build/tirtc-assets
127
- $ tirtc-devtools-cli --json send start --source .build/tirtc-assets/manifest.json --artifact-root .build/tirtc-send
135
+ $ tirtc-devtools-cli --json device start --source .build/tirtc-assets/manifest.json --artifact-root .build/tirtc-device
128
136
 
129
- bootstrap.json is a local handoff artifact for receive/sample/validation automation.
137
+ device start requires device id, device secret key, and endpoint.
138
+ Missing flags are read from TIRTC_DEVICE_ID, TIRTC_DEVICE_SECRET_KEY, and TIRTC_ENDPOINT.
139
+
140
+ bootstrap.json is a local handoff artifact for client/sample/validation automation.
141
+ It is only written when --client-token-json is provided.
130
142
  It is not a mobile SDK connection protocol.
131
143
  `)
132
144
  .action((commandOptions) => {
133
- runAndExit((0, role_driver_1.runSendStart)(commandOptions, getCliOptions()));
145
+ runAndExit((0, role_driver_1.runDeviceStart)(commandOptions, getCliOptions()));
134
146
  });
135
- const receive = program.command('receive').description('作为标准下行端运行 native DevTools driver');
136
- receive.command('start')
137
- .description('启动 receive role,消费 bootstrap 或显式 identity 并产出 frame_dump')
147
+ const client = program.command('client').description('作为标准下行 client 运行 native DevTools driver');
148
+ client.command('start')
149
+ .description('启动下行 client,消费 bootstrap 或显式 token 并产出 frame_dump')
138
150
  .option('--artifact-root <dir>', 'artifact 输出目录')
139
- .option('--bootstrap <path>', 'send role 产出的 bootstrap.json')
140
- .option('--remote-id <id>', '显式 remote id;优先于 bootstrap')
151
+ .option('--bootstrap <path>', 'device start 产出的 bootstrap.json')
152
+ .option('--target-device-id <id>', '目标 device id;优先于 bootstrap')
141
153
  .option('--token <token>', '显式 token;优先于 bootstrap')
154
+ .option('--endpoint <url>', 'TiRTC endpoint;优先于 bootstrap')
155
+ .option('--app-id <id>', 'client connect app id;不传时读取 bootstrap 或 TIRTC_APP_ID')
142
156
  .option('--audio-stream-id <id>', '音频 stream id')
143
157
  .option('--video-stream-id <id>', '视频 stream id')
144
158
  .option('--consumer <consumer>', 'packet_dump|frame_dump', 'frame_dump')
@@ -149,12 +163,12 @@ receive.command('start')
149
163
  .option('--first-output-timeout-ms <ms>', '首帧输出最大等待')
150
164
  .addHelpText('after', `
151
165
  Examples:
152
- $ tirtc-devtools-cli --json receive start --bootstrap .build/tirtc-send/bootstrap.json
166
+ $ tirtc-devtools-cli --json client start --bootstrap .build/tirtc-device/bootstrap.json
153
167
 
154
- bootstrap.json is expected to come from a local send start run.
168
+ bootstrap.json is expected to come from a local device start run.
155
169
  For mobile device debugging, use token/license QR or a future session QR/deeplink.
156
170
  `)
157
171
  .action((commandOptions) => {
158
- runAndExit((0, role_driver_1.runReceiveStart)(commandOptions, getCliOptions()));
172
+ runAndExit((0, role_driver_1.runClientStart)(commandOptions, getCliOptions()));
159
173
  });
160
174
  program.parse(process.argv);
@@ -17,9 +17,11 @@ type ExecFileLike = (file: string, args: string[], options: {
17
17
  stdout?: string | Buffer;
18
18
  stderr?: string | Buffer;
19
19
  }>;
20
+ type ProgressCallback = (message: string) => void;
20
21
  type PrepareMediaAssetsOptions = {
21
22
  repoRoot?: string;
22
23
  execFile?: ExecFileLike;
24
+ progress?: ProgressCallback;
23
25
  };
24
26
  export declare function prepareMediaAssets(request: PrepareMediaAssetsRequest, options?: PrepareMediaAssetsOptions): Promise<PrepareMediaAssetsResult>;
25
27
  export {};
@@ -18,6 +18,9 @@ class PrepareMediaAssetsError extends Error {
18
18
  this.reasonCode = reasonCode;
19
19
  }
20
20
  }
21
+ const prepareProgressPrefix = '[prepare_runtime_media_dataset] progress: ';
22
+ const prepareErrorPrefix = '[prepare_runtime_media_dataset] error: ';
23
+ const prepareExecMaxBuffer = 10 * 1024 * 1024;
21
24
  function resolveRepoRoot(fromDir) {
22
25
  const candidates = [
23
26
  path_1.default.resolve(fromDir, '../../..'),
@@ -44,9 +47,43 @@ function resolvePrepareScript(repoRoot) {
44
47
  }
45
48
  return path_1.default.join(repoRoot, 'runtime/script/prepare_runtime_media_dataset.sh');
46
49
  }
50
+ function appendBounded(chunks, text, currentSize, maxSize) {
51
+ const nextSize = currentSize + Buffer.byteLength(text);
52
+ if (nextSize > maxSize) {
53
+ throw new Error('media assets prepare output exceeded buffer limit');
54
+ }
55
+ chunks.push(text);
56
+ return nextSize;
57
+ }
58
+ function emitProgressLine(line, progress) {
59
+ if (!progress || !line.startsWith(prepareProgressPrefix)) {
60
+ return;
61
+ }
62
+ const message = line.slice(prepareProgressPrefix.length).trim();
63
+ if (message.length > 0) {
64
+ progress(message);
65
+ }
66
+ }
67
+ function emitBufferedProgress(stderr, progress) {
68
+ if (!stderr || !progress) {
69
+ return;
70
+ }
71
+ String(stderr)
72
+ .split(/\r?\n/)
73
+ .forEach((line) => {
74
+ emitProgressLine(line, progress);
75
+ });
76
+ }
77
+ function stripProgressLines(message) {
78
+ const lines = message.split(/\r?\n/);
79
+ const nonProgressLines = lines.filter((line) => !line.startsWith(prepareProgressPrefix));
80
+ const cleaned = nonProgressLines.join('\n').trim();
81
+ return cleaned.length > 0 ? cleaned : message.trim();
82
+ }
47
83
  function normalizeExecErrorMessage(message) {
48
- const prefix = '[prepare_runtime_media_dataset] error: ';
49
- const normalized = message.startsWith(prefix) ? message.slice(prefix.length).trim() : message;
84
+ const cleaned = stripProgressLines(message);
85
+ const errorLine = cleaned.split(/\r?\n/).find((line) => line.startsWith(prepareErrorPrefix));
86
+ const normalized = errorLine ? errorLine.slice(prepareErrorPrefix.length).trim() : cleaned;
50
87
  const reasonMatch = normalized.match(/^([a-z][a-z0-9_]*):\s*(.+)$/);
51
88
  if (reasonMatch) {
52
89
  return {
@@ -56,11 +93,14 @@ function normalizeExecErrorMessage(message) {
56
93
  }
57
94
  return { message: normalized };
58
95
  }
59
- function parseExecError(error) {
96
+ function parseExecError(error, progress) {
60
97
  if (!error || typeof error !== 'object') {
61
98
  return normalizeExecErrorMessage(String(error));
62
99
  }
63
100
  const typed = error;
101
+ if (!typed.progressEmitted) {
102
+ emitBufferedProgress(typed.stderr, progress);
103
+ }
64
104
  const stderr = typeof typed.stderr === 'string' ? typed.stderr.trim() : typed.stderr?.toString('utf8').trim();
65
105
  if (stderr && stderr.length > 0) {
66
106
  return normalizeExecErrorMessage(stderr);
@@ -85,6 +125,74 @@ function assertPrepareRequest(request) {
85
125
  throw new Error('media assets prepare requires non-empty --output-dir when provided');
86
126
  }
87
127
  }
128
+ function execPrepareWithProgress(file, args, options) {
129
+ return new Promise((resolve, reject) => {
130
+ const child = (0, child_process_1.spawn)(file, args, {
131
+ cwd: options.cwd,
132
+ env: options.env,
133
+ stdio: ['ignore', 'pipe', 'pipe'],
134
+ });
135
+ const stdoutChunks = [];
136
+ const stderrChunks = [];
137
+ let stdoutSize = 0;
138
+ let stderrSize = 0;
139
+ let stderrLineBuffer = '';
140
+ let settled = false;
141
+ function rejectOnce(error) {
142
+ if (settled) {
143
+ return;
144
+ }
145
+ settled = true;
146
+ child.kill();
147
+ reject(error);
148
+ }
149
+ child.stdout.on('data', (chunk) => {
150
+ try {
151
+ stdoutSize = appendBounded(stdoutChunks, chunk.toString('utf8'), stdoutSize, options.maxBuffer);
152
+ }
153
+ catch (error) {
154
+ rejectOnce(error instanceof Error ? error : new Error(String(error)));
155
+ }
156
+ });
157
+ child.stderr.on('data', (chunk) => {
158
+ const text = chunk.toString('utf8');
159
+ try {
160
+ stderrSize = appendBounded(stderrChunks, text, stderrSize, options.maxBuffer);
161
+ }
162
+ catch (error) {
163
+ rejectOnce(error instanceof Error ? error : new Error(String(error)));
164
+ return;
165
+ }
166
+ stderrLineBuffer += text;
167
+ const lines = stderrLineBuffer.split(/\r?\n/);
168
+ stderrLineBuffer = lines.pop() ?? '';
169
+ lines.forEach((line) => {
170
+ emitProgressLine(line, options.progress);
171
+ });
172
+ });
173
+ child.on('error', (error) => {
174
+ rejectOnce(error);
175
+ });
176
+ child.on('close', (code, signal) => {
177
+ if (settled) {
178
+ return;
179
+ }
180
+ settled = true;
181
+ if (stderrLineBuffer.length > 0) {
182
+ emitProgressLine(stderrLineBuffer, options.progress);
183
+ }
184
+ const stdout = stdoutChunks.join('');
185
+ const stderr = stderrChunks.join('');
186
+ if (code === 0) {
187
+ resolve({ stdout, stderr });
188
+ return;
189
+ }
190
+ const error = new Error(signal ? `process killed by signal ${signal}` : `process exited with code ${code}`);
191
+ Object.assign(error, { stdout, stderr, progressEmitted: true });
192
+ reject(error);
193
+ });
194
+ });
195
+ }
88
196
  async function prepareMediaAssets(request, options = {}) {
89
197
  assertPrepareRequest(request);
90
198
  const repoRoot = options.repoRoot ? path_1.default.resolve(options.repoRoot) : resolveDefaultRepoRoot();
@@ -108,18 +216,28 @@ async function prepareMediaAssets(request, options = {}) {
108
216
  }
109
217
  let stdout = '';
110
218
  try {
111
- const result = await execFile('bash', [scriptPath, ...args], {
219
+ const execOptions = {
112
220
  cwd: repoRoot,
113
221
  env: {
114
222
  ...process.env,
115
223
  TIRTC_ENSURE_FFMPEG_SCRIPT: ensureFfmpegScriptPath,
116
224
  },
117
- maxBuffer: 10 * 1024 * 1024,
118
- });
225
+ maxBuffer: prepareExecMaxBuffer,
226
+ };
227
+ const useStreamingProgress = options.progress && !options.execFile;
228
+ const result = useStreamingProgress
229
+ ? await execPrepareWithProgress('bash', [scriptPath, ...args], {
230
+ ...execOptions,
231
+ progress: options.progress,
232
+ })
233
+ : await execFile('bash', [scriptPath, ...args], execOptions);
234
+ if (!useStreamingProgress) {
235
+ emitBufferedProgress(result.stderr, options.progress);
236
+ }
119
237
  stdout = String(result.stdout ?? '').trim();
120
238
  }
121
239
  catch (error) {
122
- const parsed = parseExecError(error);
240
+ const parsed = parseExecError(error, options.progress);
123
241
  throw new PrepareMediaAssetsError(parsed.message, parsed.reasonCode);
124
242
  }
125
243
  let parsed;
@@ -1,24 +1,25 @@
1
1
  export type CliOptions = {
2
2
  json?: boolean;
3
3
  };
4
- type SendCommandOptions = {
5
- executionId?: string;
6
- caseId?: string;
7
- appId?: string;
4
+ type DeviceCommandOptions = {
8
5
  artifactRoot?: string;
9
- remoteId?: string;
6
+ deviceId?: string;
7
+ deviceSecretKey?: string;
8
+ endpoint?: string;
10
9
  source?: string;
11
10
  videoCodec?: string;
12
11
  durationMs?: string;
13
12
  connectTimeoutMs?: string;
14
13
  firstPacketTimeoutMs?: string;
15
- bootstrapTokenJson?: string;
14
+ clientTokenJson?: string;
16
15
  };
17
- type ReceiveCommandOptions = {
16
+ type ClientCommandOptions = {
18
17
  artifactRoot?: string;
19
18
  bootstrap?: string;
20
- remoteId?: string;
19
+ targetDeviceId?: string;
21
20
  token?: string;
21
+ endpoint?: string;
22
+ appId?: string;
22
23
  audioStreamId?: string;
23
24
  videoStreamId?: string;
24
25
  consumer?: string;
@@ -28,6 +29,6 @@ type ReceiveCommandOptions = {
28
29
  firstPacketTimeoutMs?: string;
29
30
  firstOutputTimeoutMs?: string;
30
31
  };
31
- export declare function runSendStart(commandOptions: SendCommandOptions, options: CliOptions): Promise<number>;
32
- export declare function runReceiveStart(commandOptions: ReceiveCommandOptions, options: CliOptions): Promise<number>;
32
+ export declare function runDeviceStart(commandOptions: DeviceCommandOptions, options: CliOptions): Promise<number>;
33
+ export declare function runClientStart(commandOptions: ClientCommandOptions, options: CliOptions): Promise<number>;
33
34
  export {};
@@ -3,15 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runSendStart = runSendStart;
7
- exports.runReceiveStart = runReceiveStart;
6
+ exports.runDeviceStart = runDeviceStart;
7
+ exports.runClientStart = runClientStart;
8
8
  const child_process_1 = __importDefault(require("child_process"));
9
9
  const crypto_1 = __importDefault(require("crypto"));
10
10
  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 token_tool_1 = require("./token_tool");
15
14
  const defaultAudioStreamId = 10;
16
15
  const defaultVideoStreamId = 11;
17
16
  const defaultConnectTimeoutMs = 10000;
@@ -142,13 +141,6 @@ function parseOptionalPositiveInt(raw, name) {
142
141
  }
143
142
  return parsePositiveInt(raw, 1, name);
144
143
  }
145
- function requireEnv(name) {
146
- const value = process.env[name]?.trim();
147
- if (!value) {
148
- throw rolePreflightError('missing_env', 'missing environment: ' + name);
149
- }
150
- return value;
151
- }
152
144
  function executionSuffix() {
153
145
  return new Date().toISOString().replace(/[-:.TZ]/g, '').slice(0, 14);
154
146
  }
@@ -211,10 +203,30 @@ function readTokenIssueJson(filePath) {
211
203
  appId: trimOptional(parsed.data?.payload?.app_id),
212
204
  };
213
205
  }
206
+ function resolveDeviceIdentity(options) {
207
+ const deviceId = trimOptional(options.deviceId) ?? trimOptional(process.env.TIRTC_DEVICE_ID);
208
+ const deviceSecretKey = trimOptional(options.deviceSecretKey) ??
209
+ trimOptional(process.env.TIRTC_DEVICE_SECRET_KEY);
210
+ const endpoint = trimOptional(options.endpoint) ?? trimOptional(process.env.TIRTC_ENDPOINT);
211
+ const missing = [];
212
+ if (!deviceId) {
213
+ missing.push('device id (pass --device-id or set TIRTC_DEVICE_ID)');
214
+ }
215
+ if (!deviceSecretKey) {
216
+ missing.push('device secret key (pass --device-secret-key or set TIRTC_DEVICE_SECRET_KEY)');
217
+ }
218
+ if (!endpoint) {
219
+ missing.push('endpoint (pass --endpoint or set TIRTC_ENDPOINT)');
220
+ }
221
+ if (missing.length > 0 || !deviceId || !deviceSecretKey || !endpoint) {
222
+ throw rolePreflightError('missing_env', 'device start requires ' + missing.join(' and '));
223
+ }
224
+ return { deviceId, deviceSecretKey, endpoint };
225
+ }
214
226
  function readBootstrap(bootstrapPath) {
215
227
  const resolved = path_1.default.resolve(bootstrapPath);
216
228
  const parsed = readJson(resolved);
217
- if (parsed.schema_version !== 1 || !parsed.remote_id || !parsed.token) {
229
+ if (parsed.schema_version !== 1 || !(parsed.device_id || parsed.remote_id) || !parsed.token) {
218
230
  throw roleUsageError('bootstrap_invalid');
219
231
  }
220
232
  return parsed;
@@ -277,62 +289,27 @@ function printEnvelope(options, code, message, data) {
277
289
  }
278
290
  }
279
291
  }
280
- async function buildSendRequest(roots, artifactRoot, options) {
292
+ function buildDeviceRequest(roots, artifactRoot, options) {
281
293
  const codec = codecOrDefault(options.videoCodec);
282
- const executionId = trimOptional(options.executionId) ?? 'cli-send-' + codec + '-' + executionSuffix();
283
- const caseId = trimOptional(options.caseId) ?? 'devtools-cli-send.' + codec;
284
- let remoteId = trimOptional(options.remoteId);
285
- let endpoint = trimOptional(process.env.TIRTC_ENDPOINT);
286
- let appId = trimOptional(options.appId) ?? trimOptional(process.env.TIRTC_APP_ID);
287
- let token;
288
- try {
289
- if (options.bootstrapTokenJson) {
290
- const tokenIssue = readTokenIssueJson(options.bootstrapTokenJson);
291
- token = tokenIssue.token;
292
- remoteId = remoteId ?? tokenIssue.remoteId;
293
- endpoint = tokenIssue.endpoint ?? endpoint;
294
- appId = appId ?? tokenIssue.appId;
295
- }
296
- else {
297
- remoteId = remoteId ?? requireEnv('TIRTC_DEVICE_ID');
298
- appId = appId ?? requireEnv('TIRTC_APP_ID');
299
- token = await (0, token_tool_1.issueToken)({
300
- accessId: requireEnv('TIRTC_ACCESS_KEY_ID'),
301
- secretKey: requireEnv('TIRTC_SECRET_KEY_ID'),
302
- appId,
303
- remoteId,
304
- openapiEndpoint: process.env.TIRTC_OPEN_API_ENDPOINT || process.env.TIRTC_OPENAPI_ENDPOINT,
305
- endpoint,
306
- });
307
- }
308
- }
309
- catch (error) {
310
- if (error instanceof RoleCommandError) {
311
- throw error;
312
- }
313
- const detail = error instanceof Error ? error.message : String(error);
314
- throw rolePreflightError('token_issue_failed', detail);
315
- }
316
- remoteId = remoteId ?? requireEnv('TIRTC_DEVICE_ID');
317
- endpoint = endpoint ?? requireEnv('TIRTC_ENDPOINT');
318
- appId = appId ?? requireEnv('TIRTC_APP_ID');
319
- if (!token) {
320
- throw rolePreflightError('token_issue_invalid', 'missing client token');
321
- }
294
+ const executionId = 'cli-device-' + codec + '-' + executionSuffix();
295
+ const caseId = 'devtools-cli-device.' + codec;
296
+ const deviceIdentity = resolveDeviceIdentity(options);
297
+ const tokenIssue = options.clientTokenJson ? readTokenIssueJson(options.clientTokenJson) : undefined;
298
+ const bootstrap = tokenIssue ? {
299
+ client_token: tokenIssue.token,
300
+ token_fingerprint: tokenFingerprint(tokenIssue.token),
301
+ } : undefined;
322
302
  return {
323
303
  schema_version: 1,
324
304
  execution_id: executionId,
325
305
  case_id: caseId,
326
- role: 'send',
327
- endpoint,
306
+ role: 'device',
307
+ endpoint: deviceIdentity.endpoint,
328
308
  identity: {
329
- license: remoteId + ',' + requireEnv('TIRTC_DEVICE_SECRET_KEY'),
330
- remote_id: remoteId,
331
- },
332
- bootstrap: {
333
- client_token: token,
334
- token_fingerprint: tokenFingerprint(token),
309
+ license: deviceIdentity.deviceId + ',' + deviceIdentity.deviceSecretKey,
310
+ device_id: deviceIdentity.deviceId,
335
311
  },
312
+ bootstrap,
336
313
  streams: {
337
314
  audio_stream_id: defaultAudioStreamId,
338
315
  video_stream_id: defaultVideoStreamId,
@@ -349,30 +326,49 @@ async function buildSendRequest(roots, artifactRoot, options) {
349
326
  first_output_timeout_ms: defaultFirstOutputTimeoutMs,
350
327
  },
351
328
  artifact: { root_dir: artifactRoot },
352
- probe: { app_id: appId },
329
+ probe: { app_id: tokenIssue?.appId ?? '' },
353
330
  };
354
331
  }
355
- function buildReceiveRequest(roots, artifactRoot, options) {
332
+ function buildClientRequest(roots, artifactRoot, options) {
356
333
  const bootstrap = options.bootstrap ? readBootstrap(options.bootstrap) : undefined;
357
- const remoteId = options.remoteId?.trim() || bootstrap?.remote_id || process.env.TIRTC_REMOTE_ID?.trim() || process.env.TIRTC_DEVICE_ID?.trim();
334
+ const targetDeviceId = trimOptional(options.targetDeviceId) ??
335
+ trimOptional(bootstrap?.device_id) ??
336
+ trimOptional(bootstrap?.remote_id) ??
337
+ trimOptional(process.env.TIRTC_TARGET_DEVICE_ID);
358
338
  const token = options.token?.trim() || bootstrap?.token || process.env.TIRTC_TOKEN?.trim();
359
- if (!remoteId) {
360
- throw rolePreflightError('missing_env', 'missing remote id: pass --remote-id, --bootstrap, or TIRTC_REMOTE_ID');
339
+ const endpoint = trimOptional(options.endpoint) ??
340
+ trimOptional(bootstrap?.endpoint) ??
341
+ trimOptional(process.env.TIRTC_ENDPOINT);
342
+ const appId = trimOptional(options.appId) ??
343
+ trimOptional(bootstrap?.app_id) ??
344
+ trimOptional(process.env.TIRTC_APP_ID);
345
+ const missing = [];
346
+ if (!targetDeviceId) {
347
+ missing.push('target device id (pass --target-device-id, --bootstrap, or set TIRTC_TARGET_DEVICE_ID)');
361
348
  }
362
349
  if (!token) {
363
- throw rolePreflightError('missing_env', 'missing token: pass --token, --bootstrap, or TIRTC_TOKEN');
350
+ missing.push('token (pass --token, --bootstrap, or set TIRTC_TOKEN)');
364
351
  }
365
- const executionId = 'cli-receive-' + executionSuffix();
366
- const identityOverride = Boolean(bootstrap && (options.remoteId || options.token));
352
+ if (!endpoint) {
353
+ missing.push('endpoint (pass --endpoint, --bootstrap, or set TIRTC_ENDPOINT)');
354
+ }
355
+ if (!appId) {
356
+ missing.push('app id (pass --app-id, --bootstrap, or set TIRTC_APP_ID)');
357
+ }
358
+ if (missing.length > 0 || !targetDeviceId || !token || !endpoint || !appId) {
359
+ throw rolePreflightError('missing_env', 'client start requires ' + missing.join(' and '));
360
+ }
361
+ const executionId = 'cli-client-' + executionSuffix();
362
+ const identityOverride = Boolean(bootstrap && (options.targetDeviceId || options.token));
367
363
  const videoCodec = codecOrDefault(bootstrap?.video_codec);
368
364
  return {
369
365
  schema_version: 1,
370
366
  execution_id: executionId,
371
- case_id: 'devtools-cli-receive',
372
- role: 'receive',
373
- endpoint: process.env.TIRTC_ENDPOINT?.trim() || bootstrap?.endpoint || '',
367
+ case_id: 'devtools-cli-client',
368
+ role: 'client',
369
+ endpoint,
374
370
  identity: {
375
- remote_id: remoteId,
371
+ device_id: targetDeviceId,
376
372
  token,
377
373
  bootstrap_path: options.bootstrap ? path_1.default.resolve(options.bootstrap) : undefined,
378
374
  bootstrap_id: bootstrap?.bootstrap_id,
@@ -397,7 +393,7 @@ function buildReceiveRequest(roots, artifactRoot, options) {
397
393
  first_output_timeout_ms: parsePositiveInt(options.firstOutputTimeoutMs, defaultFirstOutputTimeoutMs, '--first-output-timeout-ms'),
398
394
  },
399
395
  artifact: { root_dir: artifactRoot },
400
- probe: { app_id: process.env.TIRTC_APP_ID?.trim() || bootstrap?.app_id || '' },
396
+ probe: { app_id: appId },
401
397
  };
402
398
  }
403
399
  function runDriver(request, artifactRoot, roots) {
@@ -460,15 +456,15 @@ async function runRole(role, commandOptions, options) {
460
456
  const artifactRoot = path_1.default.resolve(commandOptions.artifactRoot ?? defaultRoot);
461
457
  ensureDir(artifactRoot);
462
458
  try {
463
- const request = role === 'send' ?
464
- await buildSendRequest(roots, artifactRoot, commandOptions) :
465
- buildReceiveRequest(roots, artifactRoot, commandOptions);
459
+ const request = role === 'device' ?
460
+ buildDeviceRequest(roots, artifactRoot, commandOptions) :
461
+ buildClientRequest(roots, artifactRoot, commandOptions);
466
462
  const summary = runDriver(request, artifactRoot, roots);
467
463
  const summaryPath = path_1.default.join(artifactRoot, 'summary.json');
468
464
  const data = {
469
465
  status: summary.status,
470
466
  exit_code: summary.exit_code,
471
- role: summary.role,
467
+ role,
472
468
  execution_id: summary.execution_id,
473
469
  artifact_root: artifactRoot,
474
470
  summary_path: summaryPath,
@@ -497,9 +493,9 @@ async function runRole(role, commandOptions, options) {
497
493
  return normalized.exitCode;
498
494
  }
499
495
  }
500
- function runSendStart(commandOptions, options) {
501
- return runRole('send', commandOptions, options);
496
+ function runDeviceStart(commandOptions, options) {
497
+ return runRole('device', commandOptions, options);
502
498
  }
503
- function runReceiveStart(commandOptions, options) {
504
- return runRole('receive', commandOptions, options);
499
+ function runClientStart(commandOptions, options) {
500
+ return runRole('client', commandOptions, options);
505
501
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirtc-devtools-cli",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "main": "dist/cli/src/index.js",
6
6
  "types": "dist/cli/src/index.d.ts",
@@ -91,6 +91,28 @@ typedef enum TirtcError {
91
91
  TIRTC_ERROR_VIDEO_DECODER_INPUT_PENDING = 6081,
92
92
  TIRTC_ERROR_VIDEO_DECODER_OUTPUT_PENDING = 6082,
93
93
  TIRTC_ERROR_MEDIA_UPLINK_INPUT_MODE_MISMATCH = 6083,
94
+ TIRTC_ERROR_TRANSPORT_CONNECT_INVOCATION_FAILED = 6084,
95
+ TIRTC_ERROR_TRANSPORT_DISCONNECT_STATE_UNEXPECTED = 6085,
96
+ TIRTC_ERROR_HTTP_TRANSPORT_FAILED = 6086,
97
+ TIRTC_ERROR_LOG_UPLOAD_ENDPOINT_RESPONSE_INVALID = 6087,
98
+ TIRTC_ERROR_LOG_UPLOAD_TOKEN_RESPONSE_INVALID = 6088,
99
+ TIRTC_ERROR_TRANSPORT_BACKEND_UNKNOWN_STATUS = 6089,
100
+ TIRTC_ERROR_TRANSPORT_BACKEND_CONNECTION_OTHER_ERROR = 6090,
101
+ TIRTC_ERROR_FACADE_HANDLE_UNAVAILABLE = 6091,
102
+ TIRTC_ERROR_AUDIO_PROCESSING_STATE_INVALID = 6092,
103
+ TIRTC_ERROR_AUDIO_PROCESSING_CONFIGURATION_FAILED = 6093,
104
+ TIRTC_ERROR_AUDIO_PROCESSING_PROCESS_FAILED = 6094,
105
+ TIRTC_ERROR_VIDEO_ENCODER_STATE_INVALID = 6095,
106
+ TIRTC_ERROR_VIDEO_ENCODER_INPUT_REJECTED = 6096,
107
+ TIRTC_ERROR_VIDEO_ENCODER_OUTPUT_RETRIEVE_FAILED = 6097,
108
+ TIRTC_ERROR_VIDEO_ENCODER_OUTPUT_CONVERSION_FAILED = 6098,
109
+ TIRTC_ERROR_VIDEO_ENCODER_CONTROL_REQUEST_FAILED = 6099,
110
+ TIRTC_ERROR_VIDEO_DECODER_STATE_INVALID = 6100,
111
+ TIRTC_ERROR_VIDEO_DECODER_INPUT_REJECTED = 6101,
112
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_RETRIEVE_FAILED = 6102,
113
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_CONVERSION_FAILED = 6103,
114
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_RELEASE_FAILED = 6104,
115
+ TIRTC_ERROR_TRANSPORT_BACKEND_NOT_INITIALIZED = 6105,
94
116
  } TirtcError;
95
117
 
96
118
  const char* tirtc_error_to_string(TirtcError error);
@@ -1,6 +1,6 @@
1
1
  platform=linux-x64
2
2
  profile=full
3
- staged_at_utc=2026-04-30T09:36:57Z
3
+ staged_at_utc=2026-04-30T14:15:15Z
4
4
  source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/linux-x64
5
5
 
6
6
  bfc096be1484ac2b1c2776ccabfa2a4c6a982e869abf875192ff06fad85e82ca include/tirtc/audio.h
@@ -14,7 +14,7 @@ c2e1f31dcc75be461c577d18b1cebe32774f212d51cb4dd2a5b5a9bfe62b693e include/tirtc/
14
14
  21f60729117260a44af22c1af986ef17d22673b102b7b7a035f492d0665cce16 include/tirtc/audio_processing.h
15
15
  0ca7c3c630b1242f51a0fd8154097c0a332b4c816a5707090e4381719852998c include/tirtc/audio_sample_rate.h
16
16
  58807ba56770f38f47aec995661cadf9d3c1d6ea7bfc940767f1ce67317c7546 include/tirtc/av.h
17
- 0f3e2f454c35e8c2f79bdc93ed77f9f1622751e5a05defa8c9d4213ed8a797c5 include/tirtc/error.h
17
+ b3e110ce04057d3be696b120d1abeaf6141711a1c63ca7f9bdf65ed5ec6e16d7 include/tirtc/error.h
18
18
  ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/foundation/build_info.h
19
19
  7cf8b372a3d48d4de4a65a04c7f102281a7b42cebb9ec247853d3c53afb63b6a include/tirtc/http.h
20
20
  70bbf93b84d9d1a85f376d9986de570c1f658319e1e5ab6d621f7a4d41033f5c include/tirtc/logging.h
@@ -33,13 +33,13 @@ cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/
33
33
  8cd6b66bea14890a665cc317f8572429b2c3e4463773f8b77c1e4dc30a4a8747 include/tirtc/video_processing.h
34
34
  ceb7cdd45efae57e5bd53d4177cb20c4a0cb9917fcdd23127b050d69c8b919ac lib/libTiRTC.a
35
35
  b1f4135025cb8e8520a14268d831b9998920a4239f84bb6b409d0e4909fd5bee lib/libcrypto.a
36
- 8e3aff3a400fe0971c61511947c0e69d06754002d970e21eaab2339ae38b4a42 lib/libmatrix_runtime_audio.a
37
- 09696896a45a4fab199f0767979471c947b252fc8741a0e803624cdac6953b59 lib/libmatrix_runtime_facade.a
38
- 2c8cc881eeeae679129360df5813dec17d0e33935f196d79cf79671dbd0c8581 lib/libmatrix_runtime_foundation_http.a
39
- e5aff9f5d9221b9cf08dd8a9144c6039d9dba7bdee3892af2d0e7f7d69633461 lib/libmatrix_runtime_foundation_logging.a
40
- fe6b5575ce5e80f81e07a7799a05d0a8ee5a338915a28ada86d9009eee952e96 lib/libmatrix_runtime_media.a
41
- 86d9b41f84c6bcc13f8d23a1f9b46d97fe6769573758722f9f6c8d4a130306be lib/libmatrix_runtime_transport.a
42
- 6ac178f5cd371e9a5be1989dd1e8a3767291f4c4d9d30dcf12ecdd75a2081afa lib/libmatrix_runtime_video.a
36
+ 296ba0b5efa9d2ac49e3bf278c5d467b31436e73fbc608b736e974bcf9759bde lib/libmatrix_runtime_audio.a
37
+ 88f9c545943e4ef80024baf3620e91817ec16a4fea60b0e8c7887a0a41dc9d1b lib/libmatrix_runtime_facade.a
38
+ ec7bbf8e8744c6645a441a28e24e0645906152cc987d6fcca16af3c3badba940 lib/libmatrix_runtime_foundation_http.a
39
+ 4038af89ac4dc7e7c99ac9ace58ce063661ddb3134f71664b79221ade4adb8d1 lib/libmatrix_runtime_foundation_logging.a
40
+ 9c7108b70cb442dee02cfdb4f98891a8a099f15c379e9e48cf53d7b276f6e894 lib/libmatrix_runtime_media.a
41
+ fc498c74804ef35dc3939a6368d9ae908b0e35578db32eb7902ad00107781295 lib/libmatrix_runtime_transport.a
42
+ 337d38891e264e76aeb61a4e25a3b0bad56ab26697948805e64dec920874093f lib/libmatrix_runtime_video.a
43
43
  511d521f7972df3993e5976d6e2dbcad7a6fbce9be15071274d0cbd9d51157f5 lib/libssl.a
44
44
  a67ec9034848ef24a1b17671e444daa62a8f9e6b8319a1e932593908720ff2a1 lib/libwebrtc_apm.a
45
45
  700e455255897e3cffab13ca593a6e4d9d11383ae609215cbbd6043a63d47161 lib/libxlog.a
@@ -91,6 +91,28 @@ typedef enum TirtcError {
91
91
  TIRTC_ERROR_VIDEO_DECODER_INPUT_PENDING = 6081,
92
92
  TIRTC_ERROR_VIDEO_DECODER_OUTPUT_PENDING = 6082,
93
93
  TIRTC_ERROR_MEDIA_UPLINK_INPUT_MODE_MISMATCH = 6083,
94
+ TIRTC_ERROR_TRANSPORT_CONNECT_INVOCATION_FAILED = 6084,
95
+ TIRTC_ERROR_TRANSPORT_DISCONNECT_STATE_UNEXPECTED = 6085,
96
+ TIRTC_ERROR_HTTP_TRANSPORT_FAILED = 6086,
97
+ TIRTC_ERROR_LOG_UPLOAD_ENDPOINT_RESPONSE_INVALID = 6087,
98
+ TIRTC_ERROR_LOG_UPLOAD_TOKEN_RESPONSE_INVALID = 6088,
99
+ TIRTC_ERROR_TRANSPORT_BACKEND_UNKNOWN_STATUS = 6089,
100
+ TIRTC_ERROR_TRANSPORT_BACKEND_CONNECTION_OTHER_ERROR = 6090,
101
+ TIRTC_ERROR_FACADE_HANDLE_UNAVAILABLE = 6091,
102
+ TIRTC_ERROR_AUDIO_PROCESSING_STATE_INVALID = 6092,
103
+ TIRTC_ERROR_AUDIO_PROCESSING_CONFIGURATION_FAILED = 6093,
104
+ TIRTC_ERROR_AUDIO_PROCESSING_PROCESS_FAILED = 6094,
105
+ TIRTC_ERROR_VIDEO_ENCODER_STATE_INVALID = 6095,
106
+ TIRTC_ERROR_VIDEO_ENCODER_INPUT_REJECTED = 6096,
107
+ TIRTC_ERROR_VIDEO_ENCODER_OUTPUT_RETRIEVE_FAILED = 6097,
108
+ TIRTC_ERROR_VIDEO_ENCODER_OUTPUT_CONVERSION_FAILED = 6098,
109
+ TIRTC_ERROR_VIDEO_ENCODER_CONTROL_REQUEST_FAILED = 6099,
110
+ TIRTC_ERROR_VIDEO_DECODER_STATE_INVALID = 6100,
111
+ TIRTC_ERROR_VIDEO_DECODER_INPUT_REJECTED = 6101,
112
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_RETRIEVE_FAILED = 6102,
113
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_CONVERSION_FAILED = 6103,
114
+ TIRTC_ERROR_VIDEO_DECODER_OUTPUT_RELEASE_FAILED = 6104,
115
+ TIRTC_ERROR_TRANSPORT_BACKEND_NOT_INITIALIZED = 6105,
94
116
  } TirtcError;
95
117
 
96
118
  const char* tirtc_error_to_string(TirtcError error);
@@ -1,6 +1,6 @@
1
1
  platform=macos-arm64
2
2
  profile=full
3
- staged_at_utc=2026-04-30T09:35:10Z
3
+ staged_at_utc=2026-04-30T14:13:34Z
4
4
  source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/macos-arm64
5
5
 
6
6
  bfc096be1484ac2b1c2776ccabfa2a4c6a982e869abf875192ff06fad85e82ca include/tirtc/audio.h
@@ -14,7 +14,7 @@ c2e1f31dcc75be461c577d18b1cebe32774f212d51cb4dd2a5b5a9bfe62b693e include/tirtc/
14
14
  21f60729117260a44af22c1af986ef17d22673b102b7b7a035f492d0665cce16 include/tirtc/audio_processing.h
15
15
  0ca7c3c630b1242f51a0fd8154097c0a332b4c816a5707090e4381719852998c include/tirtc/audio_sample_rate.h
16
16
  58807ba56770f38f47aec995661cadf9d3c1d6ea7bfc940767f1ce67317c7546 include/tirtc/av.h
17
- 0f3e2f454c35e8c2f79bdc93ed77f9f1622751e5a05defa8c9d4213ed8a797c5 include/tirtc/error.h
17
+ b3e110ce04057d3be696b120d1abeaf6141711a1c63ca7f9bdf65ed5ec6e16d7 include/tirtc/error.h
18
18
  ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/foundation/build_info.h
19
19
  7cf8b372a3d48d4de4a65a04c7f102281a7b42cebb9ec247853d3c53afb63b6a include/tirtc/http.h
20
20
  70bbf93b84d9d1a85f376d9986de570c1f658319e1e5ab6d621f7a4d41033f5c include/tirtc/logging.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
- 8196040f7450f650ebdfcb15abe5b08c0b7e2dcb93c9c8cb557e2a831fd032ae lib/libmatrix_runtime_audio.a
39
- 24dad84f6d7f29841cd73ef069d44d5bccf9db234bfd3adeda0ee048d1448509 lib/libmatrix_runtime_facade.a
40
- 12ccfbe34a6ed3496c9cbbdc9c58193daac90987b792eae3535743cfa76d0a67 lib/libmatrix_runtime_foundation_http.a
41
- caddced4a0d14c5256b1e53683e7655034ac57bbad0288b5a3d9451633470984 lib/libmatrix_runtime_foundation_logging.a
42
- 6f0ec3bb2586ac965c67692e8e746a030512a4f3622d2a92e5892aa8267a2e05 lib/libmatrix_runtime_media.a
43
- 31797ff96ad7a63a898e22b30c97be6cea5cd9f95bdd6354c6054666b1f96f37 lib/libmatrix_runtime_transport.a
44
- 6de3cc7602dd1da437fcf803f72d81b08a82b061bc743dcae8b72d838dfaf284 lib/libmatrix_runtime_video.a
38
+ 9466d90d68de9ea40a5ef2c5ff393fe94f3ec22f410dcc9c1707253344971a17 lib/libmatrix_runtime_audio.a
39
+ 8bc2920d99c7cf575af169baeba9725951d56d3891e2ba4bf50d99023ac4608c lib/libmatrix_runtime_facade.a
40
+ 3d3ef3d682052b7ab982b82597a3810e091ab4eb3a6b40177a88d60d0391d800 lib/libmatrix_runtime_foundation_http.a
41
+ e329006b0f653f338c22addb307bd5fca56163e8f6ab6adf3d8ce2fa83c28523 lib/libmatrix_runtime_foundation_logging.a
42
+ 1e7e5b699d3625d4ba3b514b21d43ca3915d6a3f15997a74de93d86509d4e58f lib/libmatrix_runtime_media.a
43
+ 7945859c05cbc4e55f95b1eee109e0f604d90ff3cbe69bb17e3932b6b094ad01 lib/libmatrix_runtime_transport.a
44
+ b93f5eec5e4fe4278c161095c3b3445f71f78898f4b293efc2b7299d18c91253 lib/libmatrix_runtime_video.a
45
45
  c11c65d373a127028350c41fa58cd2d1223f2b5d70a84e13b115d90daaba25ca lib/libssl.a
46
46
  ef1c1104bbdd2528ed7b958fb7252bd6249875f92300b0c9577d6c4bd6c0d88a lib/libssl.dylib
47
47
  e14e846e43d64e240fa0e5745bf4e702b79d0f2442e7f768beb990610735c71b lib/libtgrtc.dylib
@@ -20,6 +20,10 @@ fail() {
20
20
  exit 1
21
21
  }
22
22
 
23
+ progress() {
24
+ echo "[prepare_runtime_media_dataset] progress: $*" >&2
25
+ }
26
+
23
27
  require_cmd() {
24
28
  command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
25
29
  }
@@ -145,6 +149,7 @@ readonly k_audio_codec="g711a"
145
149
  readonly k_output_audio_format="pcm_s16"
146
150
  readonly k_output_video_format="rgba8888"
147
151
 
152
+ progress "checking source media streams"
148
153
  AUDIO_STREAM_PRESENT="$(
149
154
  AUDIO_STREAM_JSON="$("$FFPROBE_BIN" -v error -select_streams a:0 \
150
155
  -show_entries stream=index -of json "$SOURCE_ABS")" \
@@ -230,6 +235,7 @@ fi
230
235
  MANIFEST_PATH="$ASSETS_DIR/manifest.json"
231
236
 
232
237
  if [[ -f "$MANIFEST_PATH" && "$OVERWRITE" -ne 1 ]]; then
238
+ progress "using cached prepared media assets"
233
239
  emit_result "$ASSETS_DIR" "$MANIFEST_PATH" true
234
240
  exit 0
235
241
  fi
@@ -274,6 +280,7 @@ else
274
280
  video_encode_args+=(-crf 18)
275
281
  fi
276
282
 
283
+ progress "encoding h264 video track"
277
284
  "$FFMPEG_BIN" -hide_banner -loglevel error -y \
278
285
  -i "$SOURCE_ABS" \
279
286
  -an \
@@ -302,6 +309,7 @@ else
302
309
  video_h265_encode_args+=(-crf 23)
303
310
  fi
304
311
 
312
+ progress "encoding h265 video track"
305
313
  "$FFMPEG_BIN" -hide_banner -loglevel error -y \
306
314
  -i "$SOURCE_ABS" \
307
315
  -an \
@@ -311,6 +319,7 @@ fi
311
319
 
312
320
  mjpeg_frame_dir="$ASSETS_DIR/video/mjpeg_frames"
313
321
  mkdir -p "$mjpeg_frame_dir"
322
+ progress "extracting mjpeg video frames"
314
323
  "$FFMPEG_BIN" -hide_banner -loglevel error -y \
315
324
  -i "$SOURCE_ABS" \
316
325
  -vf "fps=1/${k_mjpeg_extract_interval_seconds},scale=${TARGET_VIDEO_WIDTH}:${TARGET_VIDEO_HEIGHT}:flags=lanczos" \
@@ -326,6 +335,7 @@ if ! find "$mjpeg_frame_dir" -type f -name 'frame_*.jpg' | grep -q .; then
326
335
  "$mjpeg_frame_dir/frame_000001.jpg"
327
336
  fi
328
337
 
338
+ progress "encoding 8k g711a audio track"
329
339
  "$FFMPEG_BIN" -hide_banner -loglevel error -y \
330
340
  -i "$SOURCE_ABS" \
331
341
  -vn \
@@ -335,6 +345,7 @@ fi
335
345
  -f alaw \
336
346
  "$AUDIO_PATH"
337
347
 
348
+ progress "encoding 16k g711a audio track"
338
349
  "$FFMPEG_BIN" -hide_banner -loglevel error -y \
339
350
  -i "$SOURCE_ABS" \
340
351
  -vn \
@@ -344,6 +355,7 @@ fi
344
355
  -f alaw \
345
356
  "$AUDIO_16K_PATH"
346
357
 
358
+ progress "indexing h264 video packets"
347
359
  VIDEO_PACKET_INDEX_PATH="$VIDEO_H264_PACKET_INDEX_PATH" \
348
360
  VIDEO_PATH="$VIDEO_H264_PATH" \
349
361
  VIDEO_FPS="$k_video_fps" \
@@ -441,6 +453,7 @@ for (let index = 0; index < packetOffsets.length; index += 1) {
441
453
  fs.writeFileSync(outputPath, `${lines.join('\n')}\n`, 'utf8');
442
454
  NODE
443
455
 
456
+ progress "indexing h265 video packets"
444
457
  VIDEO_PACKET_INDEX_PATH="$VIDEO_H265_PACKET_INDEX_PATH" \
445
458
  VIDEO_PATH="$VIDEO_H265_PATH" \
446
459
  VIDEO_FPS="$k_video_fps" \
@@ -538,6 +551,7 @@ for (let index = 0; index < packetOffsets.length; index += 1) {
538
551
  fs.writeFileSync(outputPath, `${lines.join('\n')}\n`, 'utf8');
539
552
  NODE
540
553
 
554
+ progress "indexing mjpeg video packets"
541
555
  VIDEO_MJPEG_PATH="$VIDEO_MJPEG_PATH" \
542
556
  VIDEO_MJPEG_PACKET_INDEX_PATH="$VIDEO_MJPEG_PACKET_INDEX_PATH" \
543
557
  MJPEG_FRAME_DIR="$mjpeg_frame_dir" \
@@ -593,6 +607,7 @@ for (let index = 0; index < packetCount; index += 1) {
593
607
  fs.writeFileSync(indexPath, `${lines.join('\n')}\n`, 'utf8');
594
608
  NODE
595
609
 
610
+ progress "indexing 8k g711a audio packets"
596
611
  AUDIO_BYTES="$(wc -c < "$AUDIO_PATH" | tr -d '[:space:]')"
597
612
  AUDIO_PACKET_BYTES=$((k_audio_sample_rate_hz * k_audio_packet_duration_ms / 1000))
598
613
  [[ "$AUDIO_PACKET_BYTES" -gt 0 ]] || fail "invalid audio packet bytes"
@@ -624,6 +639,7 @@ AUDIO_PACKET_COUNT=$((AUDIO_BYTES / AUDIO_PACKET_BYTES))
624
639
  done
625
640
  } > "$AUDIO_PACKET_INDEX_PATH"
626
641
 
642
+ progress "indexing 16k g711a audio packets"
627
643
  AUDIO_16K_BYTES="$(wc -c < "$AUDIO_16K_PATH" | tr -d '[:space:]')"
628
644
  AUDIO_16K_PACKET_BYTES=$((k_audio_sample_rate_16k_hz * k_audio_packet_duration_ms / 1000))
629
645
  [[ "$AUDIO_16K_PACKET_BYTES" -gt 0 ]] || fail "invalid 16k audio packet bytes"
@@ -655,6 +671,7 @@ AUDIO_16K_PACKET_COUNT=$((AUDIO_16K_BYTES / AUDIO_16K_PACKET_BYTES))
655
671
  done
656
672
  } > "$AUDIO_16K_PACKET_INDEX_PATH"
657
673
 
674
+ progress "writing prepared media manifest"
658
675
  cat > "$MANIFEST_PATH" <<JSON
659
676
  {
660
677
  "schema_version": ${k_schema_version},