@snugdesk/avaya-ipo-widget 0.2.2 → 0.2.4
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/fesm2022/snugdesk-avaya-ipo-widget.mjs +965 -353
- package/fesm2022/snugdesk-avaya-ipo-widget.mjs.map +1 -1
- package/index.d.ts +174 -43
- package/package.json +1 -1
- package/src/assets/css/intl-tel-input-dropdown.css +0 -0
- package/src/assets/images/bg-app_color_line.gif +0 -0
- package/src/assets/images/icons/sd-backspace.png +0 -0
- package/src/assets/images/icons/sd-call_failed.gif +0 -0
- package/src/assets/images/logo-avaya_small_color.svg +0 -20
- package/src/assets/images/logo-avaya_small_gray.svg +0 -16
package/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { NgZone, OnInit, OnDestroy, EventEmitter, ChangeDetectorRef, AfterViewInit, ElementRef
|
|
2
|
+
import { NgZone, OnInit, OnDestroy, OnChanges, EventEmitter, ChangeDetectorRef, SimpleChanges, AfterViewInit, ElementRef } from '@angular/core';
|
|
3
3
|
import * as i14 from '@angular/forms';
|
|
4
4
|
import { FormGroup, FormBuilder } from '@angular/forms';
|
|
5
5
|
import * as rxjs from 'rxjs';
|
|
6
6
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
7
7
|
import { HttpClient } from '@angular/common/http';
|
|
8
|
-
import { SnugdeskAuthenticationService } from '@snugdesk/core';
|
|
8
|
+
import { SnugdeskAuthenticationService, AppSyncHelperService } from '@snugdesk/core';
|
|
9
9
|
import * as i19 from 'ngx-intl-tel-input';
|
|
10
10
|
import { CountryISO, SearchCountryField } from 'ngx-intl-tel-input';
|
|
11
11
|
import * as i13 from '@angular/common';
|
|
@@ -62,6 +62,9 @@ declare class AvayaIPOService {
|
|
|
62
62
|
getActiveCallCount(): number;
|
|
63
63
|
setLastIncomingCall(callId: string, farEndNumber: string): void;
|
|
64
64
|
private startRingTone;
|
|
65
|
+
private ringRetryHandler;
|
|
66
|
+
private armRingRetryOnGesture;
|
|
67
|
+
private disarmRingRetry;
|
|
65
68
|
private stopRingTone;
|
|
66
69
|
private agentId;
|
|
67
70
|
private loginStatusSubject;
|
|
@@ -69,7 +72,6 @@ declare class AvayaIPOService {
|
|
|
69
72
|
private readonly DOM_TAGS;
|
|
70
73
|
private configTemplate;
|
|
71
74
|
private readonly agentStatusApiUrl;
|
|
72
|
-
private readonly CALL_HISTORY_API_URL;
|
|
73
75
|
private prewarmedStream?;
|
|
74
76
|
private isSafari;
|
|
75
77
|
private _rpcPatched;
|
|
@@ -178,12 +180,18 @@ declare class EntitiesSearchService {
|
|
|
178
180
|
private http;
|
|
179
181
|
private authenticationService;
|
|
180
182
|
private nameCache;
|
|
183
|
+
private entityIdCache;
|
|
181
184
|
constructor(http: HttpClient, authenticationService: AuthenticationService);
|
|
182
185
|
fetchContacts(tenantId: string, size?: number, searchAfter?: [string, string]): Promise<any>;
|
|
183
186
|
searchByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<any>;
|
|
184
187
|
searchEntities(tenantId: string, query: string, size?: number, from?: number): Promise<any>;
|
|
185
188
|
getCachedName(tenantId: string, phoneNumber: string): string | null;
|
|
186
189
|
lookupNameByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<string | null>;
|
|
190
|
+
/** Resolve the entity (id + name) matching a phone number; both are cached per tenant+number. */
|
|
191
|
+
lookupEntityByPhone(tenantId: string, phoneNumber: string, size?: number): Promise<{
|
|
192
|
+
id: string | null;
|
|
193
|
+
name: string | null;
|
|
194
|
+
}>;
|
|
187
195
|
private postEntities;
|
|
188
196
|
private cacheKey;
|
|
189
197
|
private ensureWildcard;
|
|
@@ -191,7 +199,7 @@ declare class EntitiesSearchService {
|
|
|
191
199
|
static ɵprov: i0.ɵɵInjectableDeclaration<EntitiesSearchService>;
|
|
192
200
|
}
|
|
193
201
|
|
|
194
|
-
declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
202
|
+
declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy, OnChanges {
|
|
195
203
|
private formBuilder;
|
|
196
204
|
private avayaIPOService;
|
|
197
205
|
private cdr;
|
|
@@ -200,9 +208,22 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
200
208
|
private entitiesSearchService;
|
|
201
209
|
private snugdeskAuthService;
|
|
202
210
|
hostDarkMode: boolean;
|
|
211
|
+
get hostModeStandalone(): boolean;
|
|
212
|
+
get hostModePopup(): boolean;
|
|
203
213
|
private readonly STORAGE_KEY;
|
|
204
214
|
isVisible: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Render mode for the widget shell:
|
|
217
|
+
* - 'popup' (default): owns no dimensions — fills whatever box the host gives it (e.g. the snugdesk-app
|
|
218
|
+
* header popover), with a min-size guard and its own internal scroll. Preserves 100% of current behavior.
|
|
219
|
+
* - 'standalone': provides its own full-page frame — a centered card on desktop, full-bleed on mobile —
|
|
220
|
+
* for running the softphone independently.
|
|
221
|
+
*/
|
|
222
|
+
displayMode: 'popup' | 'standalone';
|
|
205
223
|
configurationMode?: string;
|
|
224
|
+
/** Recording upload strategy: 'complete' (one upload at call end) or 'chunked' (live-streamed
|
|
225
|
+
* over the recording WebSocket, survives a dead tab). Defaults to APP_CONFIG.RECORDING_UPLOAD_MODE. */
|
|
226
|
+
recordingUploadMode?: 'complete' | 'chunked';
|
|
206
227
|
avayaIPOServerIP?: string;
|
|
207
228
|
avayaIPOServerPort?: number;
|
|
208
229
|
avayaIPOServerStunServerIP?: string;
|
|
@@ -212,8 +233,34 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
212
233
|
token?: string;
|
|
213
234
|
tenantId: string;
|
|
214
235
|
userId: string;
|
|
236
|
+
/**
|
|
237
|
+
* Optional Avaya IP Office credentials. When BOTH `extension` and `password` are supplied (via the
|
|
238
|
+
* host binding), the widget patches the login form and auto-logs-in once — no manual login needed.
|
|
239
|
+
* If they are not supplied, the widget falls back to any saved localStorage session, otherwise it
|
|
240
|
+
* shows the login form as before.
|
|
241
|
+
*/
|
|
242
|
+
extension?: string;
|
|
243
|
+
password?: string;
|
|
244
|
+
/** Show/hide the History tab. Default true keeps current behavior. */
|
|
245
|
+
showHistory: boolean;
|
|
246
|
+
/** Show/hide the Contacts tab. Default true keeps current behavior. */
|
|
247
|
+
showContacts: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* The bottom tab bar only earns its space when at least one of History/Contacts is visible.
|
|
250
|
+
* With both hidden only Keypad (the default view) would remain, so the whole bar is hidden.
|
|
251
|
+
*/
|
|
252
|
+
get showTabBar(): boolean;
|
|
215
253
|
notificationEvent: EventEmitter<number>;
|
|
216
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Fires when an inbound call starts ringing, so the host app can open/focus the widget popover.
|
|
256
|
+
* Payload: the call id, the caller's number, and the resolved caller name (null if not yet known).
|
|
257
|
+
*/
|
|
258
|
+
incomingCall: EventEmitter<{
|
|
259
|
+
callId: string;
|
|
260
|
+
number: string;
|
|
261
|
+
name: string | null;
|
|
262
|
+
}>;
|
|
263
|
+
readonly widgetVersion: "0.2.4";
|
|
217
264
|
isReconnectingInProgress: boolean;
|
|
218
265
|
isFailoverInProgress: boolean;
|
|
219
266
|
isFailbackInProgress: boolean;
|
|
@@ -227,23 +274,30 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
227
274
|
private awlScriptPromise?;
|
|
228
275
|
loginForm: FormGroup;
|
|
229
276
|
activeTab: 'history' | 'contacts' | 'keypad' | 'settings';
|
|
277
|
+
private previousTab;
|
|
230
278
|
private loginSub?;
|
|
231
279
|
private incomingCallSub?;
|
|
232
280
|
private callStateSub?;
|
|
233
281
|
hideTabs: boolean;
|
|
234
282
|
darkModeEnabled: boolean;
|
|
235
283
|
activeCallNumber: string | null;
|
|
284
|
+
/** Entity id of the current call's counterpart (resolved via OpenSearch); sent with the
|
|
285
|
+
* chunked-recording socket so chunks land under <tenantId>/<entityId>/avaya-ipo-chunks/. */
|
|
286
|
+
activeCallEntityId: string | null;
|
|
236
287
|
incomingCallName: string | null;
|
|
237
288
|
incomingNameResolved: boolean;
|
|
238
289
|
activeCallName: string | null;
|
|
239
290
|
authErrorMessage: string;
|
|
240
291
|
authLoading: boolean;
|
|
241
292
|
private hasInitialized;
|
|
293
|
+
private autoLoginAttempted;
|
|
242
294
|
private callLogIndex;
|
|
243
295
|
private pendingDisconnectSide;
|
|
244
296
|
private callStartTimes;
|
|
245
297
|
constructor(formBuilder: FormBuilder, avayaIPOService: AvayaIPOService, cdr: ChangeDetectorRef, countryService: CountryService, phoneNumberLookupService: PhoneNumberLookupService, entitiesSearchService: EntitiesSearchService, snugdeskAuthService: SnugdeskAuthenticationService);
|
|
246
298
|
ngOnInit(): Promise<void>;
|
|
299
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
300
|
+
private ensureVisibleTab;
|
|
247
301
|
private initAfterAuth;
|
|
248
302
|
private authenticateWithToken;
|
|
249
303
|
onAuthLoginClick(): Promise<void>;
|
|
@@ -251,6 +305,8 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
251
305
|
onLogout(): void;
|
|
252
306
|
private handleLoginStatus;
|
|
253
307
|
selectTab(tab: 'history' | 'contacts' | 'keypad' | 'settings'): void;
|
|
308
|
+
/** Leave Settings and return to the screen the user came from (guards against a now-hidden tab). */
|
|
309
|
+
closeSettings(): void;
|
|
254
310
|
onHistoryMakeCall(payload: {
|
|
255
311
|
dialOut: string;
|
|
256
312
|
name?: string;
|
|
@@ -260,6 +316,15 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
260
316
|
dialOut: string;
|
|
261
317
|
name?: string;
|
|
262
318
|
}): void;
|
|
319
|
+
/**
|
|
320
|
+
* Public API — place an outbound call programmatically (e.g. click-to-call from the host app).
|
|
321
|
+
* Switches to the keypad view and dials `number`. Requires the widget to be registered;
|
|
322
|
+
* if it is still on the login screen the call is skipped with a warning.
|
|
323
|
+
*
|
|
324
|
+
* Usage from the host app (via @ViewChild(AvayaIPOWidgetComponent)):
|
|
325
|
+
* this.avayaWidget?.makeCall('9876543210');
|
|
326
|
+
*/
|
|
327
|
+
makeCall(number: string): void;
|
|
263
328
|
onPhoneEndCall(): void;
|
|
264
329
|
onDeviceChange(change: {
|
|
265
330
|
audioInputId: string;
|
|
@@ -274,17 +339,25 @@ declare class AvayaIPOWidgetComponent implements OnInit, OnDestroy {
|
|
|
274
339
|
private getOpenSearchCallerName;
|
|
275
340
|
private normalizePhoneForSearch;
|
|
276
341
|
private persistSession;
|
|
342
|
+
private hasInputCredentials;
|
|
343
|
+
/**
|
|
344
|
+
* Auto-login when both `extension` and `password` are supplied via @Input. Fires at most once for the
|
|
345
|
+
* widget's lifetime (so a manual logout is respected and we never loop). Returns true if it kicked off
|
|
346
|
+
* a login, so the caller can skip the localStorage fallback.
|
|
347
|
+
*/
|
|
348
|
+
private tryAutoLoginFromInputs;
|
|
277
349
|
private restoreSession;
|
|
278
350
|
private restoreThemePreference;
|
|
279
351
|
private clearSession;
|
|
280
352
|
private loadAwlScript;
|
|
281
353
|
static ɵfac: i0.ɵɵFactoryDeclaration<AvayaIPOWidgetComponent, never>;
|
|
282
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<AvayaIPOWidgetComponent, "snugdesk-avaya-ipo-widget", never, { "isVisible": { "alias": "isVisible"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "avayaIPOServerIP": { "alias": "avayaIPOServerIP"; "required": false; }; "avayaIPOServerPort": { "alias": "avayaIPOServerPort"; "required": false; }; "avayaIPOServerStunServerIP": { "alias": "avayaIPOServerStunServerIP"; "required": false; }; "avayaIPOServerStunServerPort": { "alias": "avayaIPOServerStunServerPort"; "required": false; }; "avayaIPOServerTurnServerIP": { "alias": "avayaIPOServerTurnServerIP"; "required": false; }; "avayaIPOServerTurnServerPort": { "alias": "avayaIPOServerTurnServerPort"; "required": false; }; "token": { "alias": "token"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "userId": { "alias": "userId"; "required": false; }; }, { "notificationEvent": "notificationEvent"; }, never, never, false, never>;
|
|
354
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<AvayaIPOWidgetComponent, "snugdesk-avaya-ipo-widget", never, { "isVisible": { "alias": "isVisible"; "required": false; }; "displayMode": { "alias": "displayMode"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "recordingUploadMode": { "alias": "recordingUploadMode"; "required": false; }; "avayaIPOServerIP": { "alias": "avayaIPOServerIP"; "required": false; }; "avayaIPOServerPort": { "alias": "avayaIPOServerPort"; "required": false; }; "avayaIPOServerStunServerIP": { "alias": "avayaIPOServerStunServerIP"; "required": false; }; "avayaIPOServerStunServerPort": { "alias": "avayaIPOServerStunServerPort"; "required": false; }; "avayaIPOServerTurnServerIP": { "alias": "avayaIPOServerTurnServerIP"; "required": false; }; "avayaIPOServerTurnServerPort": { "alias": "avayaIPOServerTurnServerPort"; "required": false; }; "token": { "alias": "token"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "userId": { "alias": "userId"; "required": false; }; "extension": { "alias": "extension"; "required": false; }; "password": { "alias": "password"; "required": false; }; "showHistory": { "alias": "showHistory"; "required": false; }; "showContacts": { "alias": "showContacts"; "required": false; }; }, { "notificationEvent": "notificationEvent"; "incomingCall": "incomingCall"; }, never, never, false, never>;
|
|
283
355
|
}
|
|
284
356
|
|
|
285
357
|
declare class CallHistoryComponent implements OnInit {
|
|
286
|
-
private http;
|
|
287
358
|
private cdr;
|
|
359
|
+
private appSync;
|
|
360
|
+
private auth;
|
|
288
361
|
mode: 'dial' | 'transfer';
|
|
289
362
|
tenantId?: string;
|
|
290
363
|
agentId?: string;
|
|
@@ -293,17 +366,19 @@ declare class CallHistoryComponent implements OnInit {
|
|
|
293
366
|
name?: string;
|
|
294
367
|
}>;
|
|
295
368
|
transferEv: EventEmitter<any>;
|
|
296
|
-
private readonly CALL_HISTORY_API_URL;
|
|
297
369
|
showHistoryLoader: boolean;
|
|
298
370
|
callHistory: any[];
|
|
299
371
|
searchTerm: string;
|
|
300
372
|
recentCallactiveTab: 'recentCall' | 'missedCall';
|
|
301
373
|
selectedCall: any;
|
|
302
|
-
|
|
374
|
+
private readonly LIST_PHONE_INTERACTIONS_QUERY;
|
|
375
|
+
constructor(cdr: ChangeDetectorRef, appSync: AppSyncHelperService, auth: SnugdeskAuthenticationService);
|
|
303
376
|
ngOnInit(): Promise<void>;
|
|
304
377
|
recentSelectTab(tab: 'recentCall' | 'missedCall'): void;
|
|
305
378
|
loadCallHistory(): Promise<void>;
|
|
306
|
-
|
|
379
|
+
private fetchPhoneInteractions;
|
|
380
|
+
private mapInteractionToHistoryItem;
|
|
381
|
+
private safeParse;
|
|
307
382
|
makeCall(phoneNumber: string, name?: string): void;
|
|
308
383
|
get callerDropped(): any[];
|
|
309
384
|
get filteredRecent(): any[];
|
|
@@ -321,9 +396,6 @@ declare class CallHistoryComponent implements OnInit {
|
|
|
321
396
|
selectFromHistory(item: any): void;
|
|
322
397
|
private resolveDialable;
|
|
323
398
|
private resolveName;
|
|
324
|
-
private formatDialOutFromInput;
|
|
325
|
-
private getTenantIdFromSession;
|
|
326
|
-
private getUserIdFromSession;
|
|
327
399
|
getPhoneDisplay(item: any): string;
|
|
328
400
|
getPhoneBadge(item: any): string;
|
|
329
401
|
private getInitials;
|
|
@@ -337,28 +409,47 @@ type TranscriptLine = {
|
|
|
337
409
|
speaker?: string;
|
|
338
410
|
text?: string;
|
|
339
411
|
};
|
|
340
|
-
|
|
341
|
-
|
|
412
|
+
/**
|
|
413
|
+
* Shows the same AI call analysis as snugdesk-app's conversation view: the data is read
|
|
414
|
+
* from the Interaction record (metadata.aiAnalysis), which the server-side pipeline fills
|
|
415
|
+
* after the recording is uploaded — no client-side transcription is run here.
|
|
416
|
+
*/
|
|
417
|
+
declare class CallDetailsComponent implements OnChanges {
|
|
418
|
+
private appSync;
|
|
342
419
|
call: any;
|
|
343
420
|
transcriptLines: TranscriptLine[];
|
|
344
|
-
|
|
421
|
+
conversationSummary: string[];
|
|
422
|
+
nextActions: string[];
|
|
423
|
+
keyConcerns: string[];
|
|
424
|
+
callType: string;
|
|
425
|
+
customerIntent: string;
|
|
345
426
|
customerSentiment: string;
|
|
346
|
-
|
|
347
|
-
|
|
427
|
+
aiConfidenceScore: number | null;
|
|
428
|
+
summaryText: string;
|
|
429
|
+
aiProcessingStatus: string;
|
|
430
|
+
hasAnalysis: boolean;
|
|
431
|
+
isRefreshing: boolean;
|
|
432
|
+
refreshError: string;
|
|
348
433
|
isTranscriptFullscreen: boolean;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
434
|
+
private readonly GET_INTERACTION_QUERY;
|
|
435
|
+
constructor(appSync: AppSyncHelperService);
|
|
436
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
437
|
+
get isAnalysisPending(): boolean;
|
|
352
438
|
getBadge(): string;
|
|
353
439
|
getDisplayName(): string;
|
|
354
440
|
getPhone(): string;
|
|
355
441
|
getTranscriptSpeaker(line: TranscriptLine): string;
|
|
356
|
-
runTranscription(): Promise<void>;
|
|
357
|
-
private normalizeTranscript;
|
|
358
442
|
getSentimentEmoji(): string;
|
|
359
|
-
|
|
443
|
+
/** Re-read the Interaction record (the AI pipeline fills metadata.aiAnalysis asynchronously). */
|
|
444
|
+
refreshAnalysis(): Promise<void>;
|
|
360
445
|
toggleTranscriptFullscreen(): void;
|
|
361
|
-
|
|
446
|
+
/** Pull the structured AI analysis off the interaction's metadata — same shape snugdesk-app reads. */
|
|
447
|
+
private parseAnalysisFromCall;
|
|
448
|
+
private normalizeText;
|
|
449
|
+
private normalizeBulletItems;
|
|
450
|
+
private normalizeTranscript;
|
|
451
|
+
private parseSpeakerLine;
|
|
452
|
+
private safeParse;
|
|
362
453
|
static ɵfac: i0.ɵɵFactoryDeclaration<CallDetailsComponent, never>;
|
|
363
454
|
static ɵcmp: i0.ɵɵComponentDeclaration<CallDetailsComponent, "app-call-details", never, { "call": { "alias": "call"; "required": false; }; }, {}, never, never, false, never>;
|
|
364
455
|
}
|
|
@@ -447,6 +538,7 @@ declare class SettingsComponent implements OnInit, OnDestroy {
|
|
|
447
538
|
logout: EventEmitter<void>;
|
|
448
539
|
audioInputs: MediaDeviceInfo[];
|
|
449
540
|
audioOutputs: MediaDeviceInfo[];
|
|
541
|
+
readonly widgetVersion: "0.2.4";
|
|
450
542
|
ngOnInit(): void;
|
|
451
543
|
onLogout(): void;
|
|
452
544
|
onToggleDarkMode(): void;
|
|
@@ -482,35 +574,72 @@ interface CallMetadata {
|
|
|
482
574
|
agentId: string;
|
|
483
575
|
phoneNumber: string;
|
|
484
576
|
callId: string;
|
|
577
|
+
/** Entity id of the call counterpart, when the widget has resolved one (chunked recordings
|
|
578
|
+
* use it so chunks land under <tenantId>/<entityId>/avaya-ipo-chunks/). */
|
|
579
|
+
entityId?: string | null;
|
|
485
580
|
}
|
|
486
581
|
|
|
582
|
+
type RecordingUploadMode = 'complete' | 'chunked';
|
|
487
583
|
interface RecordingSession {
|
|
488
584
|
audioContext: AudioContext;
|
|
489
585
|
recordingStream: MediaStreamAudioDestinationNode;
|
|
490
586
|
recorder?: MediaRecorder | null;
|
|
491
587
|
metadata: CallMetadata;
|
|
492
588
|
stopping: boolean;
|
|
493
|
-
|
|
494
|
-
|
|
589
|
+
chunks: Blob[];
|
|
590
|
+
mimeType: string;
|
|
591
|
+
uploaded: boolean;
|
|
592
|
+
mode: RecordingUploadMode;
|
|
593
|
+
socket?: WebSocket | null;
|
|
594
|
+
seq: number;
|
|
595
|
+
pendingChunks: string[];
|
|
596
|
+
sentAny: boolean;
|
|
597
|
+
reconnectTimer?: any;
|
|
598
|
+
reconnectAttempts: number;
|
|
599
|
+
sourceNodes: AudioNode[];
|
|
600
|
+
/** Index into `chunks` up to which slices have been streamed (rewound to 0 on reconnect). */
|
|
601
|
+
streamCursor: number;
|
|
602
|
+
pumping: boolean;
|
|
603
|
+
everConnected: boolean;
|
|
604
|
+
completedSent: boolean;
|
|
495
605
|
}
|
|
496
606
|
declare class RecordingManagerService {
|
|
497
607
|
private http;
|
|
498
608
|
private sessions;
|
|
499
609
|
private readonly MIME_TYPE_PREFERRED;
|
|
500
610
|
private readonly MIME_TYPE_FALLBACK;
|
|
501
|
-
private readonly
|
|
611
|
+
private readonly TIMESLICE_MS;
|
|
612
|
+
private readonly CHUNKED_TIMESLICE_MS;
|
|
613
|
+
private readonly CHUNKED_AUDIO_BPS;
|
|
614
|
+
private readonly MAX_WS_DATA_CHARS;
|
|
502
615
|
private readonly AUDIO_CONTEXT_CLOSE_DELAY_MS;
|
|
503
|
-
private readonly
|
|
616
|
+
private readonly SOCKET_RECONNECT_DELAY_MS;
|
|
617
|
+
private readonly CALL_COMPLETED_DELAY_MS;
|
|
618
|
+
private readonly SOCKET_MAX_RECONNECT_ATTEMPTS;
|
|
619
|
+
private readonly SOCKET_FINALIZE_GRACE_MS;
|
|
620
|
+
private readonly RECORDING_API_URL;
|
|
621
|
+
private readonly RECORDING_WS_URL;
|
|
504
622
|
constructor(http: HttpClient);
|
|
505
|
-
startRecording(localMediaStream: MediaStream, remoteMediaStream: MediaStream, metadata: CallMetadata): RecordingSession | undefined;
|
|
623
|
+
startRecording(localMediaStream: MediaStream, remoteMediaStream: MediaStream, metadata: CallMetadata, mode?: RecordingUploadMode): RecordingSession | undefined;
|
|
506
624
|
getSession(callId: string): RecordingSession | undefined;
|
|
507
625
|
stopRecording(callId: string): void;
|
|
508
|
-
private
|
|
626
|
+
private finalizeRecording;
|
|
627
|
+
/**
|
|
628
|
+
* Rewire fresh local/remote streams into the SAME recording destination. The MediaRecorder (and
|
|
629
|
+
* therefore the single WebM byte stream, the socket and the seq counter) continue uninterrupted —
|
|
630
|
+
* restarting the recorder would inject a second WebM header mid-file and break playback of the
|
|
631
|
+
* stitched recording.
|
|
632
|
+
*/
|
|
633
|
+
private rebindMedia;
|
|
634
|
+
private openRecordingSocket;
|
|
635
|
+
/** Stream session.chunks in strict order; safe to call repeatedly (single active pump). */
|
|
636
|
+
private pumpChunks;
|
|
637
|
+
private streamChunk;
|
|
638
|
+
private flushPendingChunks;
|
|
639
|
+
private finalizeChunked;
|
|
509
640
|
private uploadCallRecording;
|
|
510
641
|
private convertBlobToBase64;
|
|
511
642
|
private generateFilename;
|
|
512
|
-
private generateChunkFilename;
|
|
513
|
-
private normalizePhoneNumberForUpload;
|
|
514
643
|
static ɵfac: i0.ɵɵFactoryDeclaration<RecordingManagerService, never>;
|
|
515
644
|
static ɵprov: i0.ɵɵInjectableDeclaration<RecordingManagerService>;
|
|
516
645
|
}
|
|
@@ -530,18 +659,19 @@ declare class TranscriptionStreamService implements OnDestroy {
|
|
|
530
659
|
private readonly BUFFER_SIZE;
|
|
531
660
|
private readonly SILENCE_RMS_THRESHOLD;
|
|
532
661
|
private readonly VOICE_RMS_THRESHOLD;
|
|
662
|
+
private readonly CUSTOMER_SILENCE_RMS_THRESHOLD;
|
|
663
|
+
private readonly CUSTOMER_VOICE_RMS_THRESHOLD;
|
|
533
664
|
private readonly NOISE_FLOOR_MULTIPLIER;
|
|
534
665
|
private readonly NOISE_FLOOR_SMOOTHING;
|
|
535
|
-
private readonly
|
|
666
|
+
private readonly MIN_VOICE_FRAMES;
|
|
536
667
|
private readonly CUSTOM_WS_URL;
|
|
537
|
-
private readonly
|
|
538
|
-
private readonly LANGUAGE_CODE;
|
|
539
|
-
private readonly ALT_LANGUAGE_CODES;
|
|
668
|
+
private readonly LANGUAGE;
|
|
540
669
|
private readonly TRANSCRIPTION_MODEL;
|
|
541
670
|
constructor();
|
|
542
671
|
ngOnDestroy(): void;
|
|
543
672
|
startSession(callId: string, localStream: MediaStream, remoteStream: MediaStream, allowSendBinary?: boolean): Promise<void>;
|
|
544
673
|
stopSession(callId: string): void;
|
|
674
|
+
destroyAll(): void;
|
|
545
675
|
enableBinary(callId: string): void;
|
|
546
676
|
setStreamMuted(callId: string, label: 'agent' | 'customer', muted: boolean): void;
|
|
547
677
|
private mixToMono;
|
|
@@ -549,8 +679,6 @@ declare class TranscriptionStreamService implements OnDestroy {
|
|
|
549
679
|
private encodePcm16;
|
|
550
680
|
private downsampleBuffer;
|
|
551
681
|
private queueAudio;
|
|
552
|
-
private flushPendingAudio;
|
|
553
|
-
private mergeChunks;
|
|
554
682
|
private handleTranscriptPayload;
|
|
555
683
|
private parseSpeakerLine;
|
|
556
684
|
private createStreamSession;
|
|
@@ -558,7 +686,7 @@ declare class TranscriptionStreamService implements OnDestroy {
|
|
|
558
686
|
static ɵprov: i0.ɵɵInjectableDeclaration<TranscriptionStreamService>;
|
|
559
687
|
}
|
|
560
688
|
|
|
561
|
-
declare class PhoneComponent implements OnInit, AfterViewInit,
|
|
689
|
+
declare class PhoneComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
562
690
|
private cdr;
|
|
563
691
|
private formBuilder;
|
|
564
692
|
private avayaIpoService;
|
|
@@ -583,6 +711,9 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
|
|
|
583
711
|
turnIp?: string;
|
|
584
712
|
turnPort?: number;
|
|
585
713
|
configurationMode?: string;
|
|
714
|
+
recordingUploadMode?: 'complete' | 'chunked';
|
|
715
|
+
/** Entity id of the call counterpart (resolved by the shell) — included in recording metadata. */
|
|
716
|
+
entityId?: string | null;
|
|
586
717
|
makeCallEv: EventEmitter<string>;
|
|
587
718
|
endCallEv: EventEmitter<void>;
|
|
588
719
|
audioElement: any;
|
|
@@ -602,7 +733,6 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
|
|
|
602
733
|
private pendingTranscriptionCallId;
|
|
603
734
|
private pendingTranscriptionAllowBinary;
|
|
604
735
|
private lastPartialIndex;
|
|
605
|
-
private pendingIncomingCall;
|
|
606
736
|
dialForm: FormGroup;
|
|
607
737
|
directoryForm: FormGroup;
|
|
608
738
|
showDirectoryPhonebook: boolean;
|
|
@@ -649,7 +779,6 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
|
|
|
649
779
|
get isConnecting(): boolean;
|
|
650
780
|
constructor(cdr: ChangeDetectorRef, formBuilder: FormBuilder, avayaIpoService: AvayaIPOService, authenticationService: AuthenticationService, recordingManagerService: RecordingManagerService, transcriptionStreamService: TranscriptionStreamService);
|
|
651
781
|
ngOnInit(): void;
|
|
652
|
-
ngOnChanges(changes: SimpleChanges): void;
|
|
653
782
|
ngAfterViewInit(): void;
|
|
654
783
|
ngOnDestroy(): void;
|
|
655
784
|
makeCall(): void;
|
|
@@ -720,8 +849,10 @@ declare class PhoneComponent implements OnInit, AfterViewInit, OnChanges, OnDest
|
|
|
720
849
|
private formatDialOutFromInput;
|
|
721
850
|
private formatTransferTargetFromInput;
|
|
722
851
|
private startRecordingForCall;
|
|
852
|
+
/** Per-embed [recordingUploadMode] wins; otherwise the APP_CONFIG default applies. */
|
|
853
|
+
private resolvedRecordingMode;
|
|
723
854
|
static ɵfac: i0.ɵɵFactoryDeclaration<PhoneComponent, never>;
|
|
724
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<PhoneComponent, "app-phone", never, { "contacts": { "alias": "contacts"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "agentId": { "alias": "agentId"; "required": false; }; "isActiveCall": { "alias": "isActiveCall"; "required": false; }; "activeCallNumber": { "alias": "activeCallNumber"; "required": false; }; "incomingCallName": { "alias": "incomingCallName"; "required": false; }; "incomingNameResolved": { "alias": "incomingNameResolved"; "required": false; }; "activeCallName": { "alias": "activeCallName"; "required": false; }; "serverIp": { "alias": "serverIp"; "required": false; }; "serverPort": { "alias": "serverPort"; "required": false; }; "stunIp": { "alias": "stunIp"; "required": false; }; "stunPort": { "alias": "stunPort"; "required": false; }; "turnIp": { "alias": "turnIp"; "required": false; }; "turnPort": { "alias": "turnPort"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; }, { "callScreenChange": "callScreenChange"; "makeCallEv": "makeCallEv"; "endCallEv": "endCallEv"; }, never, never, false, never>;
|
|
855
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PhoneComponent, "app-phone", never, { "contacts": { "alias": "contacts"; "required": false; }; "tenantId": { "alias": "tenantId"; "required": false; }; "agentId": { "alias": "agentId"; "required": false; }; "isActiveCall": { "alias": "isActiveCall"; "required": false; }; "activeCallNumber": { "alias": "activeCallNumber"; "required": false; }; "incomingCallName": { "alias": "incomingCallName"; "required": false; }; "incomingNameResolved": { "alias": "incomingNameResolved"; "required": false; }; "activeCallName": { "alias": "activeCallName"; "required": false; }; "serverIp": { "alias": "serverIp"; "required": false; }; "serverPort": { "alias": "serverPort"; "required": false; }; "stunIp": { "alias": "stunIp"; "required": false; }; "stunPort": { "alias": "stunPort"; "required": false; }; "turnIp": { "alias": "turnIp"; "required": false; }; "turnPort": { "alias": "turnPort"; "required": false; }; "configurationMode": { "alias": "configurationMode"; "required": false; }; "recordingUploadMode": { "alias": "recordingUploadMode"; "required": false; }; "entityId": { "alias": "entityId"; "required": false; }; }, { "callScreenChange": "callScreenChange"; "makeCallEv": "makeCallEv"; "endCallEv": "endCallEv"; }, never, never, false, never>;
|
|
725
856
|
}
|
|
726
857
|
|
|
727
858
|
declare class PhoneIdleComponent {
|
package/package.json
CHANGED
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
|
2
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
|
|
4
|
-
<desc>Created with Fabric.js 5.2.4</desc>
|
|
5
|
-
<defs>
|
|
6
|
-
</defs>
|
|
7
|
-
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
|
|
8
|
-
<g transform="matrix(1 0 0 1 540 540)" id="46946dc3-9491-43cb-8fe7-5b8ffbba78af" >
|
|
9
|
-
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
|
|
10
|
-
</g>
|
|
11
|
-
<g transform="matrix(1 0 0 1 540 540)" id="863c060c-d63b-4daf-a3bc-022136480777" >
|
|
12
|
-
</g>
|
|
13
|
-
<g transform="matrix(1 0 0 1 540 540)" id="facf6309-efdf-434e-a753-661bb2577e88" >
|
|
14
|
-
<polygon style="stroke: rgb(0,0,0); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(218,40,28); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" points="-232.07,221.69 106.75,221.69 161.6,357.36 -295.67,357.36 -368.7,513.14 -570.6,513.14 -69.8,-513.14 69.88,-513.14 570.6,513.14 368.77,513.14 -0.04,-279.29 -232.07,221.69 -232.07,221.69 -232.07,221.69 " />
|
|
15
|
-
</g>
|
|
16
|
-
<g transform="matrix(NaN NaN NaN NaN 0 0)" >
|
|
17
|
-
<g style="" >
|
|
18
|
-
</g>
|
|
19
|
-
</g>
|
|
20
|
-
</svg>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
|
2
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
|
|
4
|
-
<desc>Created with Fabric.js 5.2.4</desc>
|
|
5
|
-
<defs>
|
|
6
|
-
</defs>
|
|
7
|
-
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
|
|
8
|
-
<g transform="matrix(1 0 0 1 540 540)" id="46946dc3-9491-43cb-8fe7-5b8ffbba78af" >
|
|
9
|
-
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
|
|
10
|
-
</g>
|
|
11
|
-
<g transform="matrix(1 0 0 1 540 540)" id="863c060c-d63b-4daf-a3bc-022136480777" >
|
|
12
|
-
</g>
|
|
13
|
-
<g transform="matrix(1 0 0 1 540 540)" id="facf6309-efdf-434e-a753-661bb2577e88" >
|
|
14
|
-
<polygon style="stroke: rgb(0,0,0); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(136,136,136); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" points="-232.07,221.69 106.75,221.69 161.6,357.36 -295.67,357.36 -368.7,513.14 -570.6,513.14 -69.8,-513.14 69.88,-513.14 570.6,513.14 368.77,513.14 -0.04,-279.29 -232.07,221.69 -232.07,221.69 -232.07,221.69 " />
|
|
15
|
-
</g>
|
|
16
|
-
</svg>
|