agora-appbuilder-core 4.1.23 → 4.1.24-beta.1
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 +1 -1
- package/template/bridge/rtc/webNg/RtcEngine.ts +86 -49
- package/template/bridge/rtc/webNg/__tests__/screenshareLifecycle.test.ts +50 -21
- package/template/defaultConfig.js +2 -2
- package/template/src/subComponents/caption/Transcript.tsx +36 -0
- package/template/src/subComponents/caption/__tests__/transcriptJourney.test.ts +7 -0
- package/template/src/subComponents/caption/transcriptJourney.ts +1 -0
- package/template/src/subComponents/caption/useCaption.tsx +215 -46
- package/template/src/subComponents/caption/useSTTAPI.tsx +13 -12
- package/template/src/subComponents/caption/useStreamMessageUtils.ts +109 -8
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +115 -30
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +489 -147
- package/template/src/subComponents/screenshare/__tests__/ScreenshareConfigure.test.tsx +245 -0
- package/template/src/subComponents/screenshare/__tests__/screenshareInterruptionRecovery.test.ts +119 -0
- package/template/src/subComponents/screenshare/screenshareInterruptionRecovery.ts +118 -0
package/package.json
CHANGED
|
@@ -209,6 +209,14 @@ interface ActiveScreenshareLifecycle {
|
|
|
209
209
|
cleanupPromise?: Promise<void>;
|
|
210
210
|
journeyData: Record<string, unknown>;
|
|
211
211
|
}
|
|
212
|
+
interface ScreenshareJourneyContext {
|
|
213
|
+
screenshareAttemptId?: string;
|
|
214
|
+
screenshareSessionId?: string;
|
|
215
|
+
recordingActive?: boolean;
|
|
216
|
+
screenShareUid?: UID;
|
|
217
|
+
stopOrigin?: string;
|
|
218
|
+
stopActorUid?: UID;
|
|
219
|
+
}
|
|
212
220
|
interface RemoteStream {
|
|
213
221
|
audio?: IRemoteAudioTrack;
|
|
214
222
|
video?: IRemoteVideoTrack;
|
|
@@ -883,24 +891,28 @@ export default class RtcEngine {
|
|
|
883
891
|
user,
|
|
884
892
|
mediaType,
|
|
885
893
|
);
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
'RTC [subscribe] to track successfully done',
|
|
900
|
-
user,
|
|
901
|
-
mediaType,
|
|
902
|
-
);
|
|
894
|
+
const isOwnScreenshare =
|
|
895
|
+
this.inScreenshare && user.uid === this.screenClient?.uid;
|
|
896
|
+
if (isOwnScreenshare) {
|
|
897
|
+
if (mediaType === 'video') {
|
|
898
|
+
(this.eventsMap.get('onRemoteVideoStateChanged') as callbackType)(
|
|
899
|
+
{},
|
|
900
|
+
user.uid,
|
|
901
|
+
2,
|
|
902
|
+
0,
|
|
903
|
+
0,
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
return;
|
|
903
907
|
}
|
|
908
|
+
await this.client.subscribe(user, mediaType);
|
|
909
|
+
logger.log(
|
|
910
|
+
LogSource.AgoraSDK,
|
|
911
|
+
'API',
|
|
912
|
+
'RTC [subscribe] to track successfully done',
|
|
913
|
+
user,
|
|
914
|
+
mediaType,
|
|
915
|
+
);
|
|
904
916
|
// If the subscribed track is an audio track
|
|
905
917
|
if (mediaType === 'audio') {
|
|
906
918
|
const audioTrack = user.audioTrack;
|
|
@@ -948,6 +960,20 @@ export default class RtcEngine {
|
|
|
948
960
|
user,
|
|
949
961
|
mediaType,
|
|
950
962
|
);
|
|
963
|
+
const isOwnScreenshare =
|
|
964
|
+
this.inScreenshare && user.uid === this.screenClient?.uid;
|
|
965
|
+
if (isOwnScreenshare) {
|
|
966
|
+
if (mediaType === 'video') {
|
|
967
|
+
(this.eventsMap.get('onRemoteVideoStateChanged') as callbackType)(
|
|
968
|
+
{},
|
|
969
|
+
user.uid,
|
|
970
|
+
0,
|
|
971
|
+
0,
|
|
972
|
+
0,
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
951
977
|
if (mediaType === 'video') {
|
|
952
978
|
this.logRemoteScreenshareTermination(
|
|
953
979
|
user.uid,
|
|
@@ -1713,6 +1739,9 @@ export default class RtcEngine {
|
|
|
1713
1739
|
return;
|
|
1714
1740
|
}
|
|
1715
1741
|
|
|
1742
|
+
// The track-ended callback passes the exact lifecycle object it captured.
|
|
1743
|
+
// A different reference means a newer screen share is now active, so this
|
|
1744
|
+
// older callback must not clean up the current share.
|
|
1716
1745
|
if (
|
|
1717
1746
|
expectedLifecycle &&
|
|
1718
1747
|
this.activeScreenshareLifecycle !== expectedLifecycle
|
|
@@ -1814,6 +1843,9 @@ export default class RtcEngine {
|
|
|
1814
1843
|
throw error;
|
|
1815
1844
|
} finally {
|
|
1816
1845
|
lifecycle.cleaned = true;
|
|
1846
|
+
// Only the lifecycle that is still active may clear shared state and
|
|
1847
|
+
// notify the app. Object identity prevents stale cleanup from ending a
|
|
1848
|
+
// newer screen-share session.
|
|
1817
1849
|
if (this.activeScreenshareLifecycle === lifecycle) {
|
|
1818
1850
|
this.activeScreenshareLifecycle = null;
|
|
1819
1851
|
this.screenStream = {};
|
|
@@ -1970,6 +2002,41 @@ export default class RtcEngine {
|
|
|
1970
2002
|
}
|
|
1971
2003
|
}
|
|
1972
2004
|
|
|
2005
|
+
async stopScreenshare(
|
|
2006
|
+
journeyContext: ScreenshareJourneyContext = {},
|
|
2007
|
+
): Promise<void> {
|
|
2008
|
+
const journeyData = {
|
|
2009
|
+
action: 'stop' as const,
|
|
2010
|
+
screenshareAttemptId:
|
|
2011
|
+
journeyContext.screenshareAttemptId || 'rtc-unknown-attempt',
|
|
2012
|
+
screenshareSessionId:
|
|
2013
|
+
journeyContext.screenshareSessionId || 'unknown-session',
|
|
2014
|
+
recordingActive: journeyContext.recordingActive || false,
|
|
2015
|
+
screenShareUid:
|
|
2016
|
+
journeyContext.screenShareUid || this.screenClient?.uid,
|
|
2017
|
+
stopOrigin: journeyContext.stopOrigin || 'unknown',
|
|
2018
|
+
stopActorUid: journeyContext.stopActorUid,
|
|
2019
|
+
};
|
|
2020
|
+
logger.log(
|
|
2021
|
+
LogSource.AgoraSDK,
|
|
2022
|
+
'API',
|
|
2023
|
+
`[SCREENSHARE_JOURNEY] screen share stop entered RTC engine from ${journeyData.stopOrigin}`,
|
|
2024
|
+
{
|
|
2025
|
+
...journeyData,
|
|
2026
|
+
stage: 'rtc_stop',
|
|
2027
|
+
outcome: 'started',
|
|
2028
|
+
requestedAction: 'stop',
|
|
2029
|
+
executedAction: 'stop',
|
|
2030
|
+
operationState: this.screenshareOperationState,
|
|
2031
|
+
},
|
|
2032
|
+
);
|
|
2033
|
+
await this.cleanupActiveScreenshare(
|
|
2034
|
+
journeyData.stopOrigin,
|
|
2035
|
+
true,
|
|
2036
|
+
journeyData.screenshareAttemptId,
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
1973
2040
|
async startScreenshare(
|
|
1974
2041
|
token: string,
|
|
1975
2042
|
channelName: string,
|
|
@@ -1986,18 +2053,10 @@ export default class RtcEngine {
|
|
|
1986
2053
|
encoderConfig: this.screenShareProfile,
|
|
1987
2054
|
},
|
|
1988
2055
|
audio: 'enable' | 'disable' | 'auto' = 'auto',
|
|
1989
|
-
journeyContext: {
|
|
1990
|
-
action?: 'start' | 'stop';
|
|
1991
|
-
screenshareAttemptId?: string;
|
|
1992
|
-
screenshareSessionId?: string;
|
|
1993
|
-
recordingActive?: boolean;
|
|
1994
|
-
screenShareUid?: UID;
|
|
1995
|
-
stopOrigin?: string;
|
|
1996
|
-
stopActorUid?: UID;
|
|
1997
|
-
} = {},
|
|
2056
|
+
journeyContext: ScreenshareJourneyContext = {},
|
|
1998
2057
|
): Promise<void> {
|
|
1999
2058
|
const journeyData = {
|
|
2000
|
-
action:
|
|
2059
|
+
action: 'start' as const,
|
|
2001
2060
|
screenshareAttemptId:
|
|
2002
2061
|
journeyContext.screenshareAttemptId || 'rtc-unknown-attempt',
|
|
2003
2062
|
screenshareSessionId:
|
|
@@ -2011,28 +2070,6 @@ export default class RtcEngine {
|
|
|
2011
2070
|
...screenShareConfig,
|
|
2012
2071
|
encoderConfig: this.screenShareProfile,
|
|
2013
2072
|
};
|
|
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
2073
|
if (this.screenshareOperationState !== 'inactive' || this.inScreenshare) {
|
|
2037
2074
|
const duplicateStartError = Object.assign(
|
|
2038
2075
|
new Error(
|
|
@@ -75,7 +75,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
75
75
|
let engine: any;
|
|
76
76
|
let screenClient: any;
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const callStartScreenshare = (sessionId = 'session-1') =>
|
|
79
79
|
engine.startScreenshare(
|
|
80
80
|
'token',
|
|
81
81
|
'channel',
|
|
@@ -87,14 +87,21 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
87
87
|
{encoderConfig: '1080p_2'},
|
|
88
88
|
'auto',
|
|
89
89
|
{
|
|
90
|
-
|
|
91
|
-
screenshareAttemptId: `${action}-request`,
|
|
90
|
+
screenshareAttemptId: 'start-request',
|
|
92
91
|
screenshareSessionId: sessionId,
|
|
93
92
|
screenShareUid: 101,
|
|
94
93
|
stopOrigin: 'toolbar',
|
|
95
94
|
},
|
|
96
95
|
);
|
|
97
96
|
|
|
97
|
+
const callStopScreenshare = (sessionId = 'session-1') =>
|
|
98
|
+
engine.stopScreenshare({
|
|
99
|
+
screenshareAttemptId: 'stop-request',
|
|
100
|
+
screenshareSessionId: sessionId,
|
|
101
|
+
screenShareUid: 101,
|
|
102
|
+
stopOrigin: 'toolbar',
|
|
103
|
+
});
|
|
104
|
+
|
|
98
105
|
beforeAll(() => {
|
|
99
106
|
(global as any).window = {};
|
|
100
107
|
RtcEngine = require('../RtcEngine').default;
|
|
@@ -120,9 +127,9 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
120
127
|
const {track} = createTrack();
|
|
121
128
|
mockCreateScreenVideoTrack.mockReturnValueOnce(picker.promise);
|
|
122
129
|
|
|
123
|
-
const firstStart =
|
|
130
|
+
const firstStart = callStartScreenshare();
|
|
124
131
|
await expect(
|
|
125
|
-
|
|
132
|
+
callStartScreenshare('duplicate-session'),
|
|
126
133
|
).rejects.toMatchObject({code: 'SCREENSHARE_OPERATION_IN_PROGRESS'});
|
|
127
134
|
|
|
128
135
|
expect(mockCreateScreenVideoTrack).toHaveBeenCalledTimes(1);
|
|
@@ -136,7 +143,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
136
143
|
const stopped = jest.fn();
|
|
137
144
|
engine.eventsMap.set('onScreenshareStopped', stopped);
|
|
138
145
|
|
|
139
|
-
await
|
|
146
|
+
await callStopScreenshare();
|
|
140
147
|
|
|
141
148
|
expect(mockCreateScreenVideoTrack).not.toHaveBeenCalled();
|
|
142
149
|
expect(screenClient.join).not.toHaveBeenCalled();
|
|
@@ -153,7 +160,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
153
160
|
}),
|
|
154
161
|
);
|
|
155
162
|
|
|
156
|
-
await expect(
|
|
163
|
+
await expect(callStartScreenshare()).rejects.toMatchObject({
|
|
157
164
|
code: 'INVALID_OPERATION',
|
|
158
165
|
});
|
|
159
166
|
|
|
@@ -168,7 +175,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
168
175
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
169
176
|
screenClient.publish.mockRejectedValueOnce(new Error('publish failed'));
|
|
170
177
|
|
|
171
|
-
await expect(
|
|
178
|
+
await expect(callStartScreenshare()).rejects.toThrow('publish failed');
|
|
172
179
|
|
|
173
180
|
expect(track.stop).toHaveBeenCalledTimes(1);
|
|
174
181
|
expect(track.close).toHaveBeenCalledTimes(1);
|
|
@@ -185,7 +192,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
185
192
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
186
193
|
screenClient.publish.mockRejectedValueOnce(publishError);
|
|
187
194
|
|
|
188
|
-
await expect(
|
|
195
|
+
await expect(callStartScreenshare()).rejects.toBe(publishError);
|
|
189
196
|
|
|
190
197
|
expect(track.stop).toHaveBeenCalledTimes(1);
|
|
191
198
|
expect(track.close).toHaveBeenCalledTimes(1);
|
|
@@ -201,13 +208,13 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
201
208
|
}),
|
|
202
209
|
);
|
|
203
210
|
|
|
204
|
-
await expect(
|
|
211
|
+
await expect(callStartScreenshare()).rejects.toMatchObject({
|
|
205
212
|
code: 'PERMISSION_DENIED',
|
|
206
213
|
});
|
|
207
214
|
|
|
208
215
|
const {track} = createTrack();
|
|
209
216
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
210
|
-
await
|
|
217
|
+
await callStartScreenshare('session-2');
|
|
211
218
|
|
|
212
219
|
expect(mockCreateScreenVideoTrack).toHaveBeenCalledTimes(2);
|
|
213
220
|
expect(screenClient.join).toHaveBeenCalledTimes(1);
|
|
@@ -220,7 +227,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
220
227
|
const {track} = createTrack();
|
|
221
228
|
mockCreateScreenVideoTrack.mockReturnValueOnce(picker.promise);
|
|
222
229
|
|
|
223
|
-
const pendingStart =
|
|
230
|
+
const pendingStart = callStartScreenshare();
|
|
224
231
|
await engine.release('end_call_cleanup');
|
|
225
232
|
picker.resolve(track);
|
|
226
233
|
|
|
@@ -239,8 +246,8 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
239
246
|
engine.eventsMap.set('onScreenshareStopped', stopped);
|
|
240
247
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
241
248
|
|
|
242
|
-
await
|
|
243
|
-
await
|
|
249
|
+
await callStartScreenshare();
|
|
250
|
+
await callStopScreenshare();
|
|
244
251
|
await handlers['track-ended']();
|
|
245
252
|
|
|
246
253
|
expect(screenClient.leave).toHaveBeenCalledTimes(1);
|
|
@@ -249,6 +256,28 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
249
256
|
expect(stopped).toHaveBeenCalledTimes(1);
|
|
250
257
|
});
|
|
251
258
|
|
|
259
|
+
it('does not let an older lifecycle clean up a newer screen share', async () => {
|
|
260
|
+
const first = createTrack();
|
|
261
|
+
const second = createTrack();
|
|
262
|
+
const stopped = jest.fn();
|
|
263
|
+
engine.eventsMap.set('onScreenshareStopped', stopped);
|
|
264
|
+
mockCreateScreenVideoTrack
|
|
265
|
+
.mockResolvedValueOnce(first.track)
|
|
266
|
+
.mockResolvedValueOnce(second.track);
|
|
267
|
+
|
|
268
|
+
await callStartScreenshare();
|
|
269
|
+
await callStopScreenshare();
|
|
270
|
+
await callStartScreenshare('session-2');
|
|
271
|
+
await first.handlers['track-ended']();
|
|
272
|
+
|
|
273
|
+
expect(engine.activeScreenshareLifecycle.video).toBe(second.track);
|
|
274
|
+
expect(engine.inScreenshare).toBe(true);
|
|
275
|
+
expect(screenClient.leave).toHaveBeenCalledTimes(1);
|
|
276
|
+
expect(second.track.stop).not.toHaveBeenCalled();
|
|
277
|
+
expect(second.track.close).not.toHaveBeenCalled();
|
|
278
|
+
expect(stopped).toHaveBeenCalledTimes(1);
|
|
279
|
+
});
|
|
280
|
+
|
|
252
281
|
it('joins an existing cleanup when Stop is requested twice', async () => {
|
|
253
282
|
const {track} = createTrack();
|
|
254
283
|
const leave = deferred<void>();
|
|
@@ -257,9 +286,9 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
257
286
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
258
287
|
screenClient.leave.mockReturnValueOnce(leave.promise);
|
|
259
288
|
|
|
260
|
-
await
|
|
261
|
-
const firstStop =
|
|
262
|
-
const secondStop =
|
|
289
|
+
await callStartScreenshare();
|
|
290
|
+
const firstStop = callStopScreenshare();
|
|
291
|
+
const secondStop = callStopScreenshare();
|
|
263
292
|
leave.resolve(undefined);
|
|
264
293
|
await Promise.all([firstStop, secondStop]);
|
|
265
294
|
|
|
@@ -278,8 +307,8 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
278
307
|
throw new Error('track stop failed');
|
|
279
308
|
});
|
|
280
309
|
|
|
281
|
-
await
|
|
282
|
-
await expect(
|
|
310
|
+
await callStartScreenshare();
|
|
311
|
+
await expect(callStopScreenshare()).resolves.toBeUndefined();
|
|
283
312
|
|
|
284
313
|
expect(track.close).toHaveBeenCalledTimes(1);
|
|
285
314
|
expect(screenClient.leave).toHaveBeenCalledTimes(1);
|
|
@@ -294,7 +323,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
294
323
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
295
324
|
screenClient.leave.mockRejectedValueOnce(new Error('leave failed'));
|
|
296
325
|
|
|
297
|
-
await
|
|
326
|
+
await callStartScreenshare();
|
|
298
327
|
await expect(handlers['track-ended']()).resolves.toBeUndefined();
|
|
299
328
|
|
|
300
329
|
expect(screenClient.leave).toHaveBeenCalledTimes(1);
|
|
@@ -317,7 +346,7 @@ describe('web RTC screen-share lifecycle', () => {
|
|
|
317
346
|
engine.eventsMap.set('onScreenshareStopped', stopped);
|
|
318
347
|
mockCreateScreenVideoTrack.mockResolvedValueOnce(track);
|
|
319
348
|
|
|
320
|
-
await
|
|
349
|
+
await callStartScreenshare();
|
|
321
350
|
await engine.release('end_call_cleanup');
|
|
322
351
|
|
|
323
352
|
const {logger} = require('../../../../src/logger/AppBuilderLogger');
|
|
@@ -77,8 +77,8 @@ const DefaultConfig = {
|
|
|
77
77
|
CHAT_ORG_NAME: "",
|
|
78
78
|
CHAT_APP_NAME: "",
|
|
79
79
|
CHAT_URL: "",
|
|
80
|
-
CLI_VERSION: "3.1.
|
|
81
|
-
CORE_VERSION: "4.1.
|
|
80
|
+
CLI_VERSION: "3.1.24-beta.1",
|
|
81
|
+
CORE_VERSION: "4.1.24-beta.1",
|
|
82
82
|
DISABLE_LANDSCAPE_MODE: false,
|
|
83
83
|
STT_AUTO_START: false,
|
|
84
84
|
CLOUD_RECORDING_AUTO_START: false,
|
|
@@ -40,6 +40,8 @@ import {
|
|
|
40
40
|
sttTranscriptPanelSearchText,
|
|
41
41
|
sttTranscriptPanelViewLatestText,
|
|
42
42
|
} from '../../../src/language/default-labels/videoCallScreenLabels';
|
|
43
|
+
import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
44
|
+
import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
|
|
43
45
|
|
|
44
46
|
export interface TranscriptProps {
|
|
45
47
|
showHeader?: boolean;
|
|
@@ -56,6 +58,7 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
56
58
|
isSTTActive,
|
|
57
59
|
selectedTranslationLanguage,
|
|
58
60
|
transcriptViewMode,
|
|
61
|
+
isSTTListenerAdded,
|
|
59
62
|
} = useCaption();
|
|
60
63
|
|
|
61
64
|
const settingSpokenLanguageLabel = useString(sttSettingSpokenLanguageText)();
|
|
@@ -68,6 +71,39 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
68
71
|
|
|
69
72
|
const data = meetingTranscript; // Object.entries(transcript);
|
|
70
73
|
console.log('[STT_GLOBAL] meetingTranscript data: ', data);
|
|
74
|
+
const hasLoggedFirstEntryRef = React.useRef(false);
|
|
75
|
+
const transcriptEntryCountRef = React.useRef(data.length);
|
|
76
|
+
transcriptEntryCountRef.current = data.length;
|
|
77
|
+
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
logger.log(
|
|
80
|
+
LogSource.Internals,
|
|
81
|
+
'TRANSCRIPT',
|
|
82
|
+
`${TRANSCRIPT_JOURNEY} transcript panel state`,
|
|
83
|
+
{
|
|
84
|
+
stage: 'transcript_panel',
|
|
85
|
+
isSTTActive,
|
|
86
|
+
listenerRegistered: isSTTListenerAdded,
|
|
87
|
+
transcriptEntryCount: transcriptEntryCountRef.current,
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
}, [isSTTActive, isSTTListenerAdded]);
|
|
91
|
+
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
if (data.length > 0 && !hasLoggedFirstEntryRef.current) {
|
|
94
|
+
hasLoggedFirstEntryRef.current = true;
|
|
95
|
+
logger.log(
|
|
96
|
+
LogSource.Internals,
|
|
97
|
+
'TRANSCRIPT',
|
|
98
|
+
`${TRANSCRIPT_JOURNEY} first transcript entry available to panel`,
|
|
99
|
+
{
|
|
100
|
+
stage: 'transcript_panel_data',
|
|
101
|
+
outcome: 'success',
|
|
102
|
+
transcriptEntryCount: data.length,
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}, [data.length]);
|
|
71
107
|
|
|
72
108
|
const [showButton, setShowButton] = React.useState(false);
|
|
73
109
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const TRANSCRIPT_JOURNEY = '[TRANSCRIPT_JOURNEY]';
|