@pickleball/expo-sdk 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +155 -101
- package/dist/advanced-DcbHBCGb.d.ts +300 -0
- package/dist/advanced-DeQwg7MK.d.cts +300 -0
- package/dist/advanced.cjs +14 -2
- package/dist/advanced.d.cts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.js +17 -5
- package/dist/camera-controls-By8tHigY.d.cts +97 -0
- package/dist/camera-controls-rCBUGGPC.d.ts +97 -0
- package/dist/chunk-62YV3PCD.cjs +139 -0
- package/dist/chunk-6F3HN6US.js +50 -0
- package/dist/chunk-6YE5BL3A.cjs +50 -0
- package/dist/chunk-7Z7TN5N3.js +318 -0
- package/dist/{chunk-TRLASNPQ.cjs → chunk-GXQYMPHE.cjs} +1 -1
- package/dist/{chunk-TBPR2QND.cjs → chunk-IUIRVKJI.cjs} +736 -399
- package/dist/chunk-TBUEXRFQ.cjs +318 -0
- package/dist/{chunk-FODE2W2H.js → chunk-XGP2MN5R.js} +688 -351
- package/dist/{chunk-6JOMESNT.js → chunk-XL4CISVQ.js} +1 -1
- package/dist/chunk-ZSKSXOCZ.js +139 -0
- package/dist/convex-command-subscription-Cabh9tND.d.ts +41 -0
- package/dist/convex-command-subscription-DUgpu75l.d.cts +41 -0
- package/dist/device-agent/index.cjs +973 -44
- package/dist/device-agent/index.d.cts +339 -3
- package/dist/device-agent/index.d.ts +339 -3
- package/dist/device-agent/index.js +940 -11
- package/dist/{engine-CCSSqPbZ.d.cts → engine-BSvSdCSE.d.cts} +227 -2
- package/dist/{engine-CCSSqPbZ.d.ts → engine-BSvSdCSE.d.ts} +227 -2
- package/dist/index.cjs +419 -937
- package/dist/index.d.cts +315 -32
- package/dist/index.d.ts +315 -32
- package/dist/index.js +423 -941
- package/dist/plugin.cjs +11 -13
- package/dist/plugin.d.cts +15 -1
- package/dist/plugin.d.ts +15 -1
- package/dist/plugin.js +7 -9
- package/dist/realtime/index.cjs +31 -0
- package/dist/realtime/index.d.cts +15 -0
- package/dist/realtime/index.d.ts +15 -0
- package/dist/realtime/index.js +31 -0
- package/dist/ui/index.cjs +1297 -0
- package/dist/ui/index.d.cts +493 -0
- package/dist/ui/index.d.ts +493 -0
- package/dist/ui/index.js +1297 -0
- package/dist/version.cjs +2 -2
- package/dist/version.js +1 -1
- package/package.json +31 -15
- package/src/advanced.ts +11 -9
- package/src/auto-resume.tsx +259 -0
- package/src/camera-controls.ts +99 -0
- package/src/camera-grant-provider.ts +392 -0
- package/src/camera-settings.ts +133 -0
- package/src/contracts.ts +73 -0
- package/src/device-agent/agent.ts +262 -9
- package/src/device-agent/beat-policy.ts +46 -0
- package/src/device-agent/component.tsx +11 -0
- package/src/device-agent/convex-beat-transport.ts +140 -0
- package/src/device-agent/convex-command-subscription.ts +101 -0
- package/src/device-agent/convex-control-channel.ts +7 -1
- package/src/device-agent/http-transport.ts +22 -1
- package/src/device-agent/index.ts +22 -0
- package/src/device-agent/mqtt-channel.ts +379 -0
- package/src/device-agent/mqtt-codec.ts +347 -0
- package/src/device-agent/tournament.ts +352 -0
- package/src/engine.ts +580 -15
- package/src/http-session-provider.ts +21 -189
- package/src/index.ts +84 -5
- package/src/local-video-quality.ts +43 -0
- package/src/native-runtime.ts +234 -78
- package/src/plugin.ts +19 -6
- package/src/provider.tsx +94 -18
- package/src/realtime/index.ts +56 -0
- package/src/resume-policy.ts +85 -0
- package/src/resume.ts +132 -0
- package/src/rtmp-room-adapter.ts +164 -12
- package/src/session-grant.ts +256 -0
- package/src/ui/camera-screen.tsx +484 -0
- package/src/ui/controls-sheet.tsx +445 -0
- package/src/ui/copy.ts +326 -0
- package/src/ui/helpers.ts +105 -0
- package/src/ui/hooks.ts +59 -0
- package/src/ui/index.ts +42 -0
- package/src/ui/preview-view.tsx +39 -0
- package/src/ui/primitives.tsx +304 -0
- package/src/uplink-check.ts +173 -0
- package/dist/advanced-BXDrDl1h.d.ts +0 -316
- package/dist/advanced-BdAa2Erv.d.cts +0 -316
- package/src/livekit-room-adapter.ts +0 -390
- package/src/livestream-screen.tsx +0 -1002
package/dist/index.d.ts
CHANGED
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { B as BootstrapInput,
|
|
3
|
-
import {
|
|
4
|
-
export { L as LivestreamContextValue, a as LivestreamTheme, P as PickleballLiveProvider, b as PickleballLiveProviderProps, c as createDefaultStorage, d as defaultLivestreamTheme } from './advanced-
|
|
5
|
-
|
|
6
|
-
import { ViewStyle } from 'react-native';
|
|
1
|
+
import { L as LivestreamSessionProvider, b as SdkSessionGrant, C as CameraGrant, c as StartLivestreamInput, a as SdkStorage, d as SdkRemoteConfig } from './engine-BSvSdCSE.js';
|
|
2
|
+
export { B as BootstrapInput, e as CameraDeviceInfo, f as CameraGrantStatus, g as CaptureOrientation, h as ConsentRequiredError, D as DeviceMetricsSample, E as EndLivestreamInput, i as EndReason, j as ExpoSdkConfigurationError, k as ExpoSdkErrorCode, l as ExpoSdkTimeoutError, I as InvalidResponseError, m as LivestreamSnapshot, n as LivestreamState, N as NetworkUnavailableError, P as PermissionDeniedError, o as PickleballExpoError, p as RecordingFailureError, R as RoomAdapter, q as SDK_TELEMETRY_EVENT_NAMES, r as SdkBootstrap, s as SdkConflictReason, t as SdkDisabledError, u as SdkError, v as SdkErrorCode, w as SdkNetwork, x as SdkRuntime, y as SdkSessionRefresh, z as SdkTelemetryCredentials, A as SdkTelemetryEvent, F as SdkTelemetryEventName, G as SessionCommandAction, H as SessionCommandChannel, J as SessionCommandPollResult, K as SessionCommandRecord, S as SessionCommandSubscription, M as SessionConflictError, T as TelemetrySink, O as TokenExpiredError, U as UnknownSdkError, Q as UnsupportedRuntimeError, V as UnsupportedSdkError, W as compareSemver, X as errorFromCode, Y as isSdkRemoteConfig, Z as isSdkVersionSupported, _ as isSessionGoneError, $ as normalizeError } from './engine-BSvSdCSE.js';
|
|
3
|
+
import { F as Fetch } from './advanced-DcbHBCGb.js';
|
|
4
|
+
export { L as LivestreamContextValue, a as LivestreamTheme, P as PickleballLiveProvider, b as PickleballLiveProviderProps, c as createDefaultStorage, d as createRtmpRoomFactory, e as createRtmpRuntime, f as defaultLivestreamTheme, u as useLivestream } from './advanced-DcbHBCGb.js';
|
|
5
|
+
export { A as AntiFlickerMode, C as CAMERA_SETTINGS_STORAGE_KEY, a as CameraCapabilities, b as CameraCapabilityRange, c as CameraSettings, d as CameraSettingsStore, e as CameraSettingsStoreOptions, D as DEFAULT_CAMERA_SETTINGS, f as applyAntiFlicker, g as cameraSettingsKey, h as createCameraSettingsStore, i as getCameraCapabilities, p as parseCameraSettings, r as requestNativePermissions, j as rtmpRoomFactoryFor, s as setExposureBias, k as setExposureLocked, l as setFocusLocked, m as setTorch, n as setZoom, u as useCameraSettings } from './camera-controls-rCBUGGPC.js';
|
|
7
6
|
export { PICKLEBALL_EXPO_SDK_VERSION } from './version.js';
|
|
7
|
+
import 'react';
|
|
8
8
|
|
|
9
|
-
type RenderState = ReturnType<typeof useLivestream>;
|
|
10
|
-
interface LivestreamScreenProps {
|
|
11
|
-
input: StartLivestreamInput;
|
|
12
|
-
style?: ViewStyle;
|
|
13
|
-
/**
|
|
14
|
-
* Hướng máy vật lý (từ cảm biến, ví dụ expo-sensors DeviceMotion). Khi được
|
|
15
|
-
* cung cấp, nút bắt đầu phát bị chặn nếu máy đang cầm lệch với khung
|
|
16
|
-
* 9:16/16:9 đã chọn. Bỏ trống để tắt kiểm tra.
|
|
17
|
-
*/
|
|
18
|
-
physicalOrientation?: "portrait" | "landscape" | null;
|
|
19
|
-
/**
|
|
20
|
-
* Tự kết nối vào phòng khi mở màn hình nếu consent đã được lưu từ trước
|
|
21
|
-
* (mặc định bật) — dashboard điều khiển được ngay từ lúc app bật.
|
|
22
|
-
*/
|
|
23
|
-
autoConnect?: boolean;
|
|
24
|
-
renderPreview?: (state: RenderState) => ReactNode;
|
|
25
|
-
renderHeader?: (state: RenderState) => ReactNode;
|
|
26
|
-
renderControls?: (state: RenderState) => ReactNode;
|
|
27
|
-
renderError?: (state: RenderState) => ReactNode;
|
|
28
|
-
onEnded?: () => void;
|
|
29
|
-
}
|
|
30
|
-
declare function LivestreamScreen(props: LivestreamScreenProps): React.JSX.Element;
|
|
31
|
-
|
|
32
|
-
type Fetch = typeof globalThis.fetch;
|
|
33
9
|
type HeadersInput = Record<string, string>;
|
|
34
10
|
interface HttpSessionProviderPaths {
|
|
35
11
|
bootstrap: string;
|
|
@@ -40,7 +16,11 @@ interface HttpSessionProviderPaths {
|
|
|
40
16
|
unpublish(sessionId: string): string;
|
|
41
17
|
}
|
|
42
18
|
interface HttpSessionProviderOptions {
|
|
43
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Base URL của proxy do đối tác host (mô hình cũ) hoặc namespace first-party
|
|
21
|
+
* `/api/v2/device-app` (app fleet). Không bao giờ là URL PickLive kèm API key.
|
|
22
|
+
* App đối tác dùng camera grant thì dùng createCameraGrantProvider thay vì đây.
|
|
23
|
+
*/
|
|
44
24
|
baseUrl: string;
|
|
45
25
|
fetch?: Fetch;
|
|
46
26
|
headers?: HeadersInput | (() => HeadersInput | Promise<HeadersInput>);
|
|
@@ -49,4 +29,307 @@ interface HttpSessionProviderOptions {
|
|
|
49
29
|
}
|
|
50
30
|
declare function createHttpSessionProvider(options: HttpSessionProviderOptions): LivestreamSessionProvider;
|
|
51
31
|
|
|
52
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Nhận lại phiên sau khi app bị kill/mở lại — phần PROVIDER.
|
|
34
|
+
*
|
|
35
|
+
* Kịch bản: máy đang phát, app biến mất (sụp nguồn, OEM giết, vuốt tắt). Server
|
|
36
|
+
* còn giữ phiên. Lần mở sau engine thấy dấu trên đĩa (adoptableSessionId) nhưng
|
|
37
|
+
* KHÔNG có grant trong bộ nhớ — phải hỏi server cấp lại credentials của đúng
|
|
38
|
+
* phiên đó rồi start bằng grant ấy thay vì tạo phiên mới. Link xem và VOD nhờ
|
|
39
|
+
* vậy liền một mạch.
|
|
40
|
+
*/
|
|
41
|
+
type ResumeAttempt = {
|
|
42
|
+
kind: "grant";
|
|
43
|
+
grant: SdkSessionGrant;
|
|
44
|
+
live: boolean;
|
|
45
|
+
} | {
|
|
46
|
+
kind: "gone";
|
|
47
|
+
} | {
|
|
48
|
+
kind: "retry";
|
|
49
|
+
};
|
|
50
|
+
interface ResumableSessionProvider extends LivestreamSessionProvider {
|
|
51
|
+
/** Đặt grant cho lượt start kế tiếp có externalSessionId `resume-<id>`. */
|
|
52
|
+
adoptResumeGrant(grant: SdkSessionGrant): void;
|
|
53
|
+
/** Hỏi server cấp lại grant cho phiên còn sống. */
|
|
54
|
+
resume(sessionId: string): Promise<ResumeAttempt>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Bọc provider: `start()` ưu tiên grant nhận lại nếu khớp phiên, còn lại tạo phiên
|
|
58
|
+
* mới như thường. Grant chờ nằm trong closure (không biến module) nên hai provider
|
|
59
|
+
* trong cùng app không dẫm nhau.
|
|
60
|
+
*/
|
|
61
|
+
declare function withResume(provider: LivestreamSessionProvider, resume: (sessionId: string) => Promise<ResumeAttempt>): ResumableSessionProvider;
|
|
62
|
+
/** Biến phản hồi refresh (đầy đủ) thành grant; méo → null để caller coi là retry. */
|
|
63
|
+
declare function grantFromRefreshPayload(data: unknown): SdkSessionGrant | null;
|
|
64
|
+
interface HttpResumeFetcherOptions {
|
|
65
|
+
/** URL endpoint refresh của phiên — namespace nào cũng được, miễn trả grant đầy đủ + status. */
|
|
66
|
+
url(sessionId: string): string;
|
|
67
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
68
|
+
fetch?: Fetch;
|
|
69
|
+
timeoutMs?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Gọi endpoint refresh để dựng lại grant. Trả về PHÂN LOẠI chứ không phải
|
|
73
|
+
* null-cho-mọi-thứ (xem resume-policy): mất mạng/5xx/méo = retry, 404/409/410 =
|
|
74
|
+
* gone. Chỉ phát tiếp khi server xác nhận phiên ĐANG live — thiếu trường status
|
|
75
|
+
* coi như không phát: để camera tự lên sóng nhầm còn tệ hơn là chờ một lệnh nữa.
|
|
76
|
+
*/
|
|
77
|
+
declare function createHttpResumeFetcher(options: HttpResumeFetcherOptions): (sessionId: string) => Promise<ResumeAttempt>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Session provider cho ĐIỆN THOẠI ĐỐI TÁC (camera grant, ADR-0002).
|
|
81
|
+
*
|
|
82
|
+
* App đối tác ──(auth riêng)──► Backend đối tác ──khoá API (chỉ server)──► PickLive REST v1
|
|
83
|
+
* App đối tác ◄───────── CameraGrant nguyên trạng ◄──────────
|
|
84
|
+
* SDK ──Bearer grant.telemetry.token──► PickLive /api/v2/camera/sessions/{id}/*
|
|
85
|
+
*
|
|
86
|
+
* App KHÔNG cầm API key, KHÔNG cấu hình URL PickLive: mọi endpoint suy từ
|
|
87
|
+
* `telemetry.endpoint` trong grant. Backend đối tác chỉ có đúng một việc — cấp grant.
|
|
88
|
+
*
|
|
89
|
+
* Handle phiên `{sessionId, base, token}` được LƯU trong sandbox app (expo-sqlite
|
|
90
|
+
* localStorage) duy nhất để nhận lại phiên sau khi app bị kill; token khoá theo
|
|
91
|
+
* một phiên và tự hết hạn. Đây là thay đổi so với lời hứa "token chỉ ở bộ nhớ"
|
|
92
|
+
* của mô hình proxy cũ — chủ ý, để resume hoạt động.
|
|
93
|
+
*/
|
|
94
|
+
declare const CAMERA_GRANT_STORAGE_KEY = "@pickleball/expo-sdk/camera-grant";
|
|
95
|
+
/** Config local cho bước prepare (engine chỉ dùng enabled/minSdkVersion/videoQuality ở đây). */
|
|
96
|
+
declare const DEFAULT_LOCAL_CONFIG: SdkRemoteConfig;
|
|
97
|
+
type CameraGrantPhase = "start" | "refresh" | "resume";
|
|
98
|
+
interface CameraGrantProviderOptions {
|
|
99
|
+
/**
|
|
100
|
+
* App đối tác gọi backend đối tác → backend gọi PickLive → trả grant nguyên
|
|
101
|
+
* trạng. Nhận StartLivestreamInput của engine (kèm `standby`, `quality`) để
|
|
102
|
+
* backend chuyển tiếp title/quality nếu muốn.
|
|
103
|
+
*/
|
|
104
|
+
requestGrant(input: StartLivestreamInput): Promise<unknown>;
|
|
105
|
+
storage?: SdkStorage;
|
|
106
|
+
storageKey?: string;
|
|
107
|
+
fetch?: Fetch;
|
|
108
|
+
timeoutMs?: number;
|
|
109
|
+
/** Ghi đè config local của bước prepare (VD videoQuality theo cài đặt máy). */
|
|
110
|
+
localConfig?: Partial<SdkRemoteConfig>;
|
|
111
|
+
onGrant?(grant: CameraGrant, phase: CameraGrantPhase): void;
|
|
112
|
+
}
|
|
113
|
+
interface CameraGrantHandle {
|
|
114
|
+
sessionId: string;
|
|
115
|
+
base: string;
|
|
116
|
+
token: string;
|
|
117
|
+
tokenExpiresAt: number;
|
|
118
|
+
quality?: 720 | 1080;
|
|
119
|
+
savedAt: number;
|
|
120
|
+
}
|
|
121
|
+
interface CameraGrantProvider extends ResumableSessionProvider {
|
|
122
|
+
/** Grant đang cầm (null khi chưa có phiên). */
|
|
123
|
+
getActiveGrant(): CameraGrant | null;
|
|
124
|
+
subscribe(listener: () => void): () => void;
|
|
125
|
+
/** Có handle phiên trên đĩa → truyền vào `keepSessionOnRestart` của provider. */
|
|
126
|
+
hasResumableSession(): Promise<boolean>;
|
|
127
|
+
/** Quên phiên (logout/đổi user). Backend đối tác nên gọi end phiên đó. */
|
|
128
|
+
clearStoredSession(): Promise<void>;
|
|
129
|
+
}
|
|
130
|
+
declare function createCameraGrantProvider(options: CameraGrantProviderOptions): CameraGrantProvider;
|
|
131
|
+
/** Grant hiện hành của provider, theo dõi bằng useSyncExternalStore. */
|
|
132
|
+
declare function useCameraGrant(provider: CameraGrantProvider): CameraGrant | null;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Luật quyết định khi nối lại một phiên server còn giữ cho máy này.
|
|
136
|
+
*
|
|
137
|
+
* Chuyển từ apps/device-streamer (src/resume-policy.ts) vào SDK để app đối tác
|
|
138
|
+
* không phải học lại từng cái bẫy đã đo được trên fleet.
|
|
139
|
+
*
|
|
140
|
+
* Vì sao cần tách riêng: bản đầu coi MỌI thất bại là "phiên đã chết" và bỏ cuộc
|
|
141
|
+
* vĩnh viễn sau đúng một lần thử. Hệ quả: máy khởi động lại lúc wifi chưa kịp
|
|
142
|
+
* lên là mất luôn cơ hội nối lại — đúng ca hay gặp nhất, vì máy vừa mở nguồn
|
|
143
|
+
* thì wifi luôn lên chậm hơn app.
|
|
144
|
+
*
|
|
145
|
+
* Phân biệt hai loại thất bại là toàn bộ giá trị của module này:
|
|
146
|
+
* - "gone": server nói phiên không còn. Thử lại bao nhiêu cũng vô ích.
|
|
147
|
+
* - "retry": mạng chưa lên, server trục trặc, phản hồi méo. Phiên có thể vẫn sống.
|
|
148
|
+
*
|
|
149
|
+
* Nghi ngờ thì chọn "retry": đoán nhầm thành "gone" là mất phiên vĩnh viễn (link
|
|
150
|
+
* xem đổi, VOD tách đôi); đoán nhầm thành "retry" chỉ tốn vài request, và đã có
|
|
151
|
+
* lưới server dọn phiên mồ côi.
|
|
152
|
+
*/
|
|
153
|
+
/** Phân loại phản hồi HTTP của endpoint refresh. */
|
|
154
|
+
type ResumeVerdict = "ok" | "gone" | "retry";
|
|
155
|
+
/**
|
|
156
|
+
* 404 = phiên biến mất hẳn. 409 = phiên đã kết thúc (mọi namespace trả
|
|
157
|
+
* SESSION_CONFLICT cho thao tác trên phiên ended, và grant bị thay cũng là 409).
|
|
158
|
+
* 410 = Gone theo chuẩn HTTP. Mọi mã khác — kể cả 401/403 — đều là "retry":
|
|
159
|
+
* token có thể được cấp lại ở nhịp sau, và một lỗi xác thực tạm thời không phải
|
|
160
|
+
* bằng chứng phiên đã chết.
|
|
161
|
+
*/
|
|
162
|
+
declare function classifyResumeStatus(status: number): ResumeVerdict;
|
|
163
|
+
/**
|
|
164
|
+
* Nhịp thử lại. Nhịp đầu 1 giây vì ca điển hình là "app mở trước khi wifi lên" —
|
|
165
|
+
* chờ vài giây là xong. Trần 15 giây để một máy chết hẳn không nện server mãi;
|
|
166
|
+
* số lần thì KHÔNG giới hạn: thà thử mãi còn hơn mất phiên, và lưới server
|
|
167
|
+
* (1 giờ cho live, 30 phút cho standby) mới là thứ quyết định lúc nào bỏ cuộc.
|
|
168
|
+
*/
|
|
169
|
+
declare const RESUME_RETRY_DELAYS_MS: number[];
|
|
170
|
+
declare function resumeRetryDelayMs(attempt: number): number;
|
|
171
|
+
/**
|
|
172
|
+
* Bất kỳ ai định TẠO PHIÊN MỚI tự động (AutoTournament của fleet, useStandbySession
|
|
173
|
+
* của app đối tác) phải NHƯỜNG khi còn phiên chờ nhận lại — nhìn CẢ HAI nguồn.
|
|
174
|
+
*
|
|
175
|
+
* Bản đầu chỉ nhìn serverSession (heartbeat, về SAU vài giây); adoptableSessionId
|
|
176
|
+
* (dấu trên đĩa) có mặt ngay từ lúc engine khởi động xong. Khe hở vài giây đó là
|
|
177
|
+
* đủ để một lượt arm nổ súng trước AutoResume: hoặc đụng chốt marker (app đứng
|
|
178
|
+
* màn LỖI), hoặc tệ hơn — lách qua trong đúng cửa sổ race và tạo phiên chờ THỨ
|
|
179
|
+
* HAI đè phiên live cũ (đo thật đêm 18/08/2026).
|
|
180
|
+
*/
|
|
181
|
+
declare function resumeBlocksArm(input: {
|
|
182
|
+
adoptableSessionId: string | null;
|
|
183
|
+
serverSessionId: string | null;
|
|
184
|
+
engineSessionId: string | null;
|
|
185
|
+
}): boolean;
|
|
186
|
+
/** Quy ước externalSessionId của lượt start NHẬN LẠI — engine chỉ cho lượt này qua chốt marker. */
|
|
187
|
+
declare function resumeExternalSessionId(sessionId: string): string;
|
|
188
|
+
/**
|
|
189
|
+
* Grant nối lại chỉ được tiêu thụ cho ĐÚNG phiên nó được cấp. AutoResume có thể
|
|
190
|
+
* bắn nhiều lượt (retry, đổi nguồn); không kiểm khớp thì một grant cũ còn sót có
|
|
191
|
+
* thể bị lượt start của phiên khác nuốt — engine nối vào nhầm phiên, đúng loại lỗi
|
|
192
|
+
* âm thầm khó truy nhất.
|
|
193
|
+
*/
|
|
194
|
+
declare function resumeGrantMatches(externalSessionId: string | undefined, grantSessionId: string): boolean;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Ba mảnh "tự động" chuyển từ apps/device-streamer vào SDK — mọi app RTMP cần
|
|
198
|
+
* chúng, không riêng máy fleet:
|
|
199
|
+
*
|
|
200
|
+
* - PickleballAutoPrepare: camera luôn bật (prepare khi idle/ended).
|
|
201
|
+
* - PickleballAutoResume: app mở lại thấy phiên còn sống → nhận lại đúng phiên.
|
|
202
|
+
* - useStandbySession: chế độ sân — arm một phiên chờ, server lật live bằng lệnh.
|
|
203
|
+
*
|
|
204
|
+
* Các bẫy đã đo trên fleet (18–19/08/2026) nằm nguyên trong đây: retry publish
|
|
205
|
+
* khi encoder chưa có SPS, thoát hố "error" khi còn phiên chờ nhận lại, và
|
|
206
|
+
* KHÔNG arm phiên mới khi còn phiên chờ nhận lại.
|
|
207
|
+
*
|
|
208
|
+
* Kỷ luật dependency: mọi effect ở đây chỉ phụ thuộc vào TRẠNG THÁI (state,
|
|
209
|
+
* sessionId, id phiên chờ, cờ enabled) — hành động của engine, props cấu hình
|
|
210
|
+
* (resumeInput, retryDelayMs, input) và callback đi qua ref. App đối tác thường
|
|
211
|
+
* truyền object/hàm inline mỗi lần render; đưa chúng vào deps là mỗi render
|
|
212
|
+
* huỷ lượt resume đang bay, bắn lượt mới ngay (spam refresh) và timer thử lại
|
|
213
|
+
* không bao giờ kịp nổ.
|
|
214
|
+
*/
|
|
215
|
+
type ResumeAttemptOutcome = ResumeAttempt["kind"] | "start_failed" | "publish_retry" | "reprepare";
|
|
216
|
+
interface PickleballAutoResumeProps {
|
|
217
|
+
provider: ResumableSessionProvider;
|
|
218
|
+
/** Thông tin dựng lượt start nhận lại (title mặc định khi không biết tên phiên). */
|
|
219
|
+
resumeInput: {
|
|
220
|
+
consentVersion: string;
|
|
221
|
+
visibility?: "public" | "private";
|
|
222
|
+
metadata?: Record<string, string>;
|
|
223
|
+
titleFor?: (sessionId: string) => string;
|
|
224
|
+
};
|
|
225
|
+
/** false = tạm dừng (VD máy đang nghỉ). */
|
|
226
|
+
enabled?: boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Nguồn thứ hai của id phiên còn sống (fleet: serverSession từ heartbeat).
|
|
229
|
+
* adoptableSessionId (dấu trên đĩa) luôn được ưu tiên vì có sớm hơn vài giây.
|
|
230
|
+
* Truyền CÙNG giá trị này vào `useStandbySession({resumeSessionId})` nếu app
|
|
231
|
+
* arm phiên chờ, để arm nhường đường nhận lại.
|
|
232
|
+
*/
|
|
233
|
+
sessionIdHint?: string | null;
|
|
234
|
+
retryDelayMs?: (attempt: number) => number;
|
|
235
|
+
onAttempt?: (sessionId: string, outcome: ResumeAttemptOutcome) => void;
|
|
236
|
+
}
|
|
237
|
+
declare function PickleballAutoResume(props: PickleballAutoResumeProps): null;
|
|
238
|
+
interface PickleballAutoPrepareProps {
|
|
239
|
+
enabled?: boolean;
|
|
240
|
+
/** Khung cố định (fleet: landscape). Bỏ trống = theo hướng máy như engine mặc định. */
|
|
241
|
+
captureOrientation?: "portrait" | "landscape";
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Camera luôn sẵn: prepare khi idle và SAU KHI phiên kết thúc (thiếu nhánh
|
|
245
|
+
* `ended` là camera tối sau phiên đầu tiên). Không chạy khi đang lỗi — người
|
|
246
|
+
* dùng cần thấy lỗi, và AutoResume lo nhánh lỗi có phiên chờ.
|
|
247
|
+
*/
|
|
248
|
+
declare function PickleballAutoPrepare(props: PickleballAutoPrepareProps): null;
|
|
249
|
+
interface UseStandbySessionOptions {
|
|
250
|
+
/** Lượt start chờ; đổi `externalSessionId` (trận kế) mới arm lại sau khi phiên trước kết thúc. */
|
|
251
|
+
input: StartLivestreamInput;
|
|
252
|
+
enabled?: boolean;
|
|
253
|
+
/**
|
|
254
|
+
* Id phiên còn sống theo nguồn NGOÀI đĩa (fleet: heartbeat; app đối tác: id
|
|
255
|
+
* backend trả về) — cùng giá trị truyền vào `PickleballAutoResume.sessionIdHint`.
|
|
256
|
+
* Có nó là arm NHƯỜNG: không tạo phiên chờ thứ hai trong lúc AutoResume đang
|
|
257
|
+
* nối lại phiên cũ.
|
|
258
|
+
*/
|
|
259
|
+
resumeSessionId?: string | null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Chế độ SÂN: điện thoại đứng chờ (standby) với grant đã cấp; trọng tài bấm
|
|
263
|
+
* match-start là server gửi lệnh `start` qua kênh lệnh và engine tự phát.
|
|
264
|
+
* Arm đúng một lần cho mỗi externalSessionId, và NHƯỜNG khi còn phiên chờ nhận
|
|
265
|
+
* lại (resumeBlocksArm) để không tạo phiên chờ thứ hai đè phiên cũ.
|
|
266
|
+
*/
|
|
267
|
+
declare function useStandbySession(options: UseStandbySessionOptions): {
|
|
268
|
+
armed: boolean;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Độ phân giải là lựa chọn LOCAL của máy — override `videoQuality` mà server trả
|
|
273
|
+
* trong bootstrap/start/refresh (engine truyền config.videoQuality vào
|
|
274
|
+
* room.preparePreview nên không cần sửa engine).
|
|
275
|
+
*
|
|
276
|
+
* Lúc TẠO phiên phải khai ngược lên server (`quality` trong StartLivestreamInput),
|
|
277
|
+
* nếu không bản ghi phiên nói dối: mặc định local 720 còn server 1080 — dashboard
|
|
278
|
+
* báo 1080 trong khi máy phát 720 suốt (18/08/2026). Chốt MỘT lần lúc start:
|
|
279
|
+
* gọi `resolution()` hai lần có thể ra hai giá trị khác nhau, khai một đằng dùng
|
|
280
|
+
* một nẻo thì tệ hơn là không khai.
|
|
281
|
+
*/
|
|
282
|
+
declare function withLocalVideoQuality<P extends LivestreamSessionProvider>(provider: P, resolution: () => 720 | 1080): P;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Đo tốc độ TẢI LÊN — chiều duy nhất quan trọng với máy phát RTMP (root cause
|
|
286
|
+
* các ca đứng hình field day là uplink hụt). Chuyển từ apps/device-streamer/
|
|
287
|
+
* src/net-check.ts; bảng bitrate giờ là nguồn duy nhất (adapter RTMP import lại).
|
|
288
|
+
*
|
|
289
|
+
* Đích đo mặc định speed.cloudflare.com/__up (edge gần VN/SG): đo "sức uplink
|
|
290
|
+
* của đường mạng", không phải đường tới đúng VPS ingest — nghẽn thực tế nằm ở
|
|
291
|
+
* last-mile WiFi/4G nên xấp xỉ tốt, và không phải mở endpoint nào trên hạ tầng.
|
|
292
|
+
*/
|
|
293
|
+
/**
|
|
294
|
+
* Trần bitrate video theo mức chất lượng — trong khoảng TikTok khuyến nghị cho
|
|
295
|
+
* live (720p 3–6 Mbps, 1080p 6–9 Mbps). Thấp hơn là pickleball bể khối rất rõ.
|
|
296
|
+
*/
|
|
297
|
+
declare const VIDEO_BITRATE_BPS: Readonly<Record<720 | 1080, number>>;
|
|
298
|
+
declare const AUDIO_BITRATE_BPS = 128000;
|
|
299
|
+
interface UplinkCheckOptions {
|
|
300
|
+
resolution: 720 | 1080;
|
|
301
|
+
/** Đích POST khối dữ liệu; mặc định Cloudflare speed test. */
|
|
302
|
+
uploadUrl?: string;
|
|
303
|
+
/** HEAD để đo RTT (VD ingest của bạn). Bỏ trống = không đo ping. */
|
|
304
|
+
pingUrl?: string;
|
|
305
|
+
fetch?: typeof globalThis.fetch;
|
|
306
|
+
/** Đo tối thiểu chừng này thời gian sau warmup (mặc định 6s). */
|
|
307
|
+
measureMs?: number;
|
|
308
|
+
/** Trần cho cả bài đo (mặc định 25s). */
|
|
309
|
+
totalTimeoutMs?: number;
|
|
310
|
+
/** Cỡ mỗi khối POST (mặc định 2 MiB). */
|
|
311
|
+
chunkBytes?: number;
|
|
312
|
+
/** Trần cho khối warmup (mặc định 10s) — quá là mạng "low", không phải lỗi đo. */
|
|
313
|
+
warmupTimeoutMs?: number;
|
|
314
|
+
}
|
|
315
|
+
interface UplinkCheckResult {
|
|
316
|
+
uploadMbps: number;
|
|
317
|
+
/** RTT tới pingUrl, null nếu không đo/đo hỏng. */
|
|
318
|
+
pingMs: number | null;
|
|
319
|
+
/** Băng thông cần cho cấu hình (video trần + audio), Mbps. */
|
|
320
|
+
requiredMbps: number;
|
|
321
|
+
verdict: "good" | "ok" | "low";
|
|
322
|
+
}
|
|
323
|
+
declare const DEFAULT_UPLOAD_URL = "https://speed.cloudflare.com/__up";
|
|
324
|
+
declare function requiredMbpsFor(settings: {
|
|
325
|
+
resolution: 720 | 1080;
|
|
326
|
+
}): number;
|
|
327
|
+
/**
|
|
328
|
+
* Verdict theo tỉ lệ đo/cần: ≥1.8× là dư (chịu được dao động), ≥1.25× tạm đủ
|
|
329
|
+
* (AIMD sẽ phải hạ bitrate lúc mạng chùng), dưới đó là thiếu — hạ cấu hình
|
|
330
|
+
* hoặc đổi mạng trước khi lên sóng.
|
|
331
|
+
*/
|
|
332
|
+
declare function verdictFor(uploadMbps: number, requiredMbps: number): UplinkCheckResult["verdict"];
|
|
333
|
+
declare function runUplinkCheck(options: UplinkCheckOptions): Promise<UplinkCheckResult>;
|
|
334
|
+
|
|
335
|
+
export { AUDIO_BITRATE_BPS, CAMERA_GRANT_STORAGE_KEY, CameraGrant, type CameraGrantHandle, type CameraGrantPhase, type CameraGrantProvider, type CameraGrantProviderOptions, DEFAULT_LOCAL_CONFIG, DEFAULT_UPLOAD_URL, type HttpResumeFetcherOptions, type HttpSessionProviderOptions, type HttpSessionProviderPaths, LivestreamSessionProvider, PickleballAutoPrepare, type PickleballAutoPrepareProps, PickleballAutoResume, type PickleballAutoResumeProps, RESUME_RETRY_DELAYS_MS, type ResumableSessionProvider, type ResumeAttempt, type ResumeAttemptOutcome, type ResumeVerdict, SdkRemoteConfig, SdkSessionGrant, SdkStorage, StartLivestreamInput, type UplinkCheckOptions, type UplinkCheckResult, type UseStandbySessionOptions, VIDEO_BITRATE_BPS, classifyResumeStatus, createCameraGrantProvider, createHttpResumeFetcher, createHttpSessionProvider, grantFromRefreshPayload, requiredMbpsFor, resumeBlocksArm, resumeExternalSessionId, resumeGrantMatches, resumeRetryDelayMs, runUplinkCheck, useCameraGrant, useStandbySession, verdictFor, withLocalVideoQuality, withResume };
|