@tiledev/sdk-apptile-live-selling 0.1.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/README.md +322 -0
- package/android/build.gradle +33 -0
- package/android/src/main/AndroidManifest.xml +7 -0
- package/android/src/main/java/expo/modules/livepip/LivePipModule.kt +310 -0
- package/app.plugin.js +3 -0
- package/dist/auctions.d.ts +3 -0
- package/dist/auctions.d.ts.map +1 -0
- package/dist/auctions.js +152 -0
- package/dist/auctions.js.map +1 -0
- package/dist/client.d.ts +63 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +154 -0
- package/dist/client.js.map +1 -0
- package/dist/clips.d.ts +3 -0
- package/dist/clips.d.ts.map +1 -0
- package/dist/clips.js +53 -0
- package/dist/clips.js.map +1 -0
- package/dist/commentLinks.d.ts +46 -0
- package/dist/commentLinks.d.ts.map +1 -0
- package/dist/commentLinks.js +120 -0
- package/dist/commentLinks.js.map +1 -0
- package/dist/engine.d.ts +13 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +40 -0
- package/dist/engine.js.map +1 -0
- package/dist/engine.native.d.ts +3 -0
- package/dist/engine.native.d.ts.map +1 -0
- package/dist/engine.native.js +815 -0
- package/dist/engine.native.js.map +1 -0
- package/dist/flags.d.ts +5 -0
- package/dist/flags.d.ts.map +1 -0
- package/dist/flags.js +61 -0
- package/dist/flags.js.map +1 -0
- package/dist/guest.d.ts +5 -0
- package/dist/guest.d.ts.map +1 -0
- package/dist/guest.js +89 -0
- package/dist/guest.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/liveSelling.d.ts +3 -0
- package/dist/liveSelling.d.ts.map +1 -0
- package/dist/liveSelling.js +44 -0
- package/dist/liveSelling.js.map +1 -0
- package/dist/nativeViewTag.d.ts +15 -0
- package/dist/nativeViewTag.d.ts.map +1 -0
- package/dist/nativeViewTag.js +23 -0
- package/dist/nativeViewTag.js.map +1 -0
- package/dist/pip.d.ts +14 -0
- package/dist/pip.d.ts.map +1 -0
- package/dist/pip.js +15 -0
- package/dist/pip.js.map +1 -0
- package/dist/pip.native.d.ts +11 -0
- package/dist/pip.native.d.ts.map +1 -0
- package/dist/pip.native.js +47 -0
- package/dist/pip.native.js.map +1 -0
- package/dist/polls.d.ts +11 -0
- package/dist/polls.d.ts.map +1 -0
- package/dist/polls.js +135 -0
- package/dist/polls.js.map +1 -0
- package/dist/react/LiveSellingProvider.d.ts +16 -0
- package/dist/react/LiveSellingProvider.d.ts.map +1 -0
- package/dist/react/LiveSellingProvider.js +49 -0
- package/dist/react/LiveSellingProvider.js.map +1 -0
- package/dist/react/LiveVideoTarget.d.ts +22 -0
- package/dist/react/LiveVideoTarget.d.ts.map +1 -0
- package/dist/react/LiveVideoTarget.js +73 -0
- package/dist/react/LiveVideoTarget.js.map +1 -0
- package/dist/react/index.d.ts +19 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +43 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useAuction.d.ts +28 -0
- package/dist/react/useAuction.d.ts.map +1 -0
- package/dist/react/useAuction.js +66 -0
- package/dist/react/useAuction.js.map +1 -0
- package/dist/react/useAuctionBidGate.d.ts +48 -0
- package/dist/react/useAuctionBidGate.d.ts.map +1 -0
- package/dist/react/useAuctionBidGate.js +144 -0
- package/dist/react/useAuctionBidGate.js.map +1 -0
- package/dist/react/useAuctionWins.d.ts +51 -0
- package/dist/react/useAuctionWins.d.ts.map +1 -0
- package/dist/react/useAuctionWins.js +268 -0
- package/dist/react/useAuctionWins.js.map +1 -0
- package/dist/react/useClips.d.ts +9 -0
- package/dist/react/useClips.d.ts.map +1 -0
- package/dist/react/useClips.js +37 -0
- package/dist/react/useClips.js.map +1 -0
- package/dist/react/useLiveSession.d.ts +34 -0
- package/dist/react/useLiveSession.d.ts.map +1 -0
- package/dist/react/useLiveSession.js +876 -0
- package/dist/react/useLiveSession.js.map +1 -0
- package/dist/react/useLiveStreams.d.ts +9 -0
- package/dist/react/useLiveStreams.d.ts.map +1 -0
- package/dist/react/useLiveStreams.js +35 -0
- package/dist/react/useLiveStreams.js.map +1 -0
- package/dist/react/useOngoingLive.d.ts +13 -0
- package/dist/react/useOngoingLive.d.ts.map +1 -0
- package/dist/react/useOngoingLive.js +45 -0
- package/dist/react/useOngoingLive.js.map +1 -0
- package/dist/react/useReplays.d.ts +15 -0
- package/dist/react/useReplays.d.ts.map +1 -0
- package/dist/react/useReplays.js +66 -0
- package/dist/react/useReplays.js.map +1 -0
- package/dist/react/useStreamInfo.d.ts +21 -0
- package/dist/react/useStreamInfo.d.ts.map +1 -0
- package/dist/react/useStreamInfo.js +125 -0
- package/dist/react/useStreamInfo.js.map +1 -0
- package/dist/replays.d.ts +3 -0
- package/dist/replays.d.ts.map +1 -0
- package/dist/replays.js +114 -0
- package/dist/replays.js.map +1 -0
- package/dist/session.d.ts +23 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +464 -0
- package/dist/session.js.map +1 -0
- package/dist/sessionTypes.d.ts +462 -0
- package/dist/sessionTypes.d.ts.map +1 -0
- package/dist/sessionTypes.js +55 -0
- package/dist/sessionTypes.js.map +1 -0
- package/dist/streams.d.ts +67 -0
- package/dist/streams.d.ts.map +1 -0
- package/dist/streams.js +170 -0
- package/dist/streams.js.map +1 -0
- package/dist/types.d.ts +591 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/viewer.d.ts +5 -0
- package/dist/viewer.d.ts.map +1 -0
- package/dist/viewer.js +66 -0
- package/dist/viewer.js.map +1 -0
- package/dist/wire.d.ts +155 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +73 -0
- package/dist/wire.js.map +1 -0
- package/dist/zego.d.ts +83 -0
- package/dist/zego.d.ts.map +1 -0
- package/dist/zego.js +13 -0
- package/dist/zego.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/LivePip.podspec +20 -0
- package/ios/LivePipController.swift +327 -0
- package/ios/LivePipModule.swift +35 -0
- package/package.json +91 -0
- package/plugin/build/index.d.ts +29 -0
- package/plugin/build/index.js +101 -0
- package/react/package.json +6 -0
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.engine = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Live engine — NATIVE build (iOS / Android), driving `zego-express-engine-reactnative`.
|
|
6
|
+
*
|
|
7
|
+
* Sole owner of the Zego engine: a module singleton, because the engine *is* a process-wide singleton.
|
|
8
|
+
* The room is joined and left and the render target is rebindable, rather than the engine being created
|
|
9
|
+
* and destroyed per mount (which caused the re-login churn the source blames for an Android
|
|
10
|
+
* NetworkCallback leak).
|
|
11
|
+
*
|
|
12
|
+
* The Zego SDK is an OPTIONAL peer, pulled in with a lazy `require()` inside `createEngine` so this file
|
|
13
|
+
* carries no static import of it — that keeps the native SDK out of every non-native bundle and lets
|
|
14
|
+
* the pure `tsc --noEmit` pass without the Zego types installed. Metro resolves this file on-device and
|
|
15
|
+
* `engine.ts` (a no-op) everywhere else; keep the two signatures in lock-step.
|
|
16
|
+
*
|
|
17
|
+
* Ported from the app's `liveStreamService.ts`, with one app coupling lifted: the platform-level Zego
|
|
18
|
+
* app id comes from `configure({ zegoAppId })` rather than a config global.
|
|
19
|
+
*
|
|
20
|
+
* The engine also feeds the system picture-in-picture module — which stream is playing, and nothing
|
|
21
|
+
* more. It has to be told here rather than by the session, because only this file knows when the
|
|
22
|
+
* played id actually changes: a co-host mixer swap moves it from `{id}` to `{id}_mixed` with no
|
|
23
|
+
* involvement from React at all.
|
|
24
|
+
*/
|
|
25
|
+
const react_native_1 = require("react-native");
|
|
26
|
+
const client_1 = require("./client");
|
|
27
|
+
const wire_1 = require("./wire");
|
|
28
|
+
const commentLinks_1 = require("./commentLinks");
|
|
29
|
+
const pip_1 = require("./pip");
|
|
30
|
+
const guest_1 = require("./guest");
|
|
31
|
+
const polls_1 = require("./polls");
|
|
32
|
+
/** The zego module and the constructors/enums it exports, captured once at engine create. */
|
|
33
|
+
class NativeLiveEngine {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.isNoop = false;
|
|
36
|
+
this.Z = null;
|
|
37
|
+
this.engineReady = false;
|
|
38
|
+
this.creating = null;
|
|
39
|
+
this.queue = Promise.resolve();
|
|
40
|
+
this.listeners = new Set();
|
|
41
|
+
this.joined = null;
|
|
42
|
+
this.playingStreamId = null;
|
|
43
|
+
this.boundTag = null;
|
|
44
|
+
this.playingTag = null;
|
|
45
|
+
this.mixerActive = false;
|
|
46
|
+
this.guest = null;
|
|
47
|
+
this.previewTag = null;
|
|
48
|
+
this.viewerNameOverride = null;
|
|
49
|
+
this.commentSeq = 0;
|
|
50
|
+
this.mutedDeviceIds = [];
|
|
51
|
+
}
|
|
52
|
+
subscribe(listener) {
|
|
53
|
+
this.listeners.add(listener);
|
|
54
|
+
return () => {
|
|
55
|
+
this.listeners.delete(listener);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
emit(event) {
|
|
59
|
+
for (const listener of this.listeners)
|
|
60
|
+
listener(event);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The loaded SDK. Only valid after `createEngine`, and every caller below is downstream of it —
|
|
64
|
+
* throwing beats the `undefined is not a constructor` a missing enum would produce deeper in.
|
|
65
|
+
*/
|
|
66
|
+
get Zego() {
|
|
67
|
+
if (!this.Z)
|
|
68
|
+
throw new Error('Zego SDK is not loaded');
|
|
69
|
+
return this.Z;
|
|
70
|
+
}
|
|
71
|
+
/** The default export is the engine class; the enums/structs are named exports. */
|
|
72
|
+
get Engine() {
|
|
73
|
+
var _a;
|
|
74
|
+
const mod = this.Zego;
|
|
75
|
+
return ((_a = mod === null || mod === void 0 ? void 0 : mod.default) !== null && _a !== void 0 ? _a : mod);
|
|
76
|
+
}
|
|
77
|
+
async ensureEngine() {
|
|
78
|
+
if (this.engineReady)
|
|
79
|
+
return;
|
|
80
|
+
if (!this.creating)
|
|
81
|
+
this.creating = this.createEngine();
|
|
82
|
+
try {
|
|
83
|
+
await this.creating;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
this.creating = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async createEngine() {
|
|
90
|
+
var _a;
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
92
|
+
this.Z = require('zego-express-engine-reactnative');
|
|
93
|
+
const Engine = this.Engine;
|
|
94
|
+
const { ZegoScenario } = this.Zego;
|
|
95
|
+
// The native engine outlives this module, so adopt an existing instance rather than creating a
|
|
96
|
+
// second — "multiple instances" is a documented failure.
|
|
97
|
+
let existing = null;
|
|
98
|
+
try {
|
|
99
|
+
existing = Engine.instance();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
existing = null;
|
|
103
|
+
}
|
|
104
|
+
if (!existing) {
|
|
105
|
+
// appSign empty is the documented pairing for token auth; the token rides on the room config.
|
|
106
|
+
await Engine.createEngineWithProfile({
|
|
107
|
+
appID: (_a = (0, client_1.getConfig)().zegoAppId) !== null && _a !== void 0 ? _a : 0,
|
|
108
|
+
appSign: '',
|
|
109
|
+
scenario: ZegoScenario.Default,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// After the engine exists and before anything plays, and every time rather than only after a
|
|
113
|
+
// fresh create: the engine outlives this module, so an adopted one may never have been configured
|
|
114
|
+
// by this process. The native side ignores a second call.
|
|
115
|
+
try {
|
|
116
|
+
await pip_1.livePip.configure();
|
|
117
|
+
}
|
|
118
|
+
catch (caught) {
|
|
119
|
+
// A live stream without picture-in-picture is still a working live stream.
|
|
120
|
+
(0, client_1.getLogger)().error(caught, { at: 'liveEngine.configurePip' });
|
|
121
|
+
}
|
|
122
|
+
this.attachListeners();
|
|
123
|
+
this.engineReady = true;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Zego stops delivering video once the app leaves the foreground unless this is set. iOS only;
|
|
127
|
+
* Android's PIP window is the activity itself, which stays visible and keeps decoding.
|
|
128
|
+
*/
|
|
129
|
+
async setBackgroundVideoEnabled(enabled) {
|
|
130
|
+
if (!this.engineReady)
|
|
131
|
+
return;
|
|
132
|
+
if (react_native_1.Platform.OS !== 'ios')
|
|
133
|
+
return;
|
|
134
|
+
await this.Engine.instance().callExperimentalAPI(JSON.stringify({ method: 'liveroom.video.enable_ios_multitask', params: { enable: enabled } }));
|
|
135
|
+
}
|
|
136
|
+
attachListeners() {
|
|
137
|
+
const engine = this.Engine.instance();
|
|
138
|
+
const { ZegoUpdateType } = this.Zego;
|
|
139
|
+
// Clear first: attaching twice would deliver every comment and reaction twice over.
|
|
140
|
+
for (const event of [
|
|
141
|
+
'roomStateUpdate',
|
|
142
|
+
'roomStreamUpdate',
|
|
143
|
+
'roomOnlineUserCountUpdate',
|
|
144
|
+
'playerMediaEvent',
|
|
145
|
+
'roomStreamExtraInfoUpdate',
|
|
146
|
+
'IMRecvBarrageMessage',
|
|
147
|
+
'IMRecvCustomCommand',
|
|
148
|
+
'IMRecvBroadcastMessage',
|
|
149
|
+
]) {
|
|
150
|
+
try {
|
|
151
|
+
engine.off(event, undefined);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Nothing attached yet.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
engine.on('roomStateUpdate', (_roomId, stateVal) => {
|
|
158
|
+
this.emit({ type: 'roomState', connected: stateVal === 2 });
|
|
159
|
+
if (stateVal === 2)
|
|
160
|
+
this.announceJoin();
|
|
161
|
+
});
|
|
162
|
+
engine.on('roomStreamUpdate', (_roomId, updateType, streamList) => {
|
|
163
|
+
const ids = (0, wire_1.arr)(streamList).map((entry) => (0, wire_1.str)((0, wire_1.get)(entry, 'streamID')));
|
|
164
|
+
const isHost = ids.some((id) => { var _a, _b; return id === ((_a = this.joined) === null || _a === void 0 ? void 0 : _a.streamingId) || id === ((_b = this.joined) === null || _b === void 0 ? void 0 : _b.mixedStreamId); });
|
|
165
|
+
if (!isHost)
|
|
166
|
+
return;
|
|
167
|
+
this.emit({ type: 'publisher', publishing: updateType === ZegoUpdateType.Add });
|
|
168
|
+
});
|
|
169
|
+
engine.on('roomOnlineUserCountUpdate', (_roomId, count) => {
|
|
170
|
+
this.emit({ type: 'viewers', count });
|
|
171
|
+
});
|
|
172
|
+
engine.on('playerMediaEvent', (_streamId, event) => {
|
|
173
|
+
// 4/6 = video break/resume, 5/7 = audio break/resume. One field per event.
|
|
174
|
+
if (event === 4)
|
|
175
|
+
this.emit({ type: 'hostMedia', kind: 'video', broken: true });
|
|
176
|
+
if (event === 6)
|
|
177
|
+
this.emit({ type: 'hostMedia', kind: 'video', broken: false });
|
|
178
|
+
if (event === 5)
|
|
179
|
+
this.emit({ type: 'hostMedia', kind: 'audio', broken: true });
|
|
180
|
+
if (event === 7)
|
|
181
|
+
this.emit({ type: 'hostMedia', kind: 'audio', broken: false });
|
|
182
|
+
});
|
|
183
|
+
engine.on('playerQualityUpdate', (streamId, quality) => {
|
|
184
|
+
var _a;
|
|
185
|
+
if (streamId !== this.playingStreamId)
|
|
186
|
+
return;
|
|
187
|
+
this.emit({ type: 'hostVideo', receiving: ((_a = (0, wire_1.num)((0, wire_1.get)(quality, 'videoRecvFPS'))) !== null && _a !== void 0 ? _a : 0) > 0 });
|
|
188
|
+
});
|
|
189
|
+
engine.on('roomStreamExtraInfoUpdate', (_roomId, streamList) => {
|
|
190
|
+
const extra = (0, wire_1.get)((0, wire_1.arr)(streamList)[0], 'extraInfo');
|
|
191
|
+
if (!extra)
|
|
192
|
+
return;
|
|
193
|
+
this.handleExtraInfo(extra);
|
|
194
|
+
});
|
|
195
|
+
engine.on('IMRecvBarrageMessage', (_roomId, messageList) => {
|
|
196
|
+
this.handleBarrage((0, wire_1.arr)(messageList)[0]);
|
|
197
|
+
});
|
|
198
|
+
engine.on('IMRecvCustomCommand', (_roomId, _from, command) => {
|
|
199
|
+
this.handleCommand(command);
|
|
200
|
+
});
|
|
201
|
+
engine.on('IMRecvBroadcastMessage', (_roomId, messageList) => {
|
|
202
|
+
var _a;
|
|
203
|
+
// `sendTime` is the host's clock — the only reference an auction deadline can be read against.
|
|
204
|
+
const first = (0, wire_1.arr)(messageList)[0];
|
|
205
|
+
this.handleBroadcast((0, wire_1.get)(first, 'message'), (_a = (0, wire_1.num)((0, wire_1.get)(first, 'sendTime'))) !== null && _a !== void 0 ? _a : 0);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
handleExtraInfo(raw) {
|
|
209
|
+
const payload = (0, wire_1.parseJson)(raw);
|
|
210
|
+
if (!(0, wire_1.isRecord)(payload))
|
|
211
|
+
return;
|
|
212
|
+
const lot = () => { var _a; return (_a = (0, wire_1.str)((0, wire_1.path)(payload, 'data', 'store_product_id'))) !== null && _a !== void 0 ? _a : (0, wire_1.str)((0, wire_1.path)(payload, 'data', 'product_id')); };
|
|
213
|
+
switch ((0, wire_1.str)(payload.event)) {
|
|
214
|
+
case 'PRODUCT_CHANGE': {
|
|
215
|
+
const id = lot();
|
|
216
|
+
if (id)
|
|
217
|
+
this.emit({ type: 'productChange', storeProductId: id });
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
case 'DELETE_PRODUCT': {
|
|
221
|
+
const id = lot();
|
|
222
|
+
if (id)
|
|
223
|
+
this.emit({ type: 'productRemoved', storeProductId: id });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
case 'MULTIPLIER_CHANGE': {
|
|
227
|
+
const multiplier = (0, wire_1.num)(payload.count);
|
|
228
|
+
this.emit({
|
|
229
|
+
type: 'viewerMultiplier',
|
|
230
|
+
multiplier: multiplier !== null && multiplier > 0 ? multiplier : 1,
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
default:
|
|
235
|
+
this.emit({ type: 'unknown', channel: 'extraInfo', payload });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
handleBarrage(message) {
|
|
239
|
+
var _a, _b, _c;
|
|
240
|
+
const payload = (0, wire_1.parseJson)((0, wire_1.get)(message, 'message'));
|
|
241
|
+
if (!(0, wire_1.isRecord)(payload))
|
|
242
|
+
return;
|
|
243
|
+
// The host mutes a viewer for everyone by flagging their messages, not by dropping them.
|
|
244
|
+
if (payload.muted === true)
|
|
245
|
+
return;
|
|
246
|
+
// `payload.name` wins: a bid announcement is relayed by the host's own Zego identity, so
|
|
247
|
+
// `fromUser.userName` there is the HOST's name, not the bidder's.
|
|
248
|
+
const fromUser = (0, wire_1.str)((0, wire_1.path)(message, 'fromUser', 'userName'));
|
|
249
|
+
const userName = (_b = (_a = (0, wire_1.str)(payload.name)) !== null && _a !== void 0 ? _a : fromUser) !== null && _b !== void 0 ? _b : 'Anonymous';
|
|
250
|
+
this.emit({
|
|
251
|
+
type: 'comment',
|
|
252
|
+
comment: this.makeComment((_c = (0, wire_1.str)(payload.comment)) !== null && _c !== void 0 ? _c : '', userName, payload.source, undefined, false, payload.urlPreview),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
makeComment(text, userName, source, tipAmount, isOwn, urlPreview) {
|
|
256
|
+
const known = source === 'HOST' || source === 'MODERATOR' || source === 'TIP' ? source : 'USER';
|
|
257
|
+
this.commentSeq += 1;
|
|
258
|
+
return {
|
|
259
|
+
id: `c${this.commentSeq}`,
|
|
260
|
+
text,
|
|
261
|
+
userName,
|
|
262
|
+
source: known,
|
|
263
|
+
tipAmount,
|
|
264
|
+
urlPreview: (0, commentLinks_1.toUrlPreview)(urlPreview),
|
|
265
|
+
isOwn,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
handleCommand(raw) {
|
|
269
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
270
|
+
const payload = (0, wire_1.parseJson)(raw);
|
|
271
|
+
if (!(0, wire_1.isRecord)(payload))
|
|
272
|
+
return;
|
|
273
|
+
switch ((0, wire_1.str)(payload.type)) {
|
|
274
|
+
case 'REACTION_ANNOUCEMENT':
|
|
275
|
+
this.emit({
|
|
276
|
+
type: 'reaction',
|
|
277
|
+
reactionUrl: (_a = (0, wire_1.str)(payload.reactionUrl)) !== null && _a !== void 0 ? _a : '',
|
|
278
|
+
userName: (_b = (0, wire_1.str)(payload.userName)) !== null && _b !== void 0 ? _b : 'Anonymous',
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
case 'CART_ANNOUCEMENT':
|
|
282
|
+
this.emit({
|
|
283
|
+
type: 'cartAnnouncement',
|
|
284
|
+
productTitle: (_c = (0, wire_1.str)(payload.productTitle)) !== null && _c !== void 0 ? _c : '',
|
|
285
|
+
userName: (_d = (0, wire_1.str)(payload.userName)) !== null && _d !== void 0 ? _d : 'Anonymous',
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
case 'DONATION_ANNOUCEMENT':
|
|
289
|
+
this.emit({
|
|
290
|
+
type: 'comment',
|
|
291
|
+
comment: this.makeComment('Sent a tip', (_e = (0, wire_1.str)(payload.userName)) !== null && _e !== void 0 ? _e : 'Anonymous', 'TIP', (_f = (0, wire_1.str)(payload.donationAmount)) !== null && _f !== void 0 ? _f : undefined, false),
|
|
292
|
+
});
|
|
293
|
+
return;
|
|
294
|
+
case 'PRODUCT_SOLD_ANNOUNCEMENT':
|
|
295
|
+
this.emit({
|
|
296
|
+
type: 'sold',
|
|
297
|
+
announcement: {
|
|
298
|
+
productName: (_g = (0, wire_1.str)(payload.productName)) !== null && _g !== void 0 ? _g : '',
|
|
299
|
+
variantLabel: (0, wire_1.str)(payload.variantLabel),
|
|
300
|
+
quantity: (_h = (0, wire_1.num)(payload.qty)) !== null && _h !== void 0 ? _h : 1,
|
|
301
|
+
productImage: (0, wire_1.str)(payload.productImage),
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
return;
|
|
305
|
+
case 'START_POLL':
|
|
306
|
+
this.emitPollStarted((_j = payload.poll) !== null && _j !== void 0 ? _j : (0, wire_1.path)(payload, 'data', 'poll'));
|
|
307
|
+
return;
|
|
308
|
+
case 'MUTE_USER':
|
|
309
|
+
this.mutedDeviceIds = this.mutedIdsFrom(payload.mutedUsers);
|
|
310
|
+
this.emit({ type: 'mutedUsers', deviceIds: this.mutedDeviceIds });
|
|
311
|
+
return;
|
|
312
|
+
case 'START_BIDDING':
|
|
313
|
+
this.emitBiddingStarted(payload.data, (_k = (0, wire_1.num)((0, wire_1.path)(payload, 'data', 'timeStamp'))) !== null && _k !== void 0 ? _k : 0);
|
|
314
|
+
return;
|
|
315
|
+
case 'BROADCAST_BID_INFO':
|
|
316
|
+
this.emitBidInfo(payload.data, (_l = (0, wire_1.num)(payload.serverSentTime)) !== null && _l !== void 0 ? _l : 0);
|
|
317
|
+
return;
|
|
318
|
+
case 'giveaway_start':
|
|
319
|
+
this.emitGiveawayStarted(payload.eventData);
|
|
320
|
+
return;
|
|
321
|
+
case 'giveaway_end':
|
|
322
|
+
this.emitGiveawayEnded(payload.eventData);
|
|
323
|
+
return;
|
|
324
|
+
case 'user_registered': {
|
|
325
|
+
const count = (0, wire_1.num)((0, wire_1.path)(payload, 'eventData', 'usersCount'));
|
|
326
|
+
if (count !== null)
|
|
327
|
+
this.emit({ type: 'giveawayEntries', count });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
default:
|
|
331
|
+
this.emit({ type: 'unknown', channel: 'customCommand', payload });
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/** The moderator's Zego user id, whatever shape it arrived in — an object smuggled through crashes iOS. */
|
|
335
|
+
/**
|
|
336
|
+
* Device ids out of a host mute list.
|
|
337
|
+
*
|
|
338
|
+
* Entries with no id are dropped rather than passed through: the host dashboard can record a comment
|
|
339
|
+
* with no `deviceId`, and an id-less entry would match every viewer whose id is also absent —
|
|
340
|
+
* muting one person would silence the room.
|
|
341
|
+
*/
|
|
342
|
+
mutedIdsFrom(raw) {
|
|
343
|
+
return (0, wire_1.arr)(raw)
|
|
344
|
+
.map((entry) => (0, wire_1.str)((0, wire_1.get)(entry, 'deviceId')))
|
|
345
|
+
.filter((id) => !!id);
|
|
346
|
+
}
|
|
347
|
+
moderatorIdFrom(raw) {
|
|
348
|
+
var _a, _b;
|
|
349
|
+
if (!raw)
|
|
350
|
+
return null;
|
|
351
|
+
if (typeof raw === 'string')
|
|
352
|
+
return raw;
|
|
353
|
+
if (typeof raw === 'object') {
|
|
354
|
+
const record = raw;
|
|
355
|
+
const id = (_b = (_a = record.userID) !== null && _a !== void 0 ? _a : record.userId) !== null && _b !== void 0 ? _b : record.user_id;
|
|
356
|
+
if (typeof id === 'string' && id)
|
|
357
|
+
return id;
|
|
358
|
+
if (typeof id === 'number')
|
|
359
|
+
return String(id);
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
emitBiddingStarted(data, serverNowMs) {
|
|
364
|
+
const wire = data;
|
|
365
|
+
const endsAtMs = (0, wire_1.num)((0, wire_1.get)(wire, 'endTimeStamp'));
|
|
366
|
+
if (endsAtMs === null || endsAtMs <= 0)
|
|
367
|
+
return;
|
|
368
|
+
this.emit({
|
|
369
|
+
type: 'biddingStarted',
|
|
370
|
+
endsAtMs,
|
|
371
|
+
serverNowMs: serverNowMs || endsAtMs,
|
|
372
|
+
storeProductId: (0, wire_1.str)((0, wire_1.get)(wire, 'selectedProductId')),
|
|
373
|
+
moderatorId: this.moderatorIdFrom((0, wire_1.get)(wire, 'moderatorInCharge')),
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
emitBidInfo(data, serverNowMs) {
|
|
377
|
+
var _a, _b, _c, _d;
|
|
378
|
+
const wire = data;
|
|
379
|
+
if (!(0, wire_1.isRecord)(wire))
|
|
380
|
+
return;
|
|
381
|
+
const endsAtMs = (0, wire_1.num)(wire.newEndTimeStamp);
|
|
382
|
+
const user = wire.user;
|
|
383
|
+
this.emit({
|
|
384
|
+
type: 'bidInfo',
|
|
385
|
+
highestBid: (_a = (0, wire_1.num)(wire.newHighestBid)) !== null && _a !== void 0 ? _a : 0,
|
|
386
|
+
nextBid: (_b = (0, wire_1.num)(wire.nextBid)) !== null && _b !== void 0 ? _b : 0,
|
|
387
|
+
endsAtMs: endsAtMs !== null && endsAtMs > 0 ? endsAtMs : null,
|
|
388
|
+
serverNowMs,
|
|
389
|
+
leader: (0, wire_1.isRecord)(user)
|
|
390
|
+
? { userId: (_c = (0, wire_1.str)(user.userId)) !== null && _c !== void 0 ? _c : '', userName: (_d = (0, wire_1.str)(user.userName)) !== null && _d !== void 0 ? _d : '' }
|
|
391
|
+
: null,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
emitGiveawayStarted(eventData) {
|
|
395
|
+
const wire = eventData;
|
|
396
|
+
const storeProductId = (0, wire_1.str)((0, wire_1.get)(wire, 'productId'));
|
|
397
|
+
if (!storeProductId)
|
|
398
|
+
return;
|
|
399
|
+
this.emit({
|
|
400
|
+
type: 'giveawayStarted',
|
|
401
|
+
storeProductId,
|
|
402
|
+
variantId: (0, wire_1.str)((0, wire_1.get)(wire, 'variantId')),
|
|
403
|
+
entryCount: (0, wire_1.num)((0, wire_1.get)(wire, 'userCount')),
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
emitGiveawayEnded(eventData) {
|
|
407
|
+
const storeProductId = (0, wire_1.str)((0, wire_1.get)(eventData, 'productId'));
|
|
408
|
+
if (!storeProductId)
|
|
409
|
+
return;
|
|
410
|
+
// The host sends the literal string "null" when a giveaway closes with nobody in it, so only an
|
|
411
|
+
// object is a real winner.
|
|
412
|
+
const winner = (0, wire_1.get)(eventData, 'winner');
|
|
413
|
+
const winnerName = (0, wire_1.isRecord)(winner) ? (0, wire_1.str)(winner.displayName) : null;
|
|
414
|
+
this.emit({ type: 'giveawayEnded', storeProductId, winnerName });
|
|
415
|
+
}
|
|
416
|
+
handleBroadcast(raw, serverNowMs = 0) {
|
|
417
|
+
var _a, _b, _c, _d, _e, _f;
|
|
418
|
+
const payload = (0, wire_1.parseJson)(raw);
|
|
419
|
+
if (!(0, wire_1.isRecord)(payload))
|
|
420
|
+
return;
|
|
421
|
+
switch ((0, wire_1.str)(payload.type)) {
|
|
422
|
+
case 'START_BIDDING':
|
|
423
|
+
this.emitBiddingStarted(payload.data, serverNowMs);
|
|
424
|
+
return;
|
|
425
|
+
case 'CLOSE_BIDDING':
|
|
426
|
+
this.emit({ type: 'biddingClosed' });
|
|
427
|
+
return;
|
|
428
|
+
case 'BID_WINNER_ANNOUNCEMENT': {
|
|
429
|
+
const wire = payload.data;
|
|
430
|
+
const meta = (0, wire_1.path)(wire, 'bidWinner', 'meta');
|
|
431
|
+
this.emit({
|
|
432
|
+
type: 'auctionWon',
|
|
433
|
+
win: {
|
|
434
|
+
userName: (_a = (0, wire_1.str)((0, wire_1.path)(meta, 'user', 'userName'))) !== null && _a !== void 0 ? _a : '',
|
|
435
|
+
winningBid: (_b = (0, wire_1.num)((0, wire_1.get)(meta, 'winningBid'))) !== null && _b !== void 0 ? _b : 0,
|
|
436
|
+
storeProductId: (0, wire_1.str)((0, wire_1.path)(wire, 'auctionedProduct', 'store_product_id')),
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
case 'START_POLL':
|
|
442
|
+
this.emitPollStarted((0, wire_1.path)(payload, 'data', 'poll'));
|
|
443
|
+
return;
|
|
444
|
+
case 'BROADCAST_POLL_RESULTS': {
|
|
445
|
+
const results = (0, polls_1.toLivePollResults)((0, wire_1.path)(payload, 'data', 'pollResults'));
|
|
446
|
+
if (results)
|
|
447
|
+
this.emit({ type: 'pollResults', results });
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
case 'REACTION_ANNOUCEMENT':
|
|
451
|
+
this.emit({
|
|
452
|
+
type: 'reaction',
|
|
453
|
+
reactionUrl: (_d = (_c = (0, wire_1.str)((0, wire_1.path)(payload, 'data', 'reactionUrl'))) !== null && _c !== void 0 ? _c : (0, wire_1.str)(payload.reactionUrl)) !== null && _d !== void 0 ? _d : '',
|
|
454
|
+
userName: (_f = (_e = (0, wire_1.str)((0, wire_1.path)(payload, 'data', 'userName'))) !== null && _e !== void 0 ? _e : (0, wire_1.str)(payload.userName)) !== null && _f !== void 0 ? _f : 'Anonymous',
|
|
455
|
+
});
|
|
456
|
+
return;
|
|
457
|
+
case 'END_POLL':
|
|
458
|
+
this.emit({ type: 'pollEnded' });
|
|
459
|
+
return;
|
|
460
|
+
case 'MUTE_USER':
|
|
461
|
+
this.mutedDeviceIds = this.mutedIdsFrom((0, wire_1.path)(payload, 'data', 'mutedUsers'));
|
|
462
|
+
this.emit({ type: 'mutedUsers', deviceIds: this.mutedDeviceIds });
|
|
463
|
+
return;
|
|
464
|
+
case 'STREAM_ENDED':
|
|
465
|
+
this.emit({ type: 'streamEnded' });
|
|
466
|
+
return;
|
|
467
|
+
case 'MIXER_STATE':
|
|
468
|
+
void this.applyMixerState(!!payload.active);
|
|
469
|
+
return;
|
|
470
|
+
case 'COHOST_ADMITTED':
|
|
471
|
+
if (!this.isOurSlot(payload.slot))
|
|
472
|
+
return;
|
|
473
|
+
this.emit({
|
|
474
|
+
type: 'guestAdmitted',
|
|
475
|
+
slot: Number(payload.slot),
|
|
476
|
+
mixerLayout: (0, guest_1.toMixerLayout)(payload.mixerLayout),
|
|
477
|
+
});
|
|
478
|
+
return;
|
|
479
|
+
case 'COHOST_REMOVED':
|
|
480
|
+
if (!this.isOurSlot(payload.slot))
|
|
481
|
+
return;
|
|
482
|
+
this.emit({ type: 'guestRemoved', slot: Number(payload.slot) });
|
|
483
|
+
return;
|
|
484
|
+
case 'COHOST_MUTE_AUDIO':
|
|
485
|
+
if (!this.isOurSlot(payload.slot))
|
|
486
|
+
return;
|
|
487
|
+
this.emit({ type: 'guestMutedByHost', slot: Number(payload.slot), muted: !!payload.muted });
|
|
488
|
+
return;
|
|
489
|
+
case 'COHOST_CAM_OFF':
|
|
490
|
+
if (!this.isOurSlot(payload.slot))
|
|
491
|
+
return;
|
|
492
|
+
this.emit({ type: 'guestCameraOffByHost', slot: Number(payload.slot), off: !!payload.off });
|
|
493
|
+
return;
|
|
494
|
+
case 'LAYOUT_CHANGED': {
|
|
495
|
+
const layout = (0, guest_1.toMixerLayout)(payload.mixerLayout);
|
|
496
|
+
if (layout)
|
|
497
|
+
this.emit({ type: 'mixerLayout', layout });
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
case 'GUESTS_CHANGED':
|
|
501
|
+
return;
|
|
502
|
+
default:
|
|
503
|
+
this.emit({ type: 'unknown', channel: 'broadcast', payload });
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
isOurSlot(slot) {
|
|
507
|
+
return this.guest != null && Number(slot) === this.guest.slot;
|
|
508
|
+
}
|
|
509
|
+
emitPollStarted(raw) {
|
|
510
|
+
const poll = (0, polls_1.toLivePoll)(raw);
|
|
511
|
+
if (poll)
|
|
512
|
+
this.emit({ type: 'pollStarted', poll, results: (0, polls_1.toEmbeddedResults)(raw) });
|
|
513
|
+
}
|
|
514
|
+
async applyMixerState(active) {
|
|
515
|
+
this.mixerActive = active;
|
|
516
|
+
this.emit({ type: 'mixer', active });
|
|
517
|
+
const target = this.targetStreamId();
|
|
518
|
+
if (!target || target === this.playingStreamId)
|
|
519
|
+
return;
|
|
520
|
+
await this.playStream(target);
|
|
521
|
+
}
|
|
522
|
+
targetStreamId() {
|
|
523
|
+
if (!this.joined)
|
|
524
|
+
return null;
|
|
525
|
+
return this.mixerActive && this.joined.mixedStreamId ? this.joined.mixedStreamId : this.joined.streamingId;
|
|
526
|
+
}
|
|
527
|
+
announceJoin() {
|
|
528
|
+
if (!this.joined)
|
|
529
|
+
return;
|
|
530
|
+
this.Engine.instance()
|
|
531
|
+
.sendCustomCommand(this.joined.roomId, JSON.stringify({ type: 'USER_JOINED', userName: this.joined.viewerName }), [])
|
|
532
|
+
.catch((error) => (0, client_1.getLogger)().error('[liveSelling] announceJoin', error));
|
|
533
|
+
}
|
|
534
|
+
enqueue(operation) {
|
|
535
|
+
const result = this.queue.then(operation, operation);
|
|
536
|
+
this.queue = result.catch(() => undefined);
|
|
537
|
+
return result;
|
|
538
|
+
}
|
|
539
|
+
join(params) {
|
|
540
|
+
return this.enqueue(() => this.joinNow(params));
|
|
541
|
+
}
|
|
542
|
+
leave() {
|
|
543
|
+
// A guest owns the room login while one is active; `leaveGuest` is the way out of guest mode.
|
|
544
|
+
if (this.guest)
|
|
545
|
+
return Promise.resolve();
|
|
546
|
+
return this.enqueue(() => this.leaveNow());
|
|
547
|
+
}
|
|
548
|
+
async joinNow(params) {
|
|
549
|
+
var _a;
|
|
550
|
+
await this.ensureEngine();
|
|
551
|
+
if (((_a = this.joined) === null || _a === void 0 ? void 0 : _a.streamingId) === params.streamingId)
|
|
552
|
+
return;
|
|
553
|
+
if (this.joined)
|
|
554
|
+
await this.leaveNow();
|
|
555
|
+
const { ZegoUser, ZegoRoomConfig } = this.Zego;
|
|
556
|
+
this.joined = params;
|
|
557
|
+
this.mixerActive = false;
|
|
558
|
+
// Before the room is entered, so the first comment after a cold rejoin is already checked.
|
|
559
|
+
this.mutedDeviceIds = params.mutedDeviceIds;
|
|
560
|
+
const result = await this.Engine.instance().loginRoom(params.roomId, new ZegoUser(params.viewerId, params.viewerName), new ZegoRoomConfig(0, true, params.token));
|
|
561
|
+
if (result === null || result === void 0 ? void 0 : result.errorCode)
|
|
562
|
+
throw new Error(`loginRoom failed with ${result.errorCode}`);
|
|
563
|
+
}
|
|
564
|
+
async bindView(reactTag, force = false) {
|
|
565
|
+
return this.enqueue(() => this.bindViewNow(reactTag, force));
|
|
566
|
+
}
|
|
567
|
+
async bindViewNow(reactTag, force = false) {
|
|
568
|
+
const target = this.targetStreamId();
|
|
569
|
+
if (!force &&
|
|
570
|
+
reactTag === this.boundTag &&
|
|
571
|
+
reactTag === this.playingTag &&
|
|
572
|
+
target &&
|
|
573
|
+
target === this.playingStreamId) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
this.boundTag = reactTag;
|
|
577
|
+
if (!target || reactTag == null)
|
|
578
|
+
return;
|
|
579
|
+
await this.playStream(target);
|
|
580
|
+
}
|
|
581
|
+
async refreshPlayback() {
|
|
582
|
+
return this.enqueue(() => this.refreshPlaybackNow());
|
|
583
|
+
}
|
|
584
|
+
async refreshPlaybackNow() {
|
|
585
|
+
const target = this.targetStreamId();
|
|
586
|
+
if (!target || this.boundTag == null)
|
|
587
|
+
return;
|
|
588
|
+
const { ZegoView, ZegoPlayerConfig } = this.Zego;
|
|
589
|
+
this.playingStreamId = target;
|
|
590
|
+
this.playingTag = this.boundTag;
|
|
591
|
+
void pip_1.livePip.setStream(target);
|
|
592
|
+
await this.Engine.instance().startPlayingStream(target, new ZegoView(this.boundTag, 1, 0), new ZegoPlayerConfig());
|
|
593
|
+
}
|
|
594
|
+
async stopPlayback() {
|
|
595
|
+
return this.enqueue(() => this.stopPlaybackNow());
|
|
596
|
+
}
|
|
597
|
+
async stopPlaybackNow() {
|
|
598
|
+
const playing = this.playingStreamId;
|
|
599
|
+
this.playingStreamId = null;
|
|
600
|
+
this.playingTag = null;
|
|
601
|
+
this.boundTag = null;
|
|
602
|
+
void pip_1.livePip.setStream(null);
|
|
603
|
+
if (!playing)
|
|
604
|
+
return;
|
|
605
|
+
await this.Engine.instance().stopPlayingStream(playing);
|
|
606
|
+
}
|
|
607
|
+
async playStream(streamId) {
|
|
608
|
+
if (this.boundTag == null)
|
|
609
|
+
return;
|
|
610
|
+
const { ZegoView, ZegoPlayerConfig } = this.Zego;
|
|
611
|
+
const previous = this.playingStreamId;
|
|
612
|
+
// Zego ignores a new canvas for a stream it is already playing, so moving the picture means
|
|
613
|
+
// stopping first.
|
|
614
|
+
const movingView = this.playingTag != null && this.playingTag !== this.boundTag;
|
|
615
|
+
if (previous && (previous !== streamId || movingView)) {
|
|
616
|
+
await this.Engine.instance().stopPlayingStream(previous);
|
|
617
|
+
}
|
|
618
|
+
this.playingStreamId = streamId;
|
|
619
|
+
this.playingTag = this.boundTag;
|
|
620
|
+
await this.Engine.instance().startPlayingStream(streamId, new ZegoView(this.boundTag, 1, 0), new ZegoPlayerConfig());
|
|
621
|
+
// Tracks the mixed id through a co-host swap, which is why it is set here rather than at join.
|
|
622
|
+
void pip_1.livePip.setStream(streamId);
|
|
623
|
+
this.emit({ type: 'videoBound', tag: this.playingTag });
|
|
624
|
+
}
|
|
625
|
+
// ─── Guest / co-host ──────────────────────────────────────────────────────
|
|
626
|
+
joinAsGuest(credentials, previewTag) {
|
|
627
|
+
return this.enqueue(() => this.joinAsGuestNow(credentials, previewTag));
|
|
628
|
+
}
|
|
629
|
+
async joinAsGuestNow(credentials, previewTag) {
|
|
630
|
+
await this.ensureEngine();
|
|
631
|
+
const engine = this.Engine.instance();
|
|
632
|
+
const { ZegoUser, ZegoRoomConfig, ZegoOrientation, ZegoPublishChannel } = this.Zego;
|
|
633
|
+
// The viewer login has to go first: one session per engine, and the publish privilege lives in
|
|
634
|
+
// the guest's token.
|
|
635
|
+
if (this.joined)
|
|
636
|
+
await this.leaveNow();
|
|
637
|
+
this.guest = credentials;
|
|
638
|
+
this.emit({ type: 'guestMode', active: true });
|
|
639
|
+
// Before publishing: without it the server-side MixStream output is rotated.
|
|
640
|
+
await engine.setAppOrientation(ZegoOrientation.PortraitUp, ZegoPublishChannel.Main);
|
|
641
|
+
await engine.useFrontCamera(true, ZegoPublishChannel.Main);
|
|
642
|
+
const result = await engine.loginRoom(credentials.roomId, new ZegoUser(credentials.userId, credentials.userName), new ZegoRoomConfig(0, true, credentials.token));
|
|
643
|
+
if (result === null || result === void 0 ? void 0 : result.errorCode) {
|
|
644
|
+
this.guest = null;
|
|
645
|
+
this.emit({ type: 'guestMode', active: false });
|
|
646
|
+
throw new Error(`guest loginRoom failed with ${result.errorCode}`);
|
|
647
|
+
}
|
|
648
|
+
if (previewTag != null)
|
|
649
|
+
await this.startPreviewNow(previewTag);
|
|
650
|
+
await engine.startPublishingStream(credentials.guestStreamId, ZegoPublishChannel.Main, {
|
|
651
|
+
roomID: credentials.roomId,
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
bindGuestPreview(reactTag) {
|
|
655
|
+
return this.enqueue(() => this.startPreviewNow(reactTag));
|
|
656
|
+
}
|
|
657
|
+
async startPreviewNow(reactTag) {
|
|
658
|
+
if (!this.guest || reactTag == null || reactTag === this.previewTag)
|
|
659
|
+
return;
|
|
660
|
+
const { ZegoView, ZegoPublishChannel } = this.Zego;
|
|
661
|
+
this.previewTag = reactTag;
|
|
662
|
+
await this.Engine.instance().startPreview(new ZegoView(reactTag, 1, 0), ZegoPublishChannel.Main);
|
|
663
|
+
}
|
|
664
|
+
bindGuestHostView(reactTag) {
|
|
665
|
+
return this.enqueue(async () => {
|
|
666
|
+
if (!this.guest || reactTag == null)
|
|
667
|
+
return;
|
|
668
|
+
const { ZegoView, ZegoPlayerConfig } = this.Zego;
|
|
669
|
+
// The host's raw stream, never `_mixed`: the mix contains this guest.
|
|
670
|
+
await this.Engine.instance().startPlayingStream(this.guest.streamingId, new ZegoView(reactTag, 1, 0), new ZegoPlayerConfig());
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
async setGuestMicMuted(muted) {
|
|
674
|
+
if (!this.guest)
|
|
675
|
+
return;
|
|
676
|
+
const engine = this.Engine.instance();
|
|
677
|
+
const { ZegoPublishChannel } = this.Zego;
|
|
678
|
+
await engine.muteMicrophone(muted);
|
|
679
|
+
await engine.mutePublishStreamAudio(muted, ZegoPublishChannel.Main);
|
|
680
|
+
}
|
|
681
|
+
async setGuestCameraOff(off) {
|
|
682
|
+
if (!this.guest)
|
|
683
|
+
return;
|
|
684
|
+
const engine = this.Engine.instance();
|
|
685
|
+
const { ZegoPublishChannel } = this.Zego;
|
|
686
|
+
await engine.enableCamera(!off, ZegoPublishChannel.Main);
|
|
687
|
+
await engine.mutePublishStreamVideo(off, ZegoPublishChannel.Main);
|
|
688
|
+
}
|
|
689
|
+
async flipGuestCamera(front) {
|
|
690
|
+
if (!this.guest)
|
|
691
|
+
return;
|
|
692
|
+
const { ZegoPublishChannel } = this.Zego;
|
|
693
|
+
await this.Engine.instance().useFrontCamera(front, ZegoPublishChannel.Main);
|
|
694
|
+
}
|
|
695
|
+
leaveGuest() {
|
|
696
|
+
return this.enqueue(() => this.leaveGuestNow());
|
|
697
|
+
}
|
|
698
|
+
async leaveGuestNow() {
|
|
699
|
+
const guest = this.guest;
|
|
700
|
+
if (!guest)
|
|
701
|
+
return;
|
|
702
|
+
const engine = this.Engine.instance();
|
|
703
|
+
const { ZegoPublishChannel } = this.Zego;
|
|
704
|
+
const logger = (0, client_1.getLogger)();
|
|
705
|
+
// Each guarded on its own: a failure part-way must not leave the room joined.
|
|
706
|
+
try {
|
|
707
|
+
await engine.stopPublishingStream(ZegoPublishChannel.Main);
|
|
708
|
+
}
|
|
709
|
+
catch (caught) {
|
|
710
|
+
logger.error('[liveSelling] stopPublishing', caught);
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
await engine.stopPreview(ZegoPublishChannel.Main);
|
|
714
|
+
}
|
|
715
|
+
catch (caught) {
|
|
716
|
+
logger.error('[liveSelling] stopPreview', caught);
|
|
717
|
+
}
|
|
718
|
+
try {
|
|
719
|
+
await engine.stopPlayingStream(guest.streamingId);
|
|
720
|
+
}
|
|
721
|
+
catch {
|
|
722
|
+
// Nothing was playing — the guest may never have seen the host.
|
|
723
|
+
}
|
|
724
|
+
try {
|
|
725
|
+
await engine.logoutRoom(guest.roomId);
|
|
726
|
+
}
|
|
727
|
+
catch (caught) {
|
|
728
|
+
logger.error('[liveSelling] guestLogout', caught);
|
|
729
|
+
}
|
|
730
|
+
this.guest = null;
|
|
731
|
+
this.previewTag = null;
|
|
732
|
+
this.emit({ type: 'guestMode', active: false });
|
|
733
|
+
}
|
|
734
|
+
setMutedDeviceIds(ids) {
|
|
735
|
+
const changed = ids.length !== this.mutedDeviceIds.length || ids.some((id, index) => id !== this.mutedDeviceIds[index]);
|
|
736
|
+
if (!changed)
|
|
737
|
+
return;
|
|
738
|
+
this.mutedDeviceIds = ids;
|
|
739
|
+
this.emit({ type: 'mutedUsers', deviceIds: ids });
|
|
740
|
+
}
|
|
741
|
+
setViewerName(name) {
|
|
742
|
+
this.viewerNameOverride = (name === null || name === void 0 ? void 0 : name.trim()) || null;
|
|
743
|
+
}
|
|
744
|
+
get publishedName() {
|
|
745
|
+
var _a, _b, _c;
|
|
746
|
+
return (_c = (_a = this.viewerNameOverride) !== null && _a !== void 0 ? _a : (_b = this.joined) === null || _b === void 0 ? void 0 : _b.viewerName) !== null && _c !== void 0 ? _c : 'Anonymous';
|
|
747
|
+
}
|
|
748
|
+
setMuted(muted) {
|
|
749
|
+
if (!this.engineReady)
|
|
750
|
+
return;
|
|
751
|
+
this.Engine.instance().muteSpeaker(muted);
|
|
752
|
+
}
|
|
753
|
+
async sendComment(text, deviceId) {
|
|
754
|
+
if (!this.joined || !text.trim())
|
|
755
|
+
return null;
|
|
756
|
+
const muted = this.mutedDeviceIds.includes(deviceId);
|
|
757
|
+
await this.Engine.instance().sendBarrageMessage(this.joined.roomId, JSON.stringify({ name: this.publishedName, comment: text, source: 'USER', deviceId, muted, isBanned: false }));
|
|
758
|
+
return this.makeComment(text, this.publishedName, 'USER', undefined, true);
|
|
759
|
+
}
|
|
760
|
+
async sendReaction(reactionUrl) {
|
|
761
|
+
if (!this.joined)
|
|
762
|
+
return;
|
|
763
|
+
const userName = this.publishedName;
|
|
764
|
+
// `sendCustomCommand` does not echo to the sender, so emit the local event here.
|
|
765
|
+
await this.Engine.instance().sendCustomCommand(this.joined.roomId, JSON.stringify({ type: 'REACTION_ANNOUCEMENT', reactionUrl, userName, roomId: this.joined.roomId }), []);
|
|
766
|
+
this.emit({ type: 'reaction', reactionUrl, userName });
|
|
767
|
+
}
|
|
768
|
+
async sendBid(params) {
|
|
769
|
+
var _a;
|
|
770
|
+
if (!this.joined || !params.moderatorId)
|
|
771
|
+
return;
|
|
772
|
+
const { ZegoUser } = this.Zego;
|
|
773
|
+
// Coerced at the crash boundary: a non-string recipient id is an uncatchable native crash on iOS.
|
|
774
|
+
const moderatorId = String(params.moderatorId);
|
|
775
|
+
await this.Engine.instance().sendCustomCommand(this.joined.roomId, JSON.stringify({
|
|
776
|
+
type: 'BID_PLACED',
|
|
777
|
+
data: {
|
|
778
|
+
bidAmount: params.bidAmount,
|
|
779
|
+
user: params.bidder,
|
|
780
|
+
timeStamp: params.placedAtMs,
|
|
781
|
+
userOptedVariantId: (_a = params.variantId) !== null && _a !== void 0 ? _a : '',
|
|
782
|
+
},
|
|
783
|
+
}), [new ZegoUser(moderatorId, moderatorId)]);
|
|
784
|
+
}
|
|
785
|
+
async sendCartAnnouncement(productTitle) {
|
|
786
|
+
if (!this.joined || !productTitle.trim())
|
|
787
|
+
return;
|
|
788
|
+
const userName = this.publishedName;
|
|
789
|
+
await this.Engine.instance().sendCustomCommand(this.joined.roomId, JSON.stringify({ type: 'CART_ANNOUCEMENT', productTitle, userName, roomId: this.joined.roomId }), []);
|
|
790
|
+
this.emit({ type: 'cartAnnouncement', productTitle, userName });
|
|
791
|
+
}
|
|
792
|
+
async leaveNow() {
|
|
793
|
+
if (!this.engineReady || !this.joined)
|
|
794
|
+
return;
|
|
795
|
+
const engine = this.Engine.instance();
|
|
796
|
+
if (this.playingStreamId)
|
|
797
|
+
await engine.stopPlayingStream(this.playingStreamId);
|
|
798
|
+
await engine.logoutRoom(this.joined.roomId);
|
|
799
|
+
this.playingStreamId = null;
|
|
800
|
+
this.playingTag = null;
|
|
801
|
+
this.boundTag = null;
|
|
802
|
+
this.joined = null;
|
|
803
|
+
this.emit({ type: 'videoBound', tag: null });
|
|
804
|
+
}
|
|
805
|
+
async destroy() {
|
|
806
|
+
if (!this.engineReady)
|
|
807
|
+
return;
|
|
808
|
+
await this.leave();
|
|
809
|
+
this.creating = null;
|
|
810
|
+
this.Engine.destroyEngine();
|
|
811
|
+
this.engineReady = false;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
exports.engine = new NativeLiveEngine();
|
|
815
|
+
//# sourceMappingURL=engine.native.js.map
|