agora-appbuilder-core 4.1.22-beta.2 → 4.1.22-beta.3
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/package.json +2 -2
- package/template/.eslintrc.js +20 -0
- package/template/.prettierrc.js +18 -0
- package/template/.watchmanconfig +1 -0
- package/template/agora-rn-uikit/src/Views/MaxVideoView.tsx +2 -0
- package/template/agora-rn-uikit/src/Views/MinVideoView.tsx +12 -2
- package/template/bridge/rtc/webNg/RtcEngine.ts +639 -251
- package/template/bridge/rtc/webNg/RtcSurfaceView.tsx +203 -16
- package/template/bridge/rtc/webNg/__tests__/screenshareLifecycle.test.ts +358 -0
- package/template/bridge/rtc/webNg/__tests__/screenshareMediaHealth.test.ts +49 -0
- package/template/bridge/rtc/webNg/screenshareMediaHealth.ts +49 -0
- package/template/bridge/rtm/web/index.ts +22 -31
- package/template/config.json +101 -0
- package/template/customization-api/atoms.ts +0 -2
- package/template/customization-api/customEvents.ts +1 -4
- package/template/customization-api/index.ts +0 -1
- package/template/customization-api/typeDefinition.ts +1 -6
- package/template/defaultConfig.js +2 -2
- package/template/src/components/Controls.tsx +12 -6
- package/template/src/components/CustomSidePanel.tsx +13 -13
- package/template/src/components/RTMConfigure.tsx +0 -14
- package/template/src/components/participants/UserActionMenuOptions.tsx +1 -28
- package/template/src/logger/transports/__tests__/agora-transport.test.ts +48 -0
- package/template/src/logger/transports/agora-transport.ts +18 -6
- package/template/src/pages/Create.tsx +19 -31
- package/template/src/pages/video-call/ActionSheet.native.tsx +0 -2
- package/template/src/pages/video-call/ActionSheet.tsx +0 -2
- package/template/src/pages/video-call/ActionSheetHandle.tsx +0 -1
- package/template/src/pages/video-call/SidePanelHeader.tsx +1 -3
- package/template/src/pages/video-call/VideoCallScreen.tsx +0 -3
- package/template/src/pages/video-call/VideoRenderer.tsx +0 -4
- package/template/src/rtm-events-api/Events.ts +3 -1
- package/template/src/rtm-events-api/__tests__/Events.test.ts +55 -0
- package/template/src/subComponents/SidePanelHeader.tsx +2 -16
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +38 -4
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +280 -34
- package/template/src/subComponents/screenshare/__tests__/screenshareJourney.test.ts +10 -0
- package/template/src/subComponents/screenshare/__tests__/screenshareOperation.test.ts +31 -0
- package/template/src/subComponents/screenshare/screenshareJourney.ts +6 -0
- package/template/src/subComponents/screenshare/screenshareOperation.ts +21 -0
- package/template/src/subComponents/screenshare/useScreenshare.tsx +8 -0
- package/template/theme.json +91 -0
- package/template/customization-api/ai-agent.ts +0 -4
|
@@ -45,7 +45,18 @@ import {
|
|
|
45
45
|
type ScreenEncoderConfigurationPreset,
|
|
46
46
|
type VideoEncoderConfiguration,
|
|
47
47
|
} from '../../../src/app-state/useVideoQuality';
|
|
48
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
getScreenshareReleaseOrigin,
|
|
50
|
+
getScreenshareSessionBoundaryMessage,
|
|
51
|
+
} from '../../../src/subComponents/screenshare/screenshareJourney';
|
|
52
|
+
|
|
53
|
+
export type ScreenshareMediaDiagnostics = {
|
|
54
|
+
role: 'sender' | 'viewer';
|
|
55
|
+
screenshareSessionId: string;
|
|
56
|
+
screenShareUid: UID;
|
|
57
|
+
stats: Record<string, unknown> | null;
|
|
58
|
+
mediaTrack: MediaStreamTrack | null;
|
|
59
|
+
};
|
|
49
60
|
|
|
50
61
|
interface MediaDeviceInfo {
|
|
51
62
|
readonly deviceId: string;
|
|
@@ -190,6 +201,14 @@ interface ScreenStream {
|
|
|
190
201
|
audio?: ILocalAudioTrack;
|
|
191
202
|
video?: ILocalVideoTrack;
|
|
192
203
|
}
|
|
204
|
+
interface ActiveScreenshareLifecycle {
|
|
205
|
+
audio?: ILocalAudioTrack;
|
|
206
|
+
video: ILocalVideoTrack;
|
|
207
|
+
joined: boolean;
|
|
208
|
+
cleaned: boolean;
|
|
209
|
+
cleanupPromise?: Promise<void>;
|
|
210
|
+
journeyData: Record<string, unknown>;
|
|
211
|
+
}
|
|
193
212
|
interface RemoteStream {
|
|
194
213
|
audio?: IRemoteAudioTrack;
|
|
195
214
|
video?: IRemoteVideoTrack;
|
|
@@ -253,13 +272,122 @@ export default class RtcEngine {
|
|
|
253
272
|
public screenStream: ScreenStream = {};
|
|
254
273
|
public remoteStreams = new Map<UID, RemoteStream>();
|
|
255
274
|
private inScreenshare: Boolean = false;
|
|
256
|
-
private
|
|
275
|
+
private screenshareOperationState:
|
|
276
|
+
| 'inactive'
|
|
277
|
+
| 'starting'
|
|
278
|
+
| 'active'
|
|
279
|
+
| 'stopping' = 'inactive';
|
|
280
|
+
private screenshareOperationGeneration = 0;
|
|
281
|
+
private activeScreenshareLifecycle: ActiveScreenshareLifecycle | null = null;
|
|
257
282
|
private activeScreenshareJourneyContext: {
|
|
258
283
|
screenshareSessionId?: string;
|
|
259
284
|
recordingActive?: boolean;
|
|
260
285
|
screenShareUid?: UID;
|
|
261
286
|
stopActorUid?: UID;
|
|
262
287
|
} | null = null;
|
|
288
|
+
private remoteScreenshareUids = new Set<UID>();
|
|
289
|
+
|
|
290
|
+
registerRemoteScreenshareUid(uid: UID) {
|
|
291
|
+
if (uid === undefined || uid === null) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
this.remoteScreenshareUids.add(uid);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private logRemoteScreenshareTermination(
|
|
298
|
+
uid: UID,
|
|
299
|
+
sdkEvent: 'user-unpublished' | 'user-left',
|
|
300
|
+
mediaType?: 'audio' | 'video',
|
|
301
|
+
) {
|
|
302
|
+
if (!this.remoteScreenshareUids.has(uid)) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const videoTrack = this.remoteStreams?.get?.(uid)?.video;
|
|
306
|
+
let mediaTrack: MediaStreamTrack | null = null;
|
|
307
|
+
try {
|
|
308
|
+
mediaTrack = videoTrack?.getMediaStreamTrack?.() || null;
|
|
309
|
+
} catch (_) {}
|
|
310
|
+
logger.log(
|
|
311
|
+
LogSource.AgoraSDK,
|
|
312
|
+
'Event',
|
|
313
|
+
`[SCREENSHARE_JOURNEY] receiver detected screen share stopped through RTC ${sdkEvent}`,
|
|
314
|
+
{
|
|
315
|
+
action: 'stop',
|
|
316
|
+
stage: 'receiver_rtc_termination',
|
|
317
|
+
outcome: 'detected',
|
|
318
|
+
role: 'viewer',
|
|
319
|
+
screenshareSessionId: 'remote-session-by-screen-uid',
|
|
320
|
+
screenShareUid: uid,
|
|
321
|
+
stopOrigin: 'remote_sender_or_connection',
|
|
322
|
+
sdkEvent,
|
|
323
|
+
mediaType,
|
|
324
|
+
mediaTrack: mediaTrack
|
|
325
|
+
? {
|
|
326
|
+
readyState: mediaTrack.readyState,
|
|
327
|
+
enabled: mediaTrack.enabled,
|
|
328
|
+
muted: mediaTrack.muted,
|
|
329
|
+
}
|
|
330
|
+
: null,
|
|
331
|
+
},
|
|
332
|
+
);
|
|
333
|
+
this.remoteScreenshareUids.delete(uid);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
getScreenshareMediaDiagnostics(uid: UID): ScreenshareMediaDiagnostics {
|
|
337
|
+
const isSender = uid === 1;
|
|
338
|
+
if (!isSender) {
|
|
339
|
+
this.registerRemoteScreenshareUid(uid);
|
|
340
|
+
}
|
|
341
|
+
const videoTrack = isSender
|
|
342
|
+
? this.screenStream?.video
|
|
343
|
+
: this.remoteStreams?.get?.(uid)?.video;
|
|
344
|
+
let stats: Record<string, unknown> | null = null;
|
|
345
|
+
try {
|
|
346
|
+
stats = isSender
|
|
347
|
+
? this.screenClient?.getLocalVideoStats?.() || null
|
|
348
|
+
: this.client?.getRemoteVideoStats?.()?.[uid] || null;
|
|
349
|
+
} catch (error) {
|
|
350
|
+
logger.error(
|
|
351
|
+
LogSource.AgoraSDK,
|
|
352
|
+
'API',
|
|
353
|
+
'[SCREENSHARE_JOURNEY] screen share media health stats collection failed',
|
|
354
|
+
{
|
|
355
|
+
action: 'monitor',
|
|
356
|
+
stage: 'media_health',
|
|
357
|
+
outcome: 'stats_unavailable',
|
|
358
|
+
role: isSender ? 'sender' : 'viewer',
|
|
359
|
+
screenshareSessionId: isSender
|
|
360
|
+
? this.activeScreenshareJourneyContext?.screenshareSessionId ||
|
|
361
|
+
'unknown-session'
|
|
362
|
+
: 'remote-session-by-screen-uid',
|
|
363
|
+
screenShareUid: isSender
|
|
364
|
+
? this.activeScreenshareJourneyContext?.screenShareUid ||
|
|
365
|
+
this.screenClient?.uid
|
|
366
|
+
: uid,
|
|
367
|
+
...getScreenshareErrorDetails(error),
|
|
368
|
+
},
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
role: isSender ? 'sender' : 'viewer',
|
|
373
|
+
screenshareSessionId: isSender
|
|
374
|
+
? this.activeScreenshareJourneyContext?.screenshareSessionId ||
|
|
375
|
+
'unknown-session'
|
|
376
|
+
: 'remote-session-by-screen-uid',
|
|
377
|
+
screenShareUid: isSender
|
|
378
|
+
? this.activeScreenshareJourneyContext?.screenShareUid ||
|
|
379
|
+
this.screenClient?.uid
|
|
380
|
+
: uid,
|
|
381
|
+
stats,
|
|
382
|
+
mediaTrack: (() => {
|
|
383
|
+
try {
|
|
384
|
+
return videoTrack?.getMediaStreamTrack?.() || null;
|
|
385
|
+
} catch (_) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
})(),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
263
391
|
private videoProfile:
|
|
264
392
|
| VideoEncoderConfigurationPreset
|
|
265
393
|
| VideoEncoderConfiguration;
|
|
@@ -739,6 +867,7 @@ export default class RtcEngine {
|
|
|
739
867
|
this.client.on('user-left', user => {
|
|
740
868
|
logger.log(LogSource.AgoraSDK, 'Event', 'RTC [user-left]', user);
|
|
741
869
|
const uid = user.uid;
|
|
870
|
+
this.logRemoteScreenshareTermination(uid, 'user-left');
|
|
742
871
|
if (this.remoteStreams.has(uid)) {
|
|
743
872
|
this.remoteStreams.delete(uid);
|
|
744
873
|
}
|
|
@@ -819,6 +948,13 @@ export default class RtcEngine {
|
|
|
819
948
|
user,
|
|
820
949
|
mediaType,
|
|
821
950
|
);
|
|
951
|
+
if (mediaType === 'video') {
|
|
952
|
+
this.logRemoteScreenshareTermination(
|
|
953
|
+
user.uid,
|
|
954
|
+
'user-unpublished',
|
|
955
|
+
mediaType,
|
|
956
|
+
);
|
|
957
|
+
}
|
|
822
958
|
if (mediaType === 'audio') {
|
|
823
959
|
const data = this.remoteStreams.get(user.uid);
|
|
824
960
|
try {
|
|
@@ -1537,6 +1673,167 @@ export default class RtcEngine {
|
|
|
1537
1673
|
console.error('Please use enableEncryption instead');
|
|
1538
1674
|
}
|
|
1539
1675
|
|
|
1676
|
+
private async cleanupActiveScreenshare(
|
|
1677
|
+
stopOrigin: string,
|
|
1678
|
+
notifyScreenshareStopped: boolean,
|
|
1679
|
+
screenshareAttemptId: string,
|
|
1680
|
+
expectedLifecycle?: ActiveScreenshareLifecycle,
|
|
1681
|
+
): Promise<void> {
|
|
1682
|
+
const lifecycle = expectedLifecycle || this.activeScreenshareLifecycle;
|
|
1683
|
+
const journeyData = {
|
|
1684
|
+
...(lifecycle?.journeyData || this.activeScreenshareJourneyContext || {}),
|
|
1685
|
+
action: 'stop',
|
|
1686
|
+
screenshareAttemptId,
|
|
1687
|
+
stopOrigin,
|
|
1688
|
+
};
|
|
1689
|
+
|
|
1690
|
+
if (!lifecycle) {
|
|
1691
|
+
logger.log(
|
|
1692
|
+
LogSource.AgoraSDK,
|
|
1693
|
+
'API',
|
|
1694
|
+
`[SCREENSHARE_JOURNEY] screen share stop cleanup skipped because there is no active RTC lifecycle`,
|
|
1695
|
+
{
|
|
1696
|
+
...journeyData,
|
|
1697
|
+
stage: 'cleanup',
|
|
1698
|
+
outcome: 'skipped',
|
|
1699
|
+
operationState: this.screenshareOperationState,
|
|
1700
|
+
duplicateReason: 'no_active_rtc_lifecycle',
|
|
1701
|
+
},
|
|
1702
|
+
);
|
|
1703
|
+
if (notifyScreenshareStopped) {
|
|
1704
|
+
await (this.eventsMap.get('onScreenshareStopped') as callbackType)(
|
|
1705
|
+
stopOrigin,
|
|
1706
|
+
screenshareAttemptId,
|
|
1707
|
+
journeyData.screenshareSessionId || 'unknown-session',
|
|
1708
|
+
journeyData.stopActorUid,
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1711
|
+
this.inScreenshare = false;
|
|
1712
|
+
this.screenshareOperationState = 'inactive';
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
if (
|
|
1717
|
+
expectedLifecycle &&
|
|
1718
|
+
this.activeScreenshareLifecycle !== expectedLifecycle
|
|
1719
|
+
) {
|
|
1720
|
+
logger.log(
|
|
1721
|
+
LogSource.AgoraSDK,
|
|
1722
|
+
'API',
|
|
1723
|
+
`[SCREENSHARE_JOURNEY] screen share stop ignored stale track-ended callback`,
|
|
1724
|
+
{
|
|
1725
|
+
...journeyData,
|
|
1726
|
+
stage: 'track_ended',
|
|
1727
|
+
outcome: 'skipped',
|
|
1728
|
+
operationState: this.screenshareOperationState,
|
|
1729
|
+
duplicateReason: 'stale_screenshare_lifecycle',
|
|
1730
|
+
},
|
|
1731
|
+
);
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
if (lifecycle.cleanupPromise) {
|
|
1736
|
+
logger.log(
|
|
1737
|
+
LogSource.AgoraSDK,
|
|
1738
|
+
'API',
|
|
1739
|
+
`[SCREENSHARE_JOURNEY] screen share stop joined cleanup already in progress`,
|
|
1740
|
+
{
|
|
1741
|
+
...journeyData,
|
|
1742
|
+
stage: 'cleanup',
|
|
1743
|
+
outcome: 'skipped',
|
|
1744
|
+
operationState: this.screenshareOperationState,
|
|
1745
|
+
duplicateReason: 'cleanup_already_in_progress',
|
|
1746
|
+
},
|
|
1747
|
+
);
|
|
1748
|
+
return lifecycle.cleanupPromise;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
this.screenshareOperationState = 'stopping';
|
|
1752
|
+
lifecycle.cleanupPromise = Promise.resolve().then(async () => {
|
|
1753
|
+
let cleanupError: unknown;
|
|
1754
|
+
const attemptCleanup = async (operation: () => unknown) => {
|
|
1755
|
+
try {
|
|
1756
|
+
await operation();
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
cleanupError = cleanupError || error;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
try {
|
|
1762
|
+
await attemptCleanup(() =>
|
|
1763
|
+
(this.eventsMap.get('onUserOffline') as callbackType)(
|
|
1764
|
+
{},
|
|
1765
|
+
this.screenClient.uid,
|
|
1766
|
+
),
|
|
1767
|
+
);
|
|
1768
|
+
await attemptCleanup(() => lifecycle.audio?.stop());
|
|
1769
|
+
await attemptCleanup(() => lifecycle.video?.stop());
|
|
1770
|
+
await attemptCleanup(() => lifecycle.audio?.close());
|
|
1771
|
+
await attemptCleanup(() => lifecycle.video?.close());
|
|
1772
|
+
if (lifecycle.joined) {
|
|
1773
|
+
await attemptCleanup(() => this.screenClient.leave());
|
|
1774
|
+
}
|
|
1775
|
+
if (cleanupError) {
|
|
1776
|
+
logger.error(
|
|
1777
|
+
LogSource.AgoraSDK,
|
|
1778
|
+
'API',
|
|
1779
|
+
`[SCREENSHARE_JOURNEY] screen share stop RTC cleanup completed with errors`,
|
|
1780
|
+
{
|
|
1781
|
+
...journeyData,
|
|
1782
|
+
stage: 'cleanup',
|
|
1783
|
+
outcome: 'partial_failure',
|
|
1784
|
+
operationState: 'inactive',
|
|
1785
|
+
...getScreenshareErrorDetails(cleanupError),
|
|
1786
|
+
},
|
|
1787
|
+
);
|
|
1788
|
+
} else {
|
|
1789
|
+
logger.log(
|
|
1790
|
+
LogSource.AgoraSDK,
|
|
1791
|
+
'API',
|
|
1792
|
+
`[SCREENSHARE_JOURNEY] screen share stop RTC cleanup completed`,
|
|
1793
|
+
{
|
|
1794
|
+
...journeyData,
|
|
1795
|
+
stage: 'cleanup',
|
|
1796
|
+
outcome: 'success',
|
|
1797
|
+
operationState: 'inactive',
|
|
1798
|
+
},
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
} catch (error) {
|
|
1802
|
+
logger.error(
|
|
1803
|
+
LogSource.AgoraSDK,
|
|
1804
|
+
'API',
|
|
1805
|
+
`[SCREENSHARE_JOURNEY] screen share stop RTC cleanup failed`,
|
|
1806
|
+
{
|
|
1807
|
+
...journeyData,
|
|
1808
|
+
stage: 'cleanup',
|
|
1809
|
+
outcome: 'failure',
|
|
1810
|
+
operationState: this.screenshareOperationState,
|
|
1811
|
+
...getScreenshareErrorDetails(error),
|
|
1812
|
+
},
|
|
1813
|
+
);
|
|
1814
|
+
throw error;
|
|
1815
|
+
} finally {
|
|
1816
|
+
lifecycle.cleaned = true;
|
|
1817
|
+
if (this.activeScreenshareLifecycle === lifecycle) {
|
|
1818
|
+
this.activeScreenshareLifecycle = null;
|
|
1819
|
+
this.screenStream = {};
|
|
1820
|
+
this.inScreenshare = false;
|
|
1821
|
+
this.screenshareOperationState = 'inactive';
|
|
1822
|
+
this.activeScreenshareJourneyContext = null;
|
|
1823
|
+
if (notifyScreenshareStopped) {
|
|
1824
|
+
await (this.eventsMap.get('onScreenshareStopped') as callbackType)(
|
|
1825
|
+
stopOrigin,
|
|
1826
|
+
screenshareAttemptId,
|
|
1827
|
+
journeyData.screenshareSessionId || 'unknown-session',
|
|
1828
|
+
journeyData.stopActorUid,
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
});
|
|
1834
|
+
return await lifecycle.cleanupPromise;
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1540
1837
|
// async removeAllListeners<EventType extends keyof RtcEngineEvents>(event: EventType) {
|
|
1541
1838
|
// this.client.removeAllListeners(eventName);
|
|
1542
1839
|
// }
|
|
@@ -1548,7 +1845,23 @@ export default class RtcEngine {
|
|
|
1548
1845
|
requestedStopOrigin,
|
|
1549
1846
|
typeof document !== 'undefined' ? document.visibilityState : undefined,
|
|
1550
1847
|
);
|
|
1551
|
-
if (this.
|
|
1848
|
+
if (this.screenshareOperationState === 'starting') {
|
|
1849
|
+
this.screenshareOperationGeneration += 1;
|
|
1850
|
+
this.screenshareOperationState = 'inactive';
|
|
1851
|
+
logger.log(
|
|
1852
|
+
LogSource.AgoraSDK,
|
|
1853
|
+
'API',
|
|
1854
|
+
`[SCREENSHARE_JOURNEY] screen share start cancelled by RTC release from ${stopOrigin}`,
|
|
1855
|
+
{
|
|
1856
|
+
action: 'start',
|
|
1857
|
+
stage: 'release',
|
|
1858
|
+
outcome: 'cancelled',
|
|
1859
|
+
stopOrigin,
|
|
1860
|
+
operationState: 'inactive',
|
|
1861
|
+
},
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
if (this.activeScreenshareLifecycle || this.inScreenshare) {
|
|
1552
1865
|
const screenshareAttemptId = `release-${Date.now()}`;
|
|
1553
1866
|
const journeyData = {
|
|
1554
1867
|
action: 'stop',
|
|
@@ -1574,21 +1887,10 @@ export default class RtcEngine {
|
|
|
1574
1887
|
journeyData,
|
|
1575
1888
|
);
|
|
1576
1889
|
try {
|
|
1577
|
-
|
|
1578
|
-
{},
|
|
1579
|
-
this.screenClient.uid,
|
|
1580
|
-
);
|
|
1581
|
-
this.screenStream.audio?.stop();
|
|
1582
|
-
this.screenStream.video?.stop();
|
|
1583
|
-
this.screenStream.audio?.close();
|
|
1584
|
-
this.screenStream.video?.close();
|
|
1585
|
-
await this.screenClient.leave();
|
|
1586
|
-
this.inScreenshare = false;
|
|
1587
|
-
(this.eventsMap.get('onScreenshareStopped') as callbackType)(
|
|
1890
|
+
await this.cleanupActiveScreenshare(
|
|
1588
1891
|
stopOrigin,
|
|
1892
|
+
true,
|
|
1589
1893
|
screenshareAttemptId,
|
|
1590
|
-
journeyData.screenshareSessionId,
|
|
1591
|
-
journeyData.stopActorUid,
|
|
1592
1894
|
);
|
|
1593
1895
|
logger.log(
|
|
1594
1896
|
LogSource.AgoraSDK,
|
|
@@ -1608,6 +1910,19 @@ export default class RtcEngine {
|
|
|
1608
1910
|
},
|
|
1609
1911
|
);
|
|
1610
1912
|
} finally {
|
|
1913
|
+
logger.log(
|
|
1914
|
+
LogSource.AgoraSDK,
|
|
1915
|
+
'API',
|
|
1916
|
+
getScreenshareSessionBoundaryMessage(
|
|
1917
|
+
'end',
|
|
1918
|
+
journeyData.screenshareSessionId,
|
|
1919
|
+
),
|
|
1920
|
+
{
|
|
1921
|
+
...journeyData,
|
|
1922
|
+
stage: 'session_boundary',
|
|
1923
|
+
outcome: 'ended',
|
|
1924
|
+
},
|
|
1925
|
+
);
|
|
1611
1926
|
this.activeScreenshareJourneyContext = null;
|
|
1612
1927
|
}
|
|
1613
1928
|
}
|
|
@@ -1696,280 +2011,353 @@ export default class RtcEngine {
|
|
|
1696
2011
|
...screenShareConfig,
|
|
1697
2012
|
encoderConfig: this.screenShareProfile,
|
|
1698
2013
|
};
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
}
|
|
2014
|
+
if (journeyData.action === 'stop') {
|
|
2015
|
+
logger.log(
|
|
2016
|
+
LogSource.AgoraSDK,
|
|
2017
|
+
'API',
|
|
2018
|
+
`[SCREENSHARE_JOURNEY] screen share stop entered RTC engine from ${journeyData.stopOrigin}`,
|
|
2019
|
+
{
|
|
2020
|
+
...journeyData,
|
|
2021
|
+
stage: 'rtc_stop',
|
|
2022
|
+
outcome: 'started',
|
|
2023
|
+
requestedAction: 'stop',
|
|
2024
|
+
executedAction: 'stop',
|
|
2025
|
+
operationState: this.screenshareOperationState,
|
|
2026
|
+
},
|
|
2027
|
+
);
|
|
2028
|
+
await this.cleanupActiveScreenshare(
|
|
2029
|
+
journeyData.stopOrigin,
|
|
2030
|
+
true,
|
|
2031
|
+
journeyData.screenshareAttemptId,
|
|
2032
|
+
);
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
if (this.screenshareOperationState !== 'inactive' || this.inScreenshare) {
|
|
2037
|
+
const duplicateStartError = Object.assign(
|
|
2038
|
+
new Error(
|
|
2039
|
+
`Screen share start rejected while RTC state is ${this.screenshareOperationState}`,
|
|
2040
|
+
),
|
|
2041
|
+
{code: 'SCREENSHARE_OPERATION_IN_PROGRESS'},
|
|
2042
|
+
);
|
|
2043
|
+
logger.log(
|
|
2044
|
+
LogSource.AgoraSDK,
|
|
2045
|
+
'API',
|
|
2046
|
+
`[SCREENSHARE_JOURNEY] screen share start rejected because RTC screen share is ${this.screenshareOperationState}`,
|
|
2047
|
+
{
|
|
2048
|
+
...journeyData,
|
|
2049
|
+
stage: 'precondition',
|
|
2050
|
+
outcome: 'skipped',
|
|
2051
|
+
requestedAction: 'start',
|
|
2052
|
+
executedAction: 'none',
|
|
2053
|
+
operationState: this.screenshareOperationState,
|
|
2054
|
+
duplicateReason: `start_requested_while_${this.screenshareOperationState}`,
|
|
2055
|
+
},
|
|
2056
|
+
);
|
|
2057
|
+
throw duplicateStartError;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
this.screenshareOperationState = 'starting';
|
|
2061
|
+
const operationGeneration = ++this.screenshareOperationGeneration;
|
|
2062
|
+
const ensureStartIsCurrent = () => {
|
|
2063
|
+
if (operationGeneration !== this.screenshareOperationGeneration) {
|
|
2064
|
+
throw Object.assign(
|
|
2065
|
+
new Error('Screen share start was cancelled by cleanup'),
|
|
2066
|
+
{code: 'SCREENSHARE_START_CANCELLED'},
|
|
1725
2067
|
);
|
|
1726
|
-
return;
|
|
1727
2068
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2069
|
+
};
|
|
2070
|
+
let stage = 'encryption';
|
|
2071
|
+
let joined = false;
|
|
2072
|
+
let localVideoTrack: ILocalVideoTrack | undefined;
|
|
2073
|
+
let localAudioTrack: ILocalAudioTrack | undefined;
|
|
2074
|
+
try {
|
|
2075
|
+
logger.debug(
|
|
2076
|
+
LogSource.AgoraSDK,
|
|
2077
|
+
'Log',
|
|
2078
|
+
'[SCREENSHARE_JOURNEY] screen share start entered RTC engine',
|
|
2079
|
+
{
|
|
2080
|
+
...journeyData,
|
|
2081
|
+
stage: 'rtc_start',
|
|
2082
|
+
outcome: 'started',
|
|
2083
|
+
requestedAction: 'start',
|
|
2084
|
+
executedAction: 'start',
|
|
2085
|
+
operationState: this.screenshareOperationState,
|
|
2086
|
+
},
|
|
2087
|
+
);
|
|
2088
|
+
if (encryption && encryption.screenKey && encryption.mode) {
|
|
2089
|
+
let mode: EncryptionMode;
|
|
2090
|
+
mode = this.getEncryptionMode(true, encryption?.mode);
|
|
2091
|
+
try {
|
|
2092
|
+
/**
|
|
2093
|
+
* Since version 4.7.0, if client leaves a call
|
|
2094
|
+
* and joins again the encryption needs to be
|
|
2095
|
+
* set again
|
|
2096
|
+
*/
|
|
2097
|
+
logger.log(
|
|
2098
|
+
LogSource.AgoraSDK,
|
|
2099
|
+
'Log',
|
|
2100
|
+
'[SCREENSHARE_JOURNEY] screen share start configuring RTC screen-client encryption',
|
|
2101
|
+
{...journeyData, stage, outcome: 'started'},
|
|
1734
2102
|
);
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
if (joined || this.inScreenshare) {
|
|
1741
|
-
await this.screenClient.leave();
|
|
1742
|
-
}
|
|
1743
|
-
this.screenStream = {};
|
|
1744
|
-
this.inScreenshare = false;
|
|
1745
|
-
this.activeScreenshareJourneyContext = null;
|
|
1746
|
-
if (notifyScreenshareStopped) {
|
|
1747
|
-
(this.eventsMap.get('onScreenshareStopped') as callbackType)(
|
|
1748
|
-
stopOrigin,
|
|
1749
|
-
screenshareAttemptId,
|
|
1750
|
-
cleanupJourneyData.screenshareSessionId,
|
|
1751
|
-
cleanupJourneyData.stopActorUid,
|
|
2103
|
+
await this.screenClient.setEncryptionConfig(
|
|
2104
|
+
mode,
|
|
2105
|
+
encryption.screenKey,
|
|
2106
|
+
encryption.salt,
|
|
2107
|
+
true, // encryptDataStream
|
|
1752
2108
|
);
|
|
2109
|
+
ensureStartIsCurrent();
|
|
2110
|
+
logger.log(
|
|
2111
|
+
LogSource.AgoraSDK,
|
|
2112
|
+
'Log',
|
|
2113
|
+
'[SCREENSHARE_JOURNEY] screen share start RTC screen-client encryption configured successfully',
|
|
2114
|
+
{...journeyData, stage, outcome: 'success'},
|
|
2115
|
+
);
|
|
2116
|
+
} catch (e) {
|
|
2117
|
+
logger.error(
|
|
2118
|
+
LogSource.AgoraSDK,
|
|
2119
|
+
'Log',
|
|
2120
|
+
'[SCREENSHARE_JOURNEY] screen share start RTC screen-client encryption configuration failed',
|
|
2121
|
+
{
|
|
2122
|
+
...journeyData,
|
|
2123
|
+
stage,
|
|
2124
|
+
outcome: 'failure',
|
|
2125
|
+
...getScreenshareErrorDetails(e),
|
|
2126
|
+
},
|
|
2127
|
+
);
|
|
2128
|
+
throw e;
|
|
1753
2129
|
}
|
|
2130
|
+
} else {
|
|
1754
2131
|
logger.log(
|
|
1755
|
-
LogSource.AgoraSDK,
|
|
1756
|
-
'API',
|
|
1757
|
-
`[SCREENSHARE_JOURNEY] screen share ${cleanupJourneyData.action} RTC cleanup completed`,
|
|
1758
|
-
{
|
|
1759
|
-
...cleanupJourneyData,
|
|
1760
|
-
stage: 'cleanup',
|
|
1761
|
-
outcome: 'success',
|
|
1762
|
-
stopOrigin,
|
|
1763
|
-
},
|
|
1764
|
-
);
|
|
1765
|
-
cleanupCompleted = true;
|
|
1766
|
-
} finally {
|
|
1767
|
-
this.isScreenshareCleanupInProgress = false;
|
|
1768
|
-
}
|
|
1769
|
-
};
|
|
1770
|
-
if (!this.inScreenshare) {
|
|
1771
|
-
let stage = 'encryption';
|
|
1772
|
-
try {
|
|
1773
|
-
logger.debug(
|
|
1774
2132
|
LogSource.AgoraSDK,
|
|
1775
2133
|
'Log',
|
|
1776
|
-
'[SCREENSHARE_JOURNEY] screen share start
|
|
1777
|
-
{...journeyData, stage
|
|
2134
|
+
'[SCREENSHARE_JOURNEY] screen share start RTC screen-client encryption skipped because encryption is not configured',
|
|
2135
|
+
{...journeyData, stage, outcome: 'skipped'},
|
|
1778
2136
|
);
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
stage = 'create_screen_video_track';
|
|
2140
|
+
logger.log(
|
|
2141
|
+
LogSource.AgoraSDK,
|
|
2142
|
+
'API',
|
|
2143
|
+
'[SCREENSHARE_JOURNEY] screen share start calling AgoraRTC.createScreenVideoTrack',
|
|
2144
|
+
{
|
|
2145
|
+
...journeyData,
|
|
2146
|
+
stage,
|
|
2147
|
+
outcome: 'started',
|
|
2148
|
+
config,
|
|
2149
|
+
},
|
|
2150
|
+
);
|
|
2151
|
+
const screenTracks = await AgoraRTC.createScreenVideoTrack(config, audio);
|
|
2152
|
+
const isSingleScreenTrack = this.isSingleTrack(screenTracks);
|
|
2153
|
+
localVideoTrack = isSingleScreenTrack ? screenTracks : screenTracks[0];
|
|
2154
|
+
localAudioTrack = isSingleScreenTrack ? undefined : screenTracks[1];
|
|
2155
|
+
ensureStartIsCurrent();
|
|
2156
|
+
logger.log(
|
|
2157
|
+
LogSource.AgoraSDK,
|
|
2158
|
+
'API',
|
|
2159
|
+
'[SCREENSHARE_JOURNEY] screen share start AgoraRTC.createScreenVideoTrack completed successfully',
|
|
2160
|
+
{
|
|
2161
|
+
...journeyData,
|
|
2162
|
+
stage,
|
|
2163
|
+
outcome: 'success',
|
|
2164
|
+
hasVideoTrack: Boolean(
|
|
2165
|
+
isSingleScreenTrack ? screenTracks : screenTracks[0],
|
|
2166
|
+
),
|
|
2167
|
+
hasAudioTrack: Boolean(isSingleScreenTrack ? false : screenTracks[1]),
|
|
2168
|
+
},
|
|
2169
|
+
);
|
|
2170
|
+
stage = 'rtc_join';
|
|
2171
|
+
logger.log(
|
|
2172
|
+
LogSource.AgoraSDK,
|
|
2173
|
+
'API',
|
|
2174
|
+
'[SCREENSHARE_JOURNEY] screen share start calling screenClient.join',
|
|
2175
|
+
{...journeyData, stage, outcome: 'started', channelName, optionalUid},
|
|
2176
|
+
);
|
|
2177
|
+
await this.screenClient.join(
|
|
2178
|
+
this.appId,
|
|
2179
|
+
channelName,
|
|
2180
|
+
token || null,
|
|
2181
|
+
optionalUid || null,
|
|
2182
|
+
);
|
|
2183
|
+
joined = true;
|
|
2184
|
+
ensureStartIsCurrent();
|
|
2185
|
+
logger.log(
|
|
2186
|
+
LogSource.AgoraSDK,
|
|
2187
|
+
'API',
|
|
2188
|
+
'[SCREENSHARE_JOURNEY] screen share start screenClient.join completed successfully',
|
|
2189
|
+
{...journeyData, stage, outcome: 'success'},
|
|
2190
|
+
);
|
|
2191
|
+
stage = 'rtc_publish';
|
|
2192
|
+
logger.log(
|
|
2193
|
+
LogSource.AgoraSDK,
|
|
2194
|
+
'API',
|
|
2195
|
+
'[SCREENSHARE_JOURNEY] screen share start calling screenClient.publish',
|
|
2196
|
+
{...journeyData, stage, outcome: 'started'},
|
|
2197
|
+
);
|
|
2198
|
+
await this.screenClient.publish(
|
|
2199
|
+
localAudioTrack ? [localVideoTrack, localAudioTrack] : localVideoTrack,
|
|
2200
|
+
);
|
|
2201
|
+
ensureStartIsCurrent();
|
|
2202
|
+
logger.log(
|
|
2203
|
+
LogSource.AgoraSDK,
|
|
2204
|
+
'API',
|
|
2205
|
+
'[SCREENSHARE_JOURNEY] screen share start screenClient.publish completed successfully',
|
|
2206
|
+
{...journeyData, stage, outcome: 'success'},
|
|
2207
|
+
);
|
|
2208
|
+
const lifecycle: ActiveScreenshareLifecycle = {
|
|
2209
|
+
video: localVideoTrack,
|
|
2210
|
+
audio: localAudioTrack,
|
|
2211
|
+
joined,
|
|
2212
|
+
cleaned: false,
|
|
2213
|
+
journeyData,
|
|
2214
|
+
};
|
|
2215
|
+
this.screenStream = {
|
|
2216
|
+
video: localVideoTrack,
|
|
2217
|
+
audio: localAudioTrack,
|
|
2218
|
+
};
|
|
2219
|
+
this.activeScreenshareLifecycle = lifecycle;
|
|
2220
|
+
this.inScreenshare = true;
|
|
2221
|
+
this.screenshareOperationState = 'active';
|
|
2222
|
+
this.activeScreenshareJourneyContext = {
|
|
2223
|
+
screenshareSessionId: journeyData.screenshareSessionId,
|
|
2224
|
+
recordingActive: journeyData.recordingActive,
|
|
2225
|
+
screenShareUid: journeyData.screenShareUid,
|
|
2226
|
+
stopActorUid: journeyData.stopActorUid,
|
|
2227
|
+
};
|
|
2228
|
+
localVideoTrack.on('track-ended', async () => {
|
|
2229
|
+
const nativeStopAttemptId = `${
|
|
2230
|
+
journeyData.screenshareAttemptId
|
|
2231
|
+
}-native-${Date.now()}`;
|
|
2232
|
+
const mediaTrack = localVideoTrack?.getMediaStreamTrack?.();
|
|
2233
|
+
if (this.activeScreenshareLifecycle !== lifecycle) {
|
|
1821
2234
|
logger.log(
|
|
1822
2235
|
LogSource.AgoraSDK,
|
|
1823
|
-
'
|
|
1824
|
-
'[SCREENSHARE_JOURNEY] screen share
|
|
1825
|
-
{
|
|
2236
|
+
'API',
|
|
2237
|
+
'[SCREENSHARE_JOURNEY] screen share stop ignored stale video track-ended callback',
|
|
2238
|
+
{
|
|
2239
|
+
...journeyData,
|
|
2240
|
+
action: 'stop',
|
|
2241
|
+
screenshareAttemptId: nativeStopAttemptId,
|
|
2242
|
+
stage: 'track_ended',
|
|
2243
|
+
outcome: 'skipped',
|
|
2244
|
+
stopOrigin: 'browser_native_control',
|
|
2245
|
+
operationState: this.screenshareOperationState,
|
|
2246
|
+
duplicateReason: 'stale_screenshare_lifecycle',
|
|
2247
|
+
},
|
|
1826
2248
|
);
|
|
2249
|
+
return;
|
|
1827
2250
|
}
|
|
1828
|
-
|
|
1829
|
-
stage = 'create_screen_video_track';
|
|
1830
2251
|
logger.log(
|
|
1831
2252
|
LogSource.AgoraSDK,
|
|
1832
2253
|
'API',
|
|
1833
|
-
'[SCREENSHARE_JOURNEY] screen share
|
|
2254
|
+
'[SCREENSHARE_JOURNEY] screen share stop detected from browser native control through video track-ended',
|
|
1834
2255
|
{
|
|
1835
2256
|
...journeyData,
|
|
1836
|
-
|
|
2257
|
+
action: 'stop',
|
|
2258
|
+
screenshareAttemptId: nativeStopAttemptId,
|
|
2259
|
+
stage: 'track_ended',
|
|
1837
2260
|
outcome: 'started',
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
'API',
|
|
1849
|
-
'[SCREENSHARE_JOURNEY] screen share start AgoraRTC.createScreenVideoTrack completed successfully',
|
|
1850
|
-
{
|
|
1851
|
-
...journeyData,
|
|
1852
|
-
stage,
|
|
1853
|
-
outcome: 'success',
|
|
1854
|
-
hasVideoTrack: Boolean(
|
|
1855
|
-
isSingleScreenTrack ? screenTracks : screenTracks[0],
|
|
1856
|
-
),
|
|
1857
|
-
hasAudioTrack: Boolean(
|
|
1858
|
-
isSingleScreenTrack ? false : screenTracks[1],
|
|
1859
|
-
),
|
|
2261
|
+
stopOrigin: 'browser_native_control',
|
|
2262
|
+
mediaTrack: mediaTrack
|
|
2263
|
+
? {
|
|
2264
|
+
readyState: mediaTrack.readyState,
|
|
2265
|
+
enabled: mediaTrack.enabled,
|
|
2266
|
+
muted: mediaTrack.muted,
|
|
2267
|
+
label: mediaTrack.label,
|
|
2268
|
+
settings: mediaTrack.getSettings?.(),
|
|
2269
|
+
}
|
|
2270
|
+
: null,
|
|
1860
2271
|
},
|
|
1861
2272
|
);
|
|
1862
|
-
|
|
1863
|
-
this.
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
'API',
|
|
1872
|
-
'[SCREENSHARE_JOURNEY] screen share start calling screenClient.join',
|
|
1873
|
-
{...journeyData, stage, outcome: 'started', channelName, optionalUid},
|
|
1874
|
-
);
|
|
1875
|
-
await this.screenClient.join(
|
|
1876
|
-
this.appId,
|
|
1877
|
-
channelName,
|
|
1878
|
-
token || null,
|
|
1879
|
-
optionalUid || null,
|
|
1880
|
-
);
|
|
1881
|
-
joined = true;
|
|
1882
|
-
this.inScreenshare = true;
|
|
1883
|
-
logger.log(
|
|
1884
|
-
LogSource.AgoraSDK,
|
|
1885
|
-
'API',
|
|
1886
|
-
'[SCREENSHARE_JOURNEY] screen share start screenClient.join completed successfully',
|
|
1887
|
-
{...journeyData, stage, outcome: 'success'},
|
|
1888
|
-
);
|
|
1889
|
-
stage = 'rtc_publish';
|
|
1890
|
-
logger.log(
|
|
1891
|
-
LogSource.AgoraSDK,
|
|
1892
|
-
'API',
|
|
1893
|
-
'[SCREENSHARE_JOURNEY] screen share start calling screenClient.publish',
|
|
1894
|
-
{...journeyData, stage, outcome: 'started'},
|
|
1895
|
-
);
|
|
1896
|
-
await this.screenClient.publish(
|
|
1897
|
-
this.screenStream.audio
|
|
1898
|
-
? [this.screenStream.video, this.screenStream.audio]
|
|
1899
|
-
: this.screenStream.video,
|
|
1900
|
-
);
|
|
1901
|
-
logger.log(
|
|
1902
|
-
LogSource.AgoraSDK,
|
|
1903
|
-
'API',
|
|
1904
|
-
'[SCREENSHARE_JOURNEY] screen share start screenClient.publish completed successfully',
|
|
1905
|
-
{...journeyData, stage, outcome: 'success'},
|
|
1906
|
-
);
|
|
1907
|
-
this.activeScreenshareJourneyContext = {
|
|
1908
|
-
screenshareSessionId: journeyData.screenshareSessionId,
|
|
1909
|
-
recordingActive: journeyData.recordingActive,
|
|
1910
|
-
screenShareUid: journeyData.screenShareUid,
|
|
1911
|
-
stopActorUid: journeyData.stopActorUid,
|
|
1912
|
-
};
|
|
1913
|
-
this.screenStream.video.on('track-ended', async () => {
|
|
1914
|
-
const nativeStopAttemptId = `${
|
|
1915
|
-
journeyData.screenshareAttemptId
|
|
1916
|
-
}-native-${Date.now()}`;
|
|
1917
|
-
const mediaTrack = this.screenStream.video?.getMediaStreamTrack?.();
|
|
1918
|
-
logger.log(
|
|
2273
|
+
try {
|
|
2274
|
+
await this.cleanupActiveScreenshare(
|
|
2275
|
+
'browser_native_control',
|
|
2276
|
+
true,
|
|
2277
|
+
nativeStopAttemptId,
|
|
2278
|
+
lifecycle,
|
|
2279
|
+
);
|
|
2280
|
+
} catch (error) {
|
|
2281
|
+
logger.error(
|
|
1919
2282
|
LogSource.AgoraSDK,
|
|
1920
2283
|
'API',
|
|
1921
|
-
'[SCREENSHARE_JOURNEY] screen share stop
|
|
2284
|
+
'[SCREENSHARE_JOURNEY] screen share stop from browser native control completed with cleanup errors',
|
|
1922
2285
|
{
|
|
1923
2286
|
...journeyData,
|
|
1924
2287
|
action: 'stop',
|
|
1925
2288
|
screenshareAttemptId: nativeStopAttemptId,
|
|
1926
|
-
stage: '
|
|
1927
|
-
outcome: '
|
|
2289
|
+
stage: 'cleanup',
|
|
2290
|
+
outcome: 'failure',
|
|
1928
2291
|
stopOrigin: 'browser_native_control',
|
|
1929
|
-
|
|
1930
|
-
? {
|
|
1931
|
-
readyState: mediaTrack.readyState,
|
|
1932
|
-
enabled: mediaTrack.enabled,
|
|
1933
|
-
muted: mediaTrack.muted,
|
|
1934
|
-
label: mediaTrack.label,
|
|
1935
|
-
settings: mediaTrack.getSettings?.(),
|
|
1936
|
-
}
|
|
1937
|
-
: null,
|
|
2292
|
+
...getScreenshareErrorDetails(error),
|
|
1938
2293
|
},
|
|
1939
2294
|
);
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
true,
|
|
1943
|
-
nativeStopAttemptId,
|
|
1944
|
-
);
|
|
1945
|
-
});
|
|
1946
|
-
} catch (e) {
|
|
1947
|
-
logger.error(
|
|
2295
|
+
}
|
|
2296
|
+
logger.log(
|
|
1948
2297
|
LogSource.AgoraSDK,
|
|
1949
2298
|
'API',
|
|
1950
|
-
|
|
2299
|
+
getScreenshareSessionBoundaryMessage(
|
|
2300
|
+
'end',
|
|
2301
|
+
journeyData.screenshareSessionId,
|
|
2302
|
+
),
|
|
1951
2303
|
{
|
|
1952
2304
|
...journeyData,
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2305
|
+
action: 'stop',
|
|
2306
|
+
screenshareAttemptId: nativeStopAttemptId,
|
|
2307
|
+
stage: 'session_boundary',
|
|
2308
|
+
outcome: 'ended',
|
|
2309
|
+
stopOrigin: 'browser_native_control',
|
|
1957
2310
|
},
|
|
1958
2311
|
);
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
throw e;
|
|
1963
|
-
}
|
|
1964
|
-
} else {
|
|
1965
|
-
logger.log(
|
|
2312
|
+
});
|
|
2313
|
+
} catch (e) {
|
|
2314
|
+
logger.error(
|
|
1966
2315
|
LogSource.AgoraSDK,
|
|
1967
2316
|
'API',
|
|
1968
|
-
`[SCREENSHARE_JOURNEY] screen share
|
|
1969
|
-
{
|
|
2317
|
+
`[SCREENSHARE_JOURNEY] screen share start failed inside RTC engine at ${stage}`,
|
|
2318
|
+
{
|
|
2319
|
+
...journeyData,
|
|
2320
|
+
stage,
|
|
2321
|
+
outcome: 'failure',
|
|
2322
|
+
joined,
|
|
2323
|
+
...getScreenshareErrorDetails(e),
|
|
2324
|
+
},
|
|
1970
2325
|
);
|
|
1971
|
-
|
|
1972
|
-
|
|
2326
|
+
const cleanupOperations: Array<() => unknown> = [
|
|
2327
|
+
() => localAudioTrack?.stop(),
|
|
2328
|
+
() => localVideoTrack?.stop(),
|
|
2329
|
+
() => localAudioTrack?.close(),
|
|
2330
|
+
() => localVideoTrack?.close(),
|
|
2331
|
+
];
|
|
2332
|
+
if (joined) {
|
|
2333
|
+
cleanupOperations.push(() => this.screenClient.leave());
|
|
2334
|
+
}
|
|
2335
|
+
try {
|
|
2336
|
+
for (const cleanupOperation of cleanupOperations) {
|
|
2337
|
+
try {
|
|
2338
|
+
await cleanupOperation();
|
|
2339
|
+
} catch (cleanupError) {
|
|
2340
|
+
logger.error(
|
|
2341
|
+
LogSource.AgoraSDK,
|
|
2342
|
+
'API',
|
|
2343
|
+
`[SCREENSHARE_JOURNEY] screen share start failure cleanup operation failed`,
|
|
2344
|
+
{
|
|
2345
|
+
...journeyData,
|
|
2346
|
+
stage: 'cleanup',
|
|
2347
|
+
outcome: 'failure',
|
|
2348
|
+
...getScreenshareErrorDetails(cleanupError),
|
|
2349
|
+
},
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
} finally {
|
|
2354
|
+
this.screenStream = {};
|
|
2355
|
+
this.activeScreenshareLifecycle = null;
|
|
2356
|
+
this.inScreenshare = false;
|
|
2357
|
+
this.activeScreenshareJourneyContext = null;
|
|
2358
|
+
this.screenshareOperationState = 'inactive';
|
|
2359
|
+
}
|
|
2360
|
+
throw e;
|
|
1973
2361
|
}
|
|
1974
2362
|
}
|
|
1975
2363
|
}
|