@droponair/sdk-js 0.14.0 → 0.15.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 +13 -0
- package/README.md +29 -0
- package/dist/core/messaging-client.d.ts +5 -0
- package/dist/core/messaging-client.js +29 -0
- package/dist/core/types.d.ts +17 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ This project follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [0.15.0], 2026-05-21
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Live stage roles & audience controls.** A room created with `policy.stageMode` runs its live call as a stage: hosts join as speakers, everyone else joins as receive-only audience. New `raiseHand` / `lowerHand` (any participant), `promoteToSpeaker` / `demoteToAudience` (host / co-host), and `submitStageQuestion` - all act on the callId from `joinRoom`. Role changes surface via `GROUP_CALL_ROLE_CHANGED` events (role `SPEAKER` / `AUDIENCE`); the room-call participant list now carries each participant's role.
|
|
14
|
+
- New `GROUP_CALL_STAGE_*` event types.
|
|
15
|
+
|
|
16
|
+
### Notes
|
|
17
|
+
|
|
18
|
+
- Stage mode is a roles + signaling layer, the media topology is still the WebRTC mesh, suited to panels and small/medium stages. Large-audience streaming needs an SFU and is out of scope. Pure control-plane signaling; no proto change.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
9
22
|
## [0.14.0], 2026-05-21
|
|
10
23
|
|
|
11
24
|
### Added
|
package/README.md
CHANGED
|
@@ -333,6 +333,35 @@ client.sendGroupCallSignal('GROUP_CALL_SDP_OFFER', callId, '', peerUserId, sdp);
|
|
|
333
333
|
|
|
334
334
|
`joinRoom` rejects with `HOST_REQUIRED`, `ROOM_CLOSED`, or `WAITING_ROOM_PENDING` (listen for `GROUP_CALL_WAITING_ROOM_ADMITTED`, then call `joinRoom` again).
|
|
335
335
|
|
|
336
|
+
### Live Stage
|
|
337
|
+
|
|
338
|
+
Available since SDK `0.15.0`. Create a room with `policy.stageMode` and its live call runs as a stage: hosts join as **speakers**, everyone else joins as receive-only **audience**. Audience can raise a hand; a host promotes them to speaker. The media topology is still the WebRTC mesh, so a stage is suited to panels and small/medium audiences - large-audience streaming needs an SFU and is out of scope.
|
|
339
|
+
|
|
340
|
+
| Method | Description |
|
|
341
|
+
|--------|-------------|
|
|
342
|
+
| `raiseHand(callId)` | Request promotion to speaker (any participant) |
|
|
343
|
+
| `lowerHand(callId)` | Lower your raised hand |
|
|
344
|
+
| `promoteToSpeaker(callId, userId)` | Promote an audience member (host / co-host) |
|
|
345
|
+
| `demoteToAudience(callId, userId)` | Demote a speaker (host / co-host) |
|
|
346
|
+
| `submitStageQuestion(callId, text)` | Submit a text question to the stage's speakers |
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
const room = await client.createRoom({ name: 'AMA', policy: { stageMode: true, requireHost: true } });
|
|
350
|
+
const callId = await client.joinRoom(room.roomId);
|
|
351
|
+
|
|
352
|
+
// Audience side
|
|
353
|
+
client.raiseHand(callId);
|
|
354
|
+
client.submitStageQuestion(callId, 'How does E2EE key rotation work?');
|
|
355
|
+
|
|
356
|
+
// Host side - role changes arrive as GROUP_CALL_ROLE_CHANGED events
|
|
357
|
+
client.onGroupCallEvent((e) => {
|
|
358
|
+
if (e.type === 'GROUP_CALL_STAGE_HAND_RAISED') client.promoteToSpeaker(callId, e.payload!);
|
|
359
|
+
if (e.type === 'GROUP_CALL_ROLE_CHANGED') updateStageUi(e.payload); // {"userId","role":"SPEAKER"|"AUDIENCE"}
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Audience members are receive-only by convention: on `GROUP_CALL_ROLE_CHANGED` to `AUDIENCE`, your app simply does not publish a local media track. The platform signals the role; your app owns the WebRTC tracks.
|
|
364
|
+
|
|
336
365
|
### Screen Sharing
|
|
337
366
|
|
|
338
367
|
Available since SDK `0.6.0`. The SDK only signals start/stop - capture (via the browser's `getDisplayMedia()`) and adding the resulting `MediaStreamTrack` to the existing peer connection are the app's responsibility.
|
|
@@ -289,6 +289,11 @@ export declare class MessagingClient implements DropOnAirClient {
|
|
|
289
289
|
requestWaitingRoomEntry(callId: string, groupId: string): void;
|
|
290
290
|
admitFromWaitingRoom(callId: string, groupId: string, userId: string): void;
|
|
291
291
|
rejectFromWaitingRoom(callId: string, groupId: string, userId: string): void;
|
|
292
|
+
raiseHand(callId: string): void;
|
|
293
|
+
lowerHand(callId: string): void;
|
|
294
|
+
promoteToSpeaker(callId: string, userId: string): void;
|
|
295
|
+
demoteToAudience(callId: string, userId: string): void;
|
|
296
|
+
submitStageQuestion(callId: string, text: string): void;
|
|
292
297
|
private sendGroupCallFrame;
|
|
293
298
|
/**
|
|
294
299
|
* Initiate an outgoing call.
|
|
@@ -1307,6 +1307,35 @@ class MessagingClient {
|
|
|
1307
1307
|
payload: JSON.stringify({ userId }),
|
|
1308
1308
|
});
|
|
1309
1309
|
}
|
|
1310
|
+
// Live stage controls (Feature 3.2). These act on a room call running in
|
|
1311
|
+
// stage mode; pass the callId from joinRoom(). raiseHand / lowerHand and
|
|
1312
|
+
// submitStageQuestion are open to any participant; promote / demote are
|
|
1313
|
+
// host / co-host authority. Roles surface via GROUP_CALL_ROLE_CHANGED.
|
|
1314
|
+
raiseHand(callId) {
|
|
1315
|
+
this.sendGroupCallFrame({ type: 'GROUP_CALL_STAGE_HAND_RAISED', callId, groupId: '' });
|
|
1316
|
+
}
|
|
1317
|
+
lowerHand(callId) {
|
|
1318
|
+
this.sendGroupCallFrame({ type: 'GROUP_CALL_STAGE_HAND_LOWERED', callId, groupId: '' });
|
|
1319
|
+
}
|
|
1320
|
+
promoteToSpeaker(callId, userId) {
|
|
1321
|
+
this.sendGroupCallFrame({
|
|
1322
|
+
type: 'GROUP_CALL_STAGE_PROMOTE',
|
|
1323
|
+
callId,
|
|
1324
|
+
groupId: '',
|
|
1325
|
+
payload: JSON.stringify({ userId }),
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
demoteToAudience(callId, userId) {
|
|
1329
|
+
this.sendGroupCallFrame({
|
|
1330
|
+
type: 'GROUP_CALL_STAGE_DEMOTE',
|
|
1331
|
+
callId,
|
|
1332
|
+
groupId: '',
|
|
1333
|
+
payload: JSON.stringify({ userId }),
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
submitStageQuestion(callId, text) {
|
|
1337
|
+
this.sendGroupCallFrame({ type: 'GROUP_CALL_STAGE_QUESTION', callId, groupId: '', payload: text });
|
|
1338
|
+
}
|
|
1310
1339
|
sendGroupCallFrame(frame) {
|
|
1311
1340
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
1312
1341
|
throw new Error('DropOnAir websocket is not connected');
|
package/dist/core/types.d.ts
CHANGED
|
@@ -135,7 +135,7 @@ export interface DecryptedGroupMessage {
|
|
|
135
135
|
plaintext: string;
|
|
136
136
|
}
|
|
137
137
|
export type GroupMessageCallback = (message: DecryptedGroupMessage) => void;
|
|
138
|
-
export type GroupCallEventType = 'GROUP_CALL_INVITE' | 'GROUP_CALL_RINGING' | 'GROUP_CALL_JOIN' | 'GROUP_CALL_LEAVE' | 'GROUP_CALL_END' | 'GROUP_CALL_ENDED' | 'GROUP_CALL_PARTICIPANT_JOINED' | 'GROUP_CALL_PARTICIPANT_LEFT' | 'GROUP_CALL_PARTICIPANT_REMOVED' | 'GROUP_CALL_ALREADY_ACTIVE' | 'GROUP_CALL_SDP_OFFER' | 'GROUP_CALL_SDP_ANSWER' | 'GROUP_CALL_ICE_CANDIDATE' | 'GROUP_CALL_SCREEN_SHARE_STARTED' | 'GROUP_CALL_SCREEN_SHARE_STOPPED' | 'GROUP_CALL_HOST_TRANSFER' | 'GROUP_CALL_COHOST_APPOINT' | 'GROUP_CALL_COHOST_REVOKE' | 'GROUP_CALL_ROLE_CHANGED' | 'GROUP_CALL_MUTE_PARTICIPANT' | 'GROUP_CALL_REMOVE_PARTICIPANT' | 'GROUP_CALL_WAITING_ROOM_REQUEST' | 'GROUP_CALL_WAITING_ROOM_JOINED' | 'GROUP_CALL_WAITING_ROOM_ADMIT' | 'GROUP_CALL_WAITING_ROOM_ADMITTED' | 'GROUP_CALL_WAITING_ROOM_REJECT' | 'GROUP_CALL_WAITING_ROOM_REJECTED' | 'GROUP_CALL_JOINED' | 'GROUP_CALL_WAITING_ROOM_PENDING' | 'GROUP_CALL_HOST_REQUIRED' | 'GROUP_CALL_ROOM_CLOSED';
|
|
138
|
+
export type GroupCallEventType = 'GROUP_CALL_INVITE' | 'GROUP_CALL_RINGING' | 'GROUP_CALL_JOIN' | 'GROUP_CALL_LEAVE' | 'GROUP_CALL_END' | 'GROUP_CALL_ENDED' | 'GROUP_CALL_PARTICIPANT_JOINED' | 'GROUP_CALL_PARTICIPANT_LEFT' | 'GROUP_CALL_PARTICIPANT_REMOVED' | 'GROUP_CALL_ALREADY_ACTIVE' | 'GROUP_CALL_SDP_OFFER' | 'GROUP_CALL_SDP_ANSWER' | 'GROUP_CALL_ICE_CANDIDATE' | 'GROUP_CALL_SCREEN_SHARE_STARTED' | 'GROUP_CALL_SCREEN_SHARE_STOPPED' | 'GROUP_CALL_HOST_TRANSFER' | 'GROUP_CALL_COHOST_APPOINT' | 'GROUP_CALL_COHOST_REVOKE' | 'GROUP_CALL_ROLE_CHANGED' | 'GROUP_CALL_MUTE_PARTICIPANT' | 'GROUP_CALL_REMOVE_PARTICIPANT' | 'GROUP_CALL_WAITING_ROOM_REQUEST' | 'GROUP_CALL_WAITING_ROOM_JOINED' | 'GROUP_CALL_WAITING_ROOM_ADMIT' | 'GROUP_CALL_WAITING_ROOM_ADMITTED' | 'GROUP_CALL_WAITING_ROOM_REJECT' | 'GROUP_CALL_WAITING_ROOM_REJECTED' | 'GROUP_CALL_JOINED' | 'GROUP_CALL_WAITING_ROOM_PENDING' | 'GROUP_CALL_HOST_REQUIRED' | 'GROUP_CALL_ROOM_CLOSED' | 'GROUP_CALL_STAGE_HAND_RAISED' | 'GROUP_CALL_STAGE_HAND_LOWERED' | 'GROUP_CALL_STAGE_PROMOTE' | 'GROUP_CALL_STAGE_DEMOTE' | 'GROUP_CALL_STAGE_QUESTION';
|
|
139
139
|
export interface GroupCallEvent {
|
|
140
140
|
type: GroupCallEventType | string;
|
|
141
141
|
callId: string;
|
|
@@ -159,6 +159,12 @@ export interface RoomPolicy {
|
|
|
159
159
|
maxParticipants?: number;
|
|
160
160
|
/** When true, the room flips to CLOSED once the last participant leaves the call. */
|
|
161
161
|
autoCloseWhenEmpty?: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* When true, the room's live call runs in stage mode (Feature 3.2): hosts
|
|
164
|
+
* join as speakers, everyone else as receive-only audience who can raise a
|
|
165
|
+
* hand to be promoted. Mesh-scale - suited to panels and small stages.
|
|
166
|
+
*/
|
|
167
|
+
stageMode?: boolean;
|
|
162
168
|
}
|
|
163
169
|
export interface Room {
|
|
164
170
|
roomId: string;
|
|
@@ -486,4 +492,14 @@ export interface DropOnAirClient {
|
|
|
486
492
|
joinRoom(roomId: string): Promise<string>;
|
|
487
493
|
/** Leave the live call in a room. */
|
|
488
494
|
leaveRoom(callId: string): Promise<void>;
|
|
495
|
+
/** Raise your hand to request promotion to speaker (any participant). */
|
|
496
|
+
raiseHand(callId: string): void;
|
|
497
|
+
/** Lower your previously raised hand. */
|
|
498
|
+
lowerHand(callId: string): void;
|
|
499
|
+
/** Promote an audience member to speaker (host / co-host). */
|
|
500
|
+
promoteToSpeaker(callId: string, userId: string): void;
|
|
501
|
+
/** Demote a speaker back to audience (host / co-host). */
|
|
502
|
+
demoteToAudience(callId: string, userId: string): void;
|
|
503
|
+
/** Submit a text question; relayed to the stage's speakers. */
|
|
504
|
+
submitStageQuestion(callId: string, text: string): void;
|
|
489
505
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
8
8
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
9
9
|
*/
|
|
10
|
-
export declare const SDK_VERSION = "0.
|
|
10
|
+
export declare const SDK_VERSION = "0.15.0";
|
|
11
11
|
/**
|
|
12
12
|
* Binary encrypted-payload format version.
|
|
13
13
|
* Included as the first byte of every encrypted payload so receivers can
|
package/dist/version.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.PROTOCOL_VERSION = exports.PAYLOAD_FORMAT_VERSION = exports.SDK_VERSION
|
|
|
10
10
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
11
11
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
12
12
|
*/
|
|
13
|
-
exports.SDK_VERSION = '0.
|
|
13
|
+
exports.SDK_VERSION = '0.15.0';
|
|
14
14
|
/**
|
|
15
15
|
* Binary encrypted-payload format version.
|
|
16
16
|
* Included as the first byte of every encrypted payload so receivers can
|