lecodes-sdk 2.2.7 → 2.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/global.d.ts +34 -0
- package/dist/types/inject.d.ts +1 -0
- package/dist/types/plugins/gen/webrtc/sdk/webrtc.RtcMedia.gen.d.ts +55 -0
- package/dist/types/plugins/gen/webrtc/sdk/webrtc.RtcPeerConnection.gen.d.ts +121 -0
- package/dist/types/plugins/gen/webrtc/sdk/webrtc.RtcVideo.gen.d.ts +25 -0
- package/dist/types/plugins/gen/webrtc/sdk/webrtc.d.ts +331 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types.json +1 -1
- package/package.json +1 -1
- package/src/chisel.ts +2 -2
- package/src/inject.ts +7 -0
- package/src/plugins/gen/webrtc/contract.d.ts +342 -0
- package/src/plugins/gen/webrtc/sdk/webrtc.RtcMedia.gen.ts +86 -0
- package/src/plugins/gen/webrtc/sdk/webrtc.RtcPeerConnection.gen.ts +184 -0
- package/src/plugins/gen/webrtc/sdk/webrtc.RtcVideo.gen.ts +48 -0
- package/src/plugins/gen/webrtc/sdk/webrtc.ts +765 -0
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/chisel.ts
CHANGED
|
@@ -118,7 +118,7 @@ export const chiselVocab: ChiselVocab = {
|
|
|
118
118
|
},
|
|
119
119
|
leaves: [
|
|
120
120
|
"UIText", "UIImage", "UIVideo", "UIInput", "UITextArea", "UISpacer",
|
|
121
|
-
"UITabs", "UIVirtualizedList", "NativeView", "CameraView", "MapView", "QRScanner", "WebView",
|
|
121
|
+
"UITabs", "UIVirtualizedList", "NativeView", "CameraView", "MapView", "QRScanner", "WebView", "RTCVideoView",
|
|
122
122
|
],
|
|
123
123
|
containers: [ "UIColumn", "UIRow", "UIBox", "UIButton", "UIScrollable", "UIScreen", "UIWidget" ],
|
|
124
124
|
text: "UIText",
|
|
@@ -133,7 +133,7 @@ export const chiselVocab: ChiselVocab = {
|
|
|
133
133
|
"append", "insert", "remove", "setContent", "widgets", "keepAlive", "url",
|
|
134
134
|
"detents", "dismissible", "transition", "setSourceRect",
|
|
135
135
|
"push", "pop", "popToRoot", "replace", "select",
|
|
136
|
-
// UITabs / UIVirtualizedList's hand feed / the native views (NativeView, CameraView, MapView, QRScanner)
|
|
136
|
+
// UITabs / UIVirtualizedList's hand feed / the native views (NativeView, CameraView, MapView, QRScanner, WebView, RTCVideoView)
|
|
137
137
|
"badge", "setData", "update", "prepend", "removeByKey",
|
|
138
138
|
"on", "off", "onReady", "onError", "onTap", "onMove", "onScan",
|
|
139
139
|
"flyTo", "jumpTo", "fitPoints", "setPadding", "setUserLocation",
|
package/src/inject.ts
CHANGED
|
@@ -152,6 +152,13 @@ export {
|
|
|
152
152
|
} from "./plugins/gen/map/sdk/map"
|
|
153
153
|
export { Push, type PushPayload, type PushStatus, type PushRegisterOptions, type PushEvent } from "./plugins/gen/push/sdk/push"
|
|
154
154
|
export { Browser, WebView, type BrowserOpenOptions, type WebViewParams, type WebViewEvents } from "./plugins/gen/browser/sdk/browser"
|
|
155
|
+
export {
|
|
156
|
+
RTCPeerConnection, MediaStream, MediaStreamTrack, RTCDataChannel, RTCRtpSender, RTCRtpReceiver, RTCRtpTransceiver,
|
|
157
|
+
RTCSessionDescription, RTCIceCandidate, RTCEventTarget, mediaDevices, RTCVideoView,
|
|
158
|
+
type RTCConfiguration, type RTCVideoViewOptions, type MediaStreamConstraints, type RTCIceCandidateInit,
|
|
159
|
+
type RTCPeerConnectionIceEvent, type RTCTrackEvent, type RTCDataChannelEvent, type RTCMessageEvent, type RTCErrorEvent, type RTCEvent,
|
|
160
|
+
type RTCEventListener,
|
|
161
|
+
} from "./plugins/gen/webrtc/sdk/webrtc"
|
|
155
162
|
export { Service } from "./plugins/service"
|
|
156
163
|
|
|
157
164
|
// ---- scenes as data (.scene.ts files — see src/scene/defineScene.ts) ----
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/webrtc/contract.d.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// webrtc — real-time audio, video and data between peers, over libwebrtc on iOS and Android and
|
|
4
|
+
// the browser's own stack on the web. The wire is the W3C API, cut at the objects: a peer
|
|
5
|
+
// connection is a SESSION of the "rtcPeerConnection" service (its params are the configuration,
|
|
6
|
+
// the SDK's close() is RTCPeerConnection.close()), the media devices are the "rtcMedia" service,
|
|
7
|
+
// and a track is drawn by the "rtcVideo" view. Tracks, senders, transceivers and data channels
|
|
8
|
+
// live in the host; what crosses is an id the host allocated. A remote track (the `track` event)
|
|
9
|
+
// is a track like any other: the view shows it, another connection can forward it.
|
|
10
|
+
//
|
|
11
|
+
// Signaling is NOT here: the app carries the descriptions and the candidates over its own
|
|
12
|
+
// channel (a WebSocket). The halves are dumb on purpose — no room, no call, no server — so that a
|
|
13
|
+
// client of an SFU (mediasoup-client, LiveKit's) can run in the app's bundle over this wire.
|
|
14
|
+
//
|
|
15
|
+
// The app-facing API (sdk/) is the browser's: RTCPeerConnection, MediaStream, MediaStreamTrack,
|
|
16
|
+
// RTCDataChannel, mediaDevices.getUserMedia(), plus RTCVideoView for the picture.
|
|
17
|
+
|
|
18
|
+
import type { Json, Service, View, f64, i32 } from "../../../plugin"
|
|
19
|
+
|
|
20
|
+
// ---- media ----------------------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
export type MediaKind = "audio" | "video"
|
|
23
|
+
/** The browser's facingMode values: "user" is the front camera, "environment" the back one. */
|
|
24
|
+
export type FacingMode = "user" | "environment"
|
|
25
|
+
export type DeviceKind = "audioinput" | "audiooutput" | "videoinput"
|
|
26
|
+
/** Where the call's audio plays on a phone. */
|
|
27
|
+
export type AudioOutput = "earpiece" | "speaker"
|
|
28
|
+
|
|
29
|
+
export interface AudioConstraints {
|
|
30
|
+
/** A device of enumerateDevices(); the default input when absent. */
|
|
31
|
+
deviceId?: string
|
|
32
|
+
/** Default true. */
|
|
33
|
+
echoCancellation?: boolean
|
|
34
|
+
/** Default true. */
|
|
35
|
+
noiseSuppression?: boolean
|
|
36
|
+
/** Default true. */
|
|
37
|
+
autoGainControl?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface VideoConstraints {
|
|
41
|
+
/** A device of enumerateDevices(); wins over facingMode. */
|
|
42
|
+
deviceId?: string
|
|
43
|
+
/** Default "user". */
|
|
44
|
+
facingMode?: FacingMode
|
|
45
|
+
/** The capture size wanted; the host picks the closest format the camera has. Default 1280×720. */
|
|
46
|
+
width?: i32
|
|
47
|
+
height?: i32
|
|
48
|
+
/** Default 30. */
|
|
49
|
+
frameRate?: f64
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** What to capture: a kind present = wanted (the wrapper turns the browser's `audio: true` into `{}`). */
|
|
53
|
+
export interface MediaConstraints {
|
|
54
|
+
audio?: AudioConstraints
|
|
55
|
+
video?: VideoConstraints
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface TrackInfo {
|
|
59
|
+
/** The host's id of the track — what every call names it by. */
|
|
60
|
+
id: string
|
|
61
|
+
kind: MediaKind
|
|
62
|
+
/** The device's name for a local track, the remote msid for a received one. */
|
|
63
|
+
label: string
|
|
64
|
+
enabled: boolean
|
|
65
|
+
/** A received track the sender has muted (no media is arriving). Default false. */
|
|
66
|
+
muted?: boolean
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface StreamInfo {
|
|
70
|
+
id: string
|
|
71
|
+
tracks: TrackInfo[]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface DeviceInfo {
|
|
75
|
+
deviceId: string
|
|
76
|
+
kind: DeviceKind
|
|
77
|
+
label: string
|
|
78
|
+
/** A camera's side, when the platform tells. */
|
|
79
|
+
facing?: FacingMode
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** What a local video track captures with, after the constraints were applied. */
|
|
83
|
+
export interface TrackSettings {
|
|
84
|
+
deviceId?: string
|
|
85
|
+
facingMode?: FacingMode
|
|
86
|
+
width?: i32
|
|
87
|
+
height?: i32
|
|
88
|
+
frameRate?: f64
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RtcMediaParams {}
|
|
92
|
+
|
|
93
|
+
export interface RtcMediaEvents {
|
|
94
|
+
/** A device was plugged in or removed (a headset, a camera). */
|
|
95
|
+
deviceChange: void
|
|
96
|
+
/** A local track ended on its own: the OS took the device (a call came in, the camera was claimed). */
|
|
97
|
+
trackEnded: { trackId: string }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The devices: capture, the device list, the audio route. One session for the app. */
|
|
101
|
+
export interface RtcMedia extends Service<"rtcMedia", RtcMediaParams, RtcMediaEvents> {
|
|
102
|
+
/** Capture: prompts for the permissions it needs, resolves with a stream of the new tracks.
|
|
103
|
+
* @rejects denied notFound failed */
|
|
104
|
+
getUserMedia(constraints: MediaConstraints): Promise<StreamInfo>
|
|
105
|
+
/** The devices the host can capture with (labels need a granted permission on the web). */
|
|
106
|
+
enumerateDevices(): Promise<DeviceInfo[]>
|
|
107
|
+
/** A disabled track sends silence / black frames and stays in every connection. @rejects notFound */
|
|
108
|
+
setTrackEnabled(trackId: string, enabled: boolean): Promise<void>
|
|
109
|
+
/** Re-aim a local video track: the other camera, another size or rate. The track and its id
|
|
110
|
+
* stay; every connection keeps sending it. @rejects notFound failed */
|
|
111
|
+
applyConstraints(trackId: string, constraints: VideoConstraints): Promise<void>
|
|
112
|
+
/** @rejects notFound */
|
|
113
|
+
getTrackSettings(trackId: string): Promise<TrackSettings>
|
|
114
|
+
/** End a track: the device is released once no track of it is left, every sender of it goes
|
|
115
|
+
* quiet, the id is forgotten. A no-op for an unknown id. */
|
|
116
|
+
stopTrack(trackId: string): Promise<void>
|
|
117
|
+
/** Route the audio of the call: the earpiece (the default while a wired or Bluetooth headset is
|
|
118
|
+
* not connected) or the loudspeaker. A no-op on the web. */
|
|
119
|
+
setAudioOutput(output: AudioOutput): Promise<void>
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---- the peer connection --------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
export interface IceServer {
|
|
125
|
+
urls: string[]
|
|
126
|
+
username?: string
|
|
127
|
+
credential?: string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type IceTransportPolicy = "all" | "relay"
|
|
131
|
+
export type BundlePolicy = "balanced" | "max-compat" | "max-bundle"
|
|
132
|
+
|
|
133
|
+
/** The RTCConfiguration — the params of a session, and what setConfiguration takes. */
|
|
134
|
+
export interface RtcConfiguration {
|
|
135
|
+
iceServers?: IceServer[]
|
|
136
|
+
/** Default "all". */
|
|
137
|
+
iceTransportPolicy?: IceTransportPolicy
|
|
138
|
+
/** Default "balanced". */
|
|
139
|
+
bundlePolicy?: BundlePolicy
|
|
140
|
+
/** Default 0. */
|
|
141
|
+
iceCandidatePoolSize?: i32
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export type SdpType = "offer" | "answer" | "pranswer" | "rollback"
|
|
145
|
+
|
|
146
|
+
export interface SessionDescription {
|
|
147
|
+
type: SdpType
|
|
148
|
+
sdp: string
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface IceCandidate {
|
|
152
|
+
candidate: string
|
|
153
|
+
sdpMid: string | null
|
|
154
|
+
sdpMLineIndex: i32 | null
|
|
155
|
+
usernameFragment?: string
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface OfferOptions {
|
|
159
|
+
iceRestart?: boolean
|
|
160
|
+
offerToReceiveAudio?: boolean
|
|
161
|
+
offerToReceiveVideo?: boolean
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type SignalingState = "stable" | "have-local-offer" | "have-remote-offer" | "have-local-pranswer" | "have-remote-pranswer" | "closed"
|
|
165
|
+
export type IceGatheringState = "new" | "gathering" | "complete"
|
|
166
|
+
export type IceConnectionState = "new" | "checking" | "connected" | "completed" | "failed" | "disconnected" | "closed"
|
|
167
|
+
export type PeerConnectionState = "new" | "connecting" | "connected" | "disconnected" | "failed" | "closed"
|
|
168
|
+
export type TransceiverDirection = "sendrecv" | "sendonly" | "recvonly" | "inactive" | "stopped"
|
|
169
|
+
|
|
170
|
+
/** One encoding of a sender (a simulcast layer when there are several, each with a `rid`). */
|
|
171
|
+
export interface Encoding {
|
|
172
|
+
rid?: string
|
|
173
|
+
/** Default true. */
|
|
174
|
+
active?: boolean
|
|
175
|
+
/** Bits per second. */
|
|
176
|
+
maxBitrate?: i32
|
|
177
|
+
maxFramerate?: f64
|
|
178
|
+
/** 2 = half the width and the height. */
|
|
179
|
+
scaleResolutionDownBy?: f64
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface SenderParameters {
|
|
183
|
+
encodings: Encoding[]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface TransceiverInit {
|
|
187
|
+
/** Default "sendrecv". */
|
|
188
|
+
direction?: TransceiverDirection
|
|
189
|
+
/** A local track to send from the start. */
|
|
190
|
+
trackId?: string
|
|
191
|
+
streamIds?: string[]
|
|
192
|
+
/** The simulcast layers (an SFU client's): one encoding each, with a rid. */
|
|
193
|
+
sendEncodings?: Encoding[]
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface SenderInfo {
|
|
197
|
+
id: string
|
|
198
|
+
trackId: string | null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface TransceiverInfo {
|
|
202
|
+
id: string
|
|
203
|
+
mid: string | null
|
|
204
|
+
direction: TransceiverDirection
|
|
205
|
+
currentDirection: TransceiverDirection | null
|
|
206
|
+
sender: SenderInfo
|
|
207
|
+
/** The receiver's track exists from the start (before any media arrives). */
|
|
208
|
+
receiverTrack: TrackInfo
|
|
209
|
+
stopped: boolean
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface DataChannelInit {
|
|
213
|
+
/** Default true. */
|
|
214
|
+
ordered?: boolean
|
|
215
|
+
maxPacketLifeTime?: i32
|
|
216
|
+
maxRetransmits?: i32
|
|
217
|
+
/** Default "". */
|
|
218
|
+
protocol?: string
|
|
219
|
+
/** Default false. */
|
|
220
|
+
negotiated?: boolean
|
|
221
|
+
/** The SCTP stream id of a negotiated channel. */
|
|
222
|
+
id?: i32
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export type DataChannelState = "connecting" | "open" | "closing" | "closed"
|
|
226
|
+
|
|
227
|
+
export interface DataChannelInfo {
|
|
228
|
+
/** The host's id of the channel — what every call names it by. */
|
|
229
|
+
id: string
|
|
230
|
+
label: string
|
|
231
|
+
ordered: boolean
|
|
232
|
+
maxPacketLifeTime: i32 | null
|
|
233
|
+
maxRetransmits: i32 | null
|
|
234
|
+
protocol: string
|
|
235
|
+
negotiated: boolean
|
|
236
|
+
/** The SCTP stream id; null until the transport assigned one. */
|
|
237
|
+
streamId: i32 | null
|
|
238
|
+
readyState: DataChannelState
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface RtcPeerConnectionEvents {
|
|
242
|
+
negotiationNeeded: void
|
|
243
|
+
/** A local candidate for the other side; null = the gathering of this round is complete. */
|
|
244
|
+
iceCandidate: { candidate: IceCandidate | null }
|
|
245
|
+
signalingStateChange: { state: SignalingState }
|
|
246
|
+
iceGatheringStateChange: { state: IceGatheringState }
|
|
247
|
+
iceConnectionStateChange: { state: IceConnectionState }
|
|
248
|
+
connectionStateChange: { state: PeerConnectionState }
|
|
249
|
+
/** A remote track arrived: the receiver's track of `transceiverId`, in the streams the other
|
|
250
|
+
* side put it in. */
|
|
251
|
+
track: { track: TrackInfo, streamIds: string[], transceiverId: string }
|
|
252
|
+
/** A received track went mute (nothing arrives) or came back. */
|
|
253
|
+
trackMute: { trackId: string, muted: boolean }
|
|
254
|
+
/** A received track ended: the other side removed it, or the connection closed. */
|
|
255
|
+
trackEnded: { trackId: string }
|
|
256
|
+
/** The other side opened a data channel. */
|
|
257
|
+
dataChannel: DataChannelInfo
|
|
258
|
+
dataChannelStateChange: { id: string, state: DataChannelState }
|
|
259
|
+
/** One message: `text` for a string, `binary` for bytes — exactly one of the two. */
|
|
260
|
+
dataChannelMessage: { id: string, text?: string, binary?: Uint8Array }
|
|
261
|
+
dataChannelError: { id: string, message: string }
|
|
262
|
+
/** The buffered amount fell to the threshold or under it. */
|
|
263
|
+
dataChannelBufferedAmountLow: { id: string }
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** One RTCPeerConnection: a session, created with its configuration, closed by the SDK's close(). */
|
|
267
|
+
export interface RtcPeerConnection extends Service<"rtcPeerConnection", RtcConfiguration, RtcPeerConnectionEvents> {
|
|
268
|
+
/** @rejects failed closed */
|
|
269
|
+
createOffer(options?: OfferOptions): Promise<SessionDescription>
|
|
270
|
+
/** @rejects failed closed */
|
|
271
|
+
createAnswer(): Promise<SessionDescription>
|
|
272
|
+
/** Without a description: the implicit form — an answer when a remote offer is pending, an
|
|
273
|
+
* offer otherwise. Resolves with the description now in force (the one to signal).
|
|
274
|
+
* @rejects failed closed */
|
|
275
|
+
setLocalDescription(description?: SessionDescription): Promise<SessionDescription>
|
|
276
|
+
/** @rejects failed closed */
|
|
277
|
+
setRemoteDescription(description: SessionDescription): Promise<void>
|
|
278
|
+
/** Without a candidate: the end of the remote candidates. @rejects failed closed */
|
|
279
|
+
addIceCandidate(candidate?: IceCandidate): Promise<void>
|
|
280
|
+
/** The next offer carries new ICE credentials. */
|
|
281
|
+
restartIce(): Promise<void>
|
|
282
|
+
/** @rejects failed */
|
|
283
|
+
setConfiguration(configuration: RtcConfiguration): Promise<void>
|
|
284
|
+
/** Send a local track, in the streams named (one is made up when none is). @rejects notFound failed closed */
|
|
285
|
+
addTrack(trackId: string, streamIds?: string[]): Promise<SenderInfo>
|
|
286
|
+
/** @rejects notFound closed */
|
|
287
|
+
removeTrack(senderId: string): Promise<void>
|
|
288
|
+
/** Swap what a sender sends without renegotiating; null = send nothing. @rejects notFound failed closed */
|
|
289
|
+
replaceTrack(senderId: string, trackId: string | null): Promise<void>
|
|
290
|
+
/** @rejects notFound */
|
|
291
|
+
getSenderParameters(senderId: string): Promise<SenderParameters>
|
|
292
|
+
/** The encodings' active / bitrate / scale; the layers themselves are set at addTransceiver. @rejects notFound failed */
|
|
293
|
+
setSenderParameters(senderId: string, parameters: SenderParameters): Promise<void>
|
|
294
|
+
/** @rejects notFound failed closed */
|
|
295
|
+
addTransceiver(kind: MediaKind, options?: TransceiverInit): Promise<TransceiverInfo>
|
|
296
|
+
getTransceivers(): Promise<TransceiverInfo[]>
|
|
297
|
+
/** @rejects notFound failed */
|
|
298
|
+
setTransceiverDirection(transceiverId: string, direction: TransceiverDirection): Promise<void>
|
|
299
|
+
/** @rejects notFound */
|
|
300
|
+
stopTransceiver(transceiverId: string): Promise<void>
|
|
301
|
+
/** The RTCStatsReport as an object: the stats id → the stats object (`type`, `timestamp` in ms,
|
|
302
|
+
* the fields of its type). For one track's senders / receivers when `trackId` is given. */
|
|
303
|
+
getStats(trackId?: string): Promise<Json>
|
|
304
|
+
/** @rejects failed closed */
|
|
305
|
+
createDataChannel(label: string, options?: DataChannelInit): Promise<DataChannelInfo>
|
|
306
|
+
/** @rejects notFound closed */
|
|
307
|
+
sendText(channelId: string, text: string): Promise<void>
|
|
308
|
+
/** @rejects notFound closed */
|
|
309
|
+
sendBinary(channelId: string, data: Uint8Array): Promise<void>
|
|
310
|
+
/** Bytes queued and not yet sent. @rejects notFound */
|
|
311
|
+
getBufferedAmount(channelId: string): Promise<f64>
|
|
312
|
+
/** @rejects notFound */
|
|
313
|
+
setBufferedAmountLowThreshold(channelId: string, threshold: f64): Promise<void>
|
|
314
|
+
/** A no-op for an unknown id. */
|
|
315
|
+
closeDataChannel(channelId: string): Promise<void>
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ---- the picture ----------------------------------------------------------------------------------
|
|
319
|
+
|
|
320
|
+
export type ObjectFit = "cover" | "contain"
|
|
321
|
+
|
|
322
|
+
export interface RtcVideoParams {
|
|
323
|
+
/** The track to draw; none = black. */
|
|
324
|
+
trackId?: string
|
|
325
|
+
/** Default "cover". */
|
|
326
|
+
objectFit?: ObjectFit
|
|
327
|
+
/** Flip horizontally — the front camera's preview. Default false. */
|
|
328
|
+
mirror?: boolean
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface RtcVideoEvents {
|
|
332
|
+
/** The first frame was drawn, and every change of the picture's size after. */
|
|
333
|
+
resize: { width: i32, height: i32 }
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** A view drawing one video track, local or remote. */
|
|
337
|
+
export interface RtcVideo extends View<"rtcVideo", RtcVideoParams, RtcVideoEvents> {
|
|
338
|
+
/** Draw another track; null = black. @rejects notFound */
|
|
339
|
+
setTrack(trackId: string | null): Promise<void>
|
|
340
|
+
setObjectFit(fit: ObjectFit): Promise<void>
|
|
341
|
+
setMirror(mirror: boolean): Promise<void>
|
|
342
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/webrtc/sdk/webrtc.RtcMedia.gen.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// GENERATED by `lecodes plugin gen` from contract.d.ts — do not edit.
|
|
4
|
+
// webrtc: the service "rtcMedia", contract version 1.
|
|
5
|
+
|
|
6
|
+
import { ServiceChannel } from "../../../../plugin"
|
|
7
|
+
import type { AudioOutput, DeviceInfo, MediaConstraints, RtcMediaEvents, RtcMediaParams, StreamInfo, TrackSettings, VideoConstraints } from "../contract"
|
|
8
|
+
|
|
9
|
+
/** What the halves register under. */
|
|
10
|
+
export const NAME = "rtcMedia"
|
|
11
|
+
/** The contract's version: the highest `@since` of its members. */
|
|
12
|
+
export const VERSION = 1
|
|
13
|
+
|
|
14
|
+
// ---- the wire, call by call ----------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/** Capture: prompts for the permissions it needs, resolves with a stream of the new tracks.
|
|
17
|
+
* Rejects with "denied" / "notFound" / "failed". */
|
|
18
|
+
export const getUserMedia = (service: ServiceChannel<RtcMediaEvents>, constraints: MediaConstraints): Promise<StreamInfo> =>
|
|
19
|
+
service._call("getUserMedia", [constraints])
|
|
20
|
+
|
|
21
|
+
/** The devices the host can capture with (labels need a granted permission on the web). */
|
|
22
|
+
export const enumerateDevices = (service: ServiceChannel<RtcMediaEvents>): Promise<DeviceInfo[]> =>
|
|
23
|
+
service._call("enumerateDevices", [])
|
|
24
|
+
|
|
25
|
+
/** A disabled track sends silence / black frames and stays in every connection.
|
|
26
|
+
* Rejects with "notFound". */
|
|
27
|
+
export const setTrackEnabled = (service: ServiceChannel<RtcMediaEvents>, trackId: string, enabled: boolean): Promise<void> =>
|
|
28
|
+
service._call("setTrackEnabled", [trackId, enabled])
|
|
29
|
+
|
|
30
|
+
/** Re-aim a local video track: the other camera, another size or rate. The track and its id
|
|
31
|
+
* stay; every connection keeps sending it.
|
|
32
|
+
* Rejects with "notFound" / "failed". */
|
|
33
|
+
export const applyConstraints = (service: ServiceChannel<RtcMediaEvents>, trackId: string, constraints: VideoConstraints): Promise<void> =>
|
|
34
|
+
service._call("applyConstraints", [trackId, constraints])
|
|
35
|
+
|
|
36
|
+
/** Rejects with "notFound". */
|
|
37
|
+
export const getTrackSettings = (service: ServiceChannel<RtcMediaEvents>, trackId: string): Promise<TrackSettings> =>
|
|
38
|
+
service._call("getTrackSettings", [trackId])
|
|
39
|
+
|
|
40
|
+
/** End a track: the device is released once no track of it is left, every sender of it goes
|
|
41
|
+
* quiet, the id is forgotten. A no-op for an unknown id. */
|
|
42
|
+
export const stopTrack = (service: ServiceChannel<RtcMediaEvents>, trackId: string): Promise<void> =>
|
|
43
|
+
service._call("stopTrack", [trackId])
|
|
44
|
+
|
|
45
|
+
/** Route the audio of the call: the earpiece (the default while a wired or Bluetooth headset is
|
|
46
|
+
* not connected) or the loudspeaker. A no-op on the web. */
|
|
47
|
+
export const setAudioOutput = (service: ServiceChannel<RtcMediaEvents>, output: AudioOutput): Promise<void> =>
|
|
48
|
+
service._call("setAudioOutput", [output])
|
|
49
|
+
|
|
50
|
+
// ---- what the host's half has --------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
/** A method of the contract. */
|
|
53
|
+
export type Method = "getUserMedia" | "enumerateDevices" | "setTrackEnabled" | "applyConstraints" | "getTrackSettings" | "stopTrack" | "setAudioOutput"
|
|
54
|
+
|
|
55
|
+
/** Whether this host has the service "rtcMedia" — and, given a method, a half new enough for it
|
|
56
|
+
* (a method added after the first version of the contract is tagged `@since`). */
|
|
57
|
+
export const supports = (method?: Method): boolean =>
|
|
58
|
+
ServiceChannel.supports(NAME) // every method is of version 1
|
|
59
|
+
|
|
60
|
+
// ---- the client -----------------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
/** The devices: capture, the device list, the audio route. One session for the app. */
|
|
63
|
+
export class RtcMediaBase extends ServiceChannel<RtcMediaEvents> {
|
|
64
|
+
constructor(params: RtcMediaParams = {}) { super("RtcMedia", NAME, params) }
|
|
65
|
+
|
|
66
|
+
/** Capture: prompts for the permissions it needs, resolves with a stream of the new tracks.
|
|
67
|
+
* Rejects with "denied" / "notFound" / "failed". */
|
|
68
|
+
getUserMedia(constraints: MediaConstraints): Promise<StreamInfo> { return getUserMedia(this, constraints) }
|
|
69
|
+
/** The devices the host can capture with (labels need a granted permission on the web). */
|
|
70
|
+
enumerateDevices(): Promise<DeviceInfo[]> { return enumerateDevices(this) }
|
|
71
|
+
/** A disabled track sends silence / black frames and stays in every connection.
|
|
72
|
+
* Rejects with "notFound". */
|
|
73
|
+
setTrackEnabled(trackId: string, enabled: boolean): Promise<void> { return setTrackEnabled(this, trackId, enabled) }
|
|
74
|
+
/** Re-aim a local video track: the other camera, another size or rate. The track and its id
|
|
75
|
+
* stay; every connection keeps sending it.
|
|
76
|
+
* Rejects with "notFound" / "failed". */
|
|
77
|
+
applyConstraints(trackId: string, constraints: VideoConstraints): Promise<void> { return applyConstraints(this, trackId, constraints) }
|
|
78
|
+
/** Rejects with "notFound". */
|
|
79
|
+
getTrackSettings(trackId: string): Promise<TrackSettings> { return getTrackSettings(this, trackId) }
|
|
80
|
+
/** End a track: the device is released once no track of it is left, every sender of it goes
|
|
81
|
+
* quiet, the id is forgotten. A no-op for an unknown id. */
|
|
82
|
+
stopTrack(trackId: string): Promise<void> { return stopTrack(this, trackId) }
|
|
83
|
+
/** Route the audio of the call: the earpiece (the default while a wired or Bluetooth headset is
|
|
84
|
+
* not connected) or the loudspeaker. A no-op on the web. */
|
|
85
|
+
setAudioOutput(output: AudioOutput): Promise<void> { return setAudioOutput(this, output) }
|
|
86
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/webrtc/sdk/webrtc.RtcPeerConnection.gen.ts — do not edit here.
|
|
2
|
+
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
|
+
// GENERATED by `lecodes plugin gen` from contract.d.ts — do not edit.
|
|
4
|
+
// webrtc: the service "rtcPeerConnection", contract version 1.
|
|
5
|
+
|
|
6
|
+
import { ServiceChannel, type Json } from "../../../../plugin"
|
|
7
|
+
import type { DataChannelInfo, DataChannelInit, IceCandidate, MediaKind, OfferOptions, RtcConfiguration, RtcPeerConnectionEvents, SenderInfo, SenderParameters, SessionDescription, TransceiverDirection, TransceiverInfo, TransceiverInit } from "../contract"
|
|
8
|
+
|
|
9
|
+
/** What the halves register under. */
|
|
10
|
+
export const NAME = "rtcPeerConnection"
|
|
11
|
+
/** The contract's version: the highest `@since` of its members. */
|
|
12
|
+
export const VERSION = 1
|
|
13
|
+
|
|
14
|
+
// ---- the wire, call by call ----------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/** Rejects with "failed" / "closed". */
|
|
17
|
+
export const createOffer = (service: ServiceChannel<RtcPeerConnectionEvents>, options?: OfferOptions): Promise<SessionDescription> =>
|
|
18
|
+
service._call("createOffer", [options])
|
|
19
|
+
|
|
20
|
+
/** Rejects with "failed" / "closed". */
|
|
21
|
+
export const createAnswer = (service: ServiceChannel<RtcPeerConnectionEvents>): Promise<SessionDescription> =>
|
|
22
|
+
service._call("createAnswer", [])
|
|
23
|
+
|
|
24
|
+
/** Without a description: the implicit form — an answer when a remote offer is pending, an
|
|
25
|
+
* offer otherwise. Resolves with the description now in force (the one to signal).
|
|
26
|
+
* Rejects with "failed" / "closed". */
|
|
27
|
+
export const setLocalDescription = (service: ServiceChannel<RtcPeerConnectionEvents>, description?: SessionDescription): Promise<SessionDescription> =>
|
|
28
|
+
service._call("setLocalDescription", [description])
|
|
29
|
+
|
|
30
|
+
/** Rejects with "failed" / "closed". */
|
|
31
|
+
export const setRemoteDescription = (service: ServiceChannel<RtcPeerConnectionEvents>, description: SessionDescription): Promise<void> =>
|
|
32
|
+
service._call("setRemoteDescription", [description])
|
|
33
|
+
|
|
34
|
+
/** Without a candidate: the end of the remote candidates.
|
|
35
|
+
* Rejects with "failed" / "closed". */
|
|
36
|
+
export const addIceCandidate = (service: ServiceChannel<RtcPeerConnectionEvents>, candidate?: IceCandidate): Promise<void> =>
|
|
37
|
+
service._call("addIceCandidate", [candidate])
|
|
38
|
+
|
|
39
|
+
/** The next offer carries new ICE credentials. */
|
|
40
|
+
export const restartIce = (service: ServiceChannel<RtcPeerConnectionEvents>): Promise<void> =>
|
|
41
|
+
service._call("restartIce", [])
|
|
42
|
+
|
|
43
|
+
/** Rejects with "failed". */
|
|
44
|
+
export const setConfiguration = (service: ServiceChannel<RtcPeerConnectionEvents>, configuration: RtcConfiguration): Promise<void> =>
|
|
45
|
+
service._call("setConfiguration", [configuration])
|
|
46
|
+
|
|
47
|
+
/** Send a local track, in the streams named (one is made up when none is).
|
|
48
|
+
* Rejects with "notFound" / "failed" / "closed". */
|
|
49
|
+
export const addTrack = (service: ServiceChannel<RtcPeerConnectionEvents>, trackId: string, streamIds?: string[]): Promise<SenderInfo> =>
|
|
50
|
+
service._call("addTrack", [trackId, streamIds])
|
|
51
|
+
|
|
52
|
+
/** Rejects with "notFound" / "closed". */
|
|
53
|
+
export const removeTrack = (service: ServiceChannel<RtcPeerConnectionEvents>, senderId: string): Promise<void> =>
|
|
54
|
+
service._call("removeTrack", [senderId])
|
|
55
|
+
|
|
56
|
+
/** Swap what a sender sends without renegotiating; null = send nothing.
|
|
57
|
+
* Rejects with "notFound" / "failed" / "closed". */
|
|
58
|
+
export const replaceTrack = (service: ServiceChannel<RtcPeerConnectionEvents>, senderId: string, trackId: string | null): Promise<void> =>
|
|
59
|
+
service._call("replaceTrack", [senderId, trackId])
|
|
60
|
+
|
|
61
|
+
/** Rejects with "notFound". */
|
|
62
|
+
export const getSenderParameters = (service: ServiceChannel<RtcPeerConnectionEvents>, senderId: string): Promise<SenderParameters> =>
|
|
63
|
+
service._call("getSenderParameters", [senderId])
|
|
64
|
+
|
|
65
|
+
/** The encodings' active / bitrate / scale; the layers themselves are set at addTransceiver.
|
|
66
|
+
* Rejects with "notFound" / "failed". */
|
|
67
|
+
export const setSenderParameters = (service: ServiceChannel<RtcPeerConnectionEvents>, senderId: string, parameters: SenderParameters): Promise<void> =>
|
|
68
|
+
service._call("setSenderParameters", [senderId, parameters])
|
|
69
|
+
|
|
70
|
+
/** Rejects with "notFound" / "failed" / "closed". */
|
|
71
|
+
export const addTransceiver = (service: ServiceChannel<RtcPeerConnectionEvents>, kind: MediaKind, options?: TransceiverInit): Promise<TransceiverInfo> =>
|
|
72
|
+
service._call("addTransceiver", [kind, options])
|
|
73
|
+
|
|
74
|
+
export const getTransceivers = (service: ServiceChannel<RtcPeerConnectionEvents>): Promise<TransceiverInfo[]> =>
|
|
75
|
+
service._call("getTransceivers", [])
|
|
76
|
+
|
|
77
|
+
/** Rejects with "notFound" / "failed". */
|
|
78
|
+
export const setTransceiverDirection = (service: ServiceChannel<RtcPeerConnectionEvents>, transceiverId: string, direction: TransceiverDirection): Promise<void> =>
|
|
79
|
+
service._call("setTransceiverDirection", [transceiverId, direction])
|
|
80
|
+
|
|
81
|
+
/** Rejects with "notFound". */
|
|
82
|
+
export const stopTransceiver = (service: ServiceChannel<RtcPeerConnectionEvents>, transceiverId: string): Promise<void> =>
|
|
83
|
+
service._call("stopTransceiver", [transceiverId])
|
|
84
|
+
|
|
85
|
+
/** The RTCStatsReport as an object: the stats id → the stats object (`type`, `timestamp` in ms,
|
|
86
|
+
* the fields of its type). For one track's senders / receivers when `trackId` is given. */
|
|
87
|
+
export const getStats = (service: ServiceChannel<RtcPeerConnectionEvents>, trackId?: string): Promise<Json> =>
|
|
88
|
+
service._call("getStats", [trackId])
|
|
89
|
+
|
|
90
|
+
/** Rejects with "failed" / "closed". */
|
|
91
|
+
export const createDataChannel = (service: ServiceChannel<RtcPeerConnectionEvents>, label: string, options?: DataChannelInit): Promise<DataChannelInfo> =>
|
|
92
|
+
service._call("createDataChannel", [label, options])
|
|
93
|
+
|
|
94
|
+
/** Rejects with "notFound" / "closed". */
|
|
95
|
+
export const sendText = (service: ServiceChannel<RtcPeerConnectionEvents>, channelId: string, text: string): Promise<void> =>
|
|
96
|
+
service._call("sendText", [channelId, text])
|
|
97
|
+
|
|
98
|
+
/** Rejects with "notFound" / "closed". */
|
|
99
|
+
export const sendBinary = (service: ServiceChannel<RtcPeerConnectionEvents>, channelId: string, data: Uint8Array): Promise<void> =>
|
|
100
|
+
service._call("sendBinary", [channelId, data])
|
|
101
|
+
|
|
102
|
+
/** Bytes queued and not yet sent.
|
|
103
|
+
* Rejects with "notFound". */
|
|
104
|
+
export const getBufferedAmount = (service: ServiceChannel<RtcPeerConnectionEvents>, channelId: string): Promise<number> =>
|
|
105
|
+
service._call("getBufferedAmount", [channelId])
|
|
106
|
+
|
|
107
|
+
/** Rejects with "notFound". */
|
|
108
|
+
export const setBufferedAmountLowThreshold = (service: ServiceChannel<RtcPeerConnectionEvents>, channelId: string, threshold: number): Promise<void> =>
|
|
109
|
+
service._call("setBufferedAmountLowThreshold", [channelId, threshold])
|
|
110
|
+
|
|
111
|
+
/** A no-op for an unknown id. */
|
|
112
|
+
export const closeDataChannel = (service: ServiceChannel<RtcPeerConnectionEvents>, channelId: string): Promise<void> =>
|
|
113
|
+
service._call("closeDataChannel", [channelId])
|
|
114
|
+
|
|
115
|
+
// ---- what the host's half has --------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
/** A method of the contract. */
|
|
118
|
+
export type Method = "createOffer" | "createAnswer" | "setLocalDescription" | "setRemoteDescription" | "addIceCandidate" | "restartIce" | "setConfiguration" | "addTrack" | "removeTrack" | "replaceTrack" | "getSenderParameters" | "setSenderParameters" | "addTransceiver" | "getTransceivers" | "setTransceiverDirection" | "stopTransceiver" | "getStats" | "createDataChannel" | "sendText" | "sendBinary" | "getBufferedAmount" | "setBufferedAmountLowThreshold" | "closeDataChannel"
|
|
119
|
+
|
|
120
|
+
/** Whether this host has the service "rtcPeerConnection" — and, given a method, a half new enough for it
|
|
121
|
+
* (a method added after the first version of the contract is tagged `@since`). */
|
|
122
|
+
export const supports = (method?: Method): boolean =>
|
|
123
|
+
ServiceChannel.supports(NAME) // every method is of version 1
|
|
124
|
+
|
|
125
|
+
// ---- the client -----------------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
/** One RTCPeerConnection: a session, created with its configuration, closed by the SDK's close(). */
|
|
128
|
+
export class RtcPeerConnectionBase extends ServiceChannel<RtcPeerConnectionEvents> {
|
|
129
|
+
constructor(params: RtcConfiguration = {}) { super("RtcPeerConnection", NAME, params) }
|
|
130
|
+
|
|
131
|
+
/** Rejects with "failed" / "closed". */
|
|
132
|
+
createOffer(options?: OfferOptions): Promise<SessionDescription> { return createOffer(this, options) }
|
|
133
|
+
/** Rejects with "failed" / "closed". */
|
|
134
|
+
createAnswer(): Promise<SessionDescription> { return createAnswer(this) }
|
|
135
|
+
/** Without a description: the implicit form — an answer when a remote offer is pending, an
|
|
136
|
+
* offer otherwise. Resolves with the description now in force (the one to signal).
|
|
137
|
+
* Rejects with "failed" / "closed". */
|
|
138
|
+
setLocalDescription(description?: SessionDescription): Promise<SessionDescription> { return setLocalDescription(this, description) }
|
|
139
|
+
/** Rejects with "failed" / "closed". */
|
|
140
|
+
setRemoteDescription(description: SessionDescription): Promise<void> { return setRemoteDescription(this, description) }
|
|
141
|
+
/** Without a candidate: the end of the remote candidates.
|
|
142
|
+
* Rejects with "failed" / "closed". */
|
|
143
|
+
addIceCandidate(candidate?: IceCandidate): Promise<void> { return addIceCandidate(this, candidate) }
|
|
144
|
+
/** The next offer carries new ICE credentials. */
|
|
145
|
+
restartIce(): Promise<void> { return restartIce(this) }
|
|
146
|
+
/** Rejects with "failed". */
|
|
147
|
+
setConfiguration(configuration: RtcConfiguration): Promise<void> { return setConfiguration(this, configuration) }
|
|
148
|
+
/** Send a local track, in the streams named (one is made up when none is).
|
|
149
|
+
* Rejects with "notFound" / "failed" / "closed". */
|
|
150
|
+
addTrack(trackId: string, streamIds?: string[]): Promise<SenderInfo> { return addTrack(this, trackId, streamIds) }
|
|
151
|
+
/** Rejects with "notFound" / "closed". */
|
|
152
|
+
removeTrack(senderId: string): Promise<void> { return removeTrack(this, senderId) }
|
|
153
|
+
/** Swap what a sender sends without renegotiating; null = send nothing.
|
|
154
|
+
* Rejects with "notFound" / "failed" / "closed". */
|
|
155
|
+
replaceTrack(senderId: string, trackId: string | null): Promise<void> { return replaceTrack(this, senderId, trackId) }
|
|
156
|
+
/** Rejects with "notFound". */
|
|
157
|
+
getSenderParameters(senderId: string): Promise<SenderParameters> { return getSenderParameters(this, senderId) }
|
|
158
|
+
/** The encodings' active / bitrate / scale; the layers themselves are set at addTransceiver.
|
|
159
|
+
* Rejects with "notFound" / "failed". */
|
|
160
|
+
setSenderParameters(senderId: string, parameters: SenderParameters): Promise<void> { return setSenderParameters(this, senderId, parameters) }
|
|
161
|
+
/** Rejects with "notFound" / "failed" / "closed". */
|
|
162
|
+
addTransceiver(kind: MediaKind, options?: TransceiverInit): Promise<TransceiverInfo> { return addTransceiver(this, kind, options) }
|
|
163
|
+
getTransceivers(): Promise<TransceiverInfo[]> { return getTransceivers(this) }
|
|
164
|
+
/** Rejects with "notFound" / "failed". */
|
|
165
|
+
setTransceiverDirection(transceiverId: string, direction: TransceiverDirection): Promise<void> { return setTransceiverDirection(this, transceiverId, direction) }
|
|
166
|
+
/** Rejects with "notFound". */
|
|
167
|
+
stopTransceiver(transceiverId: string): Promise<void> { return stopTransceiver(this, transceiverId) }
|
|
168
|
+
/** The RTCStatsReport as an object: the stats id → the stats object (`type`, `timestamp` in ms,
|
|
169
|
+
* the fields of its type). For one track's senders / receivers when `trackId` is given. */
|
|
170
|
+
getStats(trackId?: string): Promise<Json> { return getStats(this, trackId) }
|
|
171
|
+
/** Rejects with "failed" / "closed". */
|
|
172
|
+
createDataChannel(label: string, options?: DataChannelInit): Promise<DataChannelInfo> { return createDataChannel(this, label, options) }
|
|
173
|
+
/** Rejects with "notFound" / "closed". */
|
|
174
|
+
sendText(channelId: string, text: string): Promise<void> { return sendText(this, channelId, text) }
|
|
175
|
+
/** Rejects with "notFound" / "closed". */
|
|
176
|
+
sendBinary(channelId: string, data: Uint8Array): Promise<void> { return sendBinary(this, channelId, data) }
|
|
177
|
+
/** Bytes queued and not yet sent.
|
|
178
|
+
* Rejects with "notFound". */
|
|
179
|
+
getBufferedAmount(channelId: string): Promise<number> { return getBufferedAmount(this, channelId) }
|
|
180
|
+
/** Rejects with "notFound". */
|
|
181
|
+
setBufferedAmountLowThreshold(channelId: string, threshold: number): Promise<void> { return setBufferedAmountLowThreshold(this, channelId, threshold) }
|
|
182
|
+
/** A no-op for an unknown id. */
|
|
183
|
+
closeDataChannel(channelId: string): Promise<void> { return closeDataChannel(this, channelId) }
|
|
184
|
+
}
|