@corti/dictation-web 0.0.0-rc.359 → 0.0.0-test.562
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 +14 -5
- package/dist/CortiDictation.d.ts +6 -2
- package/dist/CortiDictation.js +36 -14
- package/dist/CortiDictation.js.map +1 -1
- package/dist/bundle.js +2802 -1571
- package/dist/components/audio-visualiser.d.ts +3 -2
- package/dist/components/audio-visualiser.js +29 -40
- package/dist/components/audio-visualiser.js.map +1 -1
- package/dist/components/corti-dictation.d.ts +123 -0
- package/dist/components/corti-dictation.js +224 -0
- package/dist/components/corti-dictation.js.map +1 -0
- package/dist/components/device-selector.d.ts +24 -0
- package/dist/components/device-selector.js +106 -0
- package/dist/components/device-selector.js.map +1 -0
- package/dist/components/language-selector.d.ts +24 -0
- package/dist/components/language-selector.js +100 -0
- package/dist/components/language-selector.js.map +1 -0
- package/dist/components/recording-button.d.ts +37 -0
- package/dist/components/recording-button.js +203 -0
- package/dist/components/recording-button.js.map +1 -0
- package/dist/components/settings-menu.d.ts +9 -13
- package/dist/components/settings-menu.js +42 -147
- package/dist/components/settings-menu.js.map +1 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +33 -12
- package/dist/constants.js.map +1 -1
- package/dist/contexts/dictation-context.d.ts +97 -0
- package/dist/contexts/dictation-context.js +208 -0
- package/dist/contexts/dictation-context.js.map +1 -0
- package/dist/controllers/DictationController.d.ts +35 -0
- package/dist/controllers/DictationController.js +130 -0
- package/dist/controllers/DictationController.js.map +1 -0
- package/dist/controllers/MediaController.d.ts +31 -0
- package/dist/controllers/MediaController.js +99 -0
- package/dist/controllers/MediaController.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/package.json +14 -0
- package/dist/src/components/audio-visualiser.d.ts +13 -0
- package/dist/src/components/audio-visualiser.js +54 -0
- package/dist/src/components/audio-visualiser.js.map +1 -0
- package/dist/src/components/corti-dictation.d.ts +108 -0
- package/dist/src/components/corti-dictation.js +201 -0
- package/dist/src/components/corti-dictation.js.map +1 -0
- package/dist/src/components/device-selector.d.ts +24 -0
- package/dist/src/components/device-selector.js +106 -0
- package/dist/src/components/device-selector.js.map +1 -0
- package/dist/src/components/language-selector.d.ts +24 -0
- package/dist/src/components/language-selector.js +100 -0
- package/dist/src/components/language-selector.js.map +1 -0
- package/dist/src/components/recording-button.d.ts +33 -0
- package/dist/src/components/recording-button.js +179 -0
- package/dist/src/components/recording-button.js.map +1 -0
- package/dist/src/components/settings-menu.d.ts +16 -0
- package/dist/src/components/settings-menu.js +80 -0
- package/dist/src/components/settings-menu.js.map +1 -0
- package/dist/src/constants.d.ts +4 -0
- package/dist/src/constants.js +19 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/contexts/dictation-context.d.ts +83 -0
- package/dist/src/contexts/dictation-context.js +188 -0
- package/dist/src/contexts/dictation-context.js.map +1 -0
- package/dist/src/controllers/DictationController.d.ts +30 -0
- package/dist/src/controllers/DictationController.js +111 -0
- package/dist/src/controllers/DictationController.js.map +1 -0
- package/dist/src/controllers/MediaController.d.ts +25 -0
- package/dist/src/controllers/MediaController.js +83 -0
- package/dist/src/controllers/MediaController.js.map +1 -0
- package/dist/src/icons/icons.d.ts +17 -0
- package/dist/src/icons/icons.js +158 -0
- package/dist/src/icons/icons.js.map +1 -0
- package/dist/src/styles/ComponentStyles.d.ts +2 -0
- package/dist/src/styles/ComponentStyles.js +18 -0
- package/dist/src/styles/ComponentStyles.js.map +1 -0
- package/dist/src/styles/audio-visualiser.d.ts +2 -0
- package/dist/src/styles/audio-visualiser.js +33 -0
- package/dist/src/styles/audio-visualiser.js.map +1 -0
- package/dist/src/styles/buttons.d.ts +2 -0
- package/dist/src/styles/buttons.js +52 -0
- package/dist/src/styles/buttons.js.map +1 -0
- package/dist/src/styles/callout.d.ts +2 -0
- package/dist/src/styles/callout.js +23 -0
- package/dist/src/styles/callout.js.map +1 -0
- package/dist/src/styles/default-theme.d.ts +2 -0
- package/dist/src/styles/default-theme.js +50 -0
- package/dist/src/styles/default-theme.js.map +1 -0
- package/dist/src/styles/recording-button.d.ts +2 -0
- package/dist/src/styles/recording-button.js +8 -0
- package/dist/src/styles/recording-button.js.map +1 -0
- package/dist/src/styles/select.d.ts +2 -0
- package/dist/src/styles/select.js +36 -0
- package/dist/src/styles/select.js.map +1 -0
- package/dist/src/styles/settings-menu.d.ts +2 -0
- package/dist/src/styles/settings-menu.js +34 -0
- package/dist/src/styles/settings-menu.js.map +1 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/auth.d.ts +9 -0
- package/dist/src/utils/auth.js +21 -0
- package/dist/src/utils/auth.js.map +1 -0
- package/dist/src/utils/converters.d.ts +4 -0
- package/dist/src/utils/converters.js +5 -0
- package/dist/src/utils/converters.js.map +1 -0
- package/dist/src/utils/devices.d.ts +26 -0
- package/dist/src/utils/devices.js +53 -0
- package/dist/src/utils/devices.js.map +1 -0
- package/dist/src/utils/events.d.ts +37 -0
- package/dist/src/utils/events.js +88 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/languages.d.ts +7 -0
- package/dist/src/utils/languages.js +28 -0
- package/dist/src/utils/languages.js.map +1 -0
- package/dist/src/utils/media.d.ts +6 -0
- package/dist/src/utils/media.js +27 -0
- package/dist/src/utils/media.js.map +1 -0
- package/dist/src/utils/token.d.ts +13 -0
- package/dist/src/utils/token.js +59 -0
- package/dist/src/utils/token.js.map +1 -0
- package/dist/src/utils/validation.d.ts +1 -0
- package/dist/src/utils/validation.js +7 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/stories/audio-visualiser.stories.d.ts +39 -0
- package/dist/stories/audio-visualiser.stories.js +71 -0
- package/dist/stories/audio-visualiser.stories.js.map +1 -0
- package/dist/stories/corti-dictation.stories.d.ts +27 -0
- package/dist/stories/corti-dictation.stories.js +129 -0
- package/dist/stories/corti-dictation.stories.js.map +1 -0
- package/dist/stories/device-selector.stories.d.ts +18 -0
- package/dist/stories/device-selector.stories.js +84 -0
- package/dist/stories/device-selector.stories.js.map +1 -0
- package/dist/stories/language-selector.stories.d.ts +18 -0
- package/dist/stories/language-selector.stories.js +53 -0
- package/dist/stories/language-selector.stories.js.map +1 -0
- package/dist/stories/recording-button.stories.d.ts +27 -0
- package/dist/stories/recording-button.stories.js +90 -0
- package/dist/stories/recording-button.stories.js.map +1 -0
- package/dist/stories/settings-menu.stories.d.ts +23 -0
- package/dist/stories/settings-menu.stories.js +156 -0
- package/dist/stories/settings-menu.stories.js.map +1 -0
- package/dist/styles/ComponentStyles.js +6 -41
- package/dist/styles/ComponentStyles.js.map +1 -1
- package/dist/styles/audio-visualiser.d.ts +2 -0
- package/dist/styles/audio-visualiser.js +33 -0
- package/dist/styles/audio-visualiser.js.map +1 -0
- package/dist/styles/buttons.js +19 -25
- package/dist/styles/buttons.js.map +1 -1
- package/dist/styles/callout.js +7 -17
- package/dist/styles/callout.js.map +1 -1
- package/dist/styles/default-theme.d.ts +2 -0
- package/dist/styles/default-theme.js +14 -0
- package/dist/styles/default-theme.js.map +1 -0
- package/dist/styles/recording-button.d.ts +2 -0
- package/dist/styles/recording-button.js +8 -0
- package/dist/styles/recording-button.js.map +1 -0
- package/dist/styles/select.js +9 -9
- package/dist/styles/select.js.map +1 -1
- package/dist/styles/settings-menu.d.ts +2 -0
- package/dist/styles/settings-menu.js +34 -0
- package/dist/styles/settings-menu.js.map +1 -0
- package/dist/tsconfig.stories.tsbuildinfo +1 -0
- package/dist/types.d.ts +7 -8
- package/dist/types.js.map +1 -1
- package/dist/utils/auth.d.ts +9 -0
- package/dist/utils/auth.js +21 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/converters.d.ts +4 -0
- package/dist/utils/converters.js +8 -0
- package/dist/utils/converters.js.map +1 -0
- package/dist/utils/devices.d.ts +26 -0
- package/dist/utils/devices.js +53 -0
- package/dist/utils/devices.js.map +1 -0
- package/dist/utils/events.d.ts +44 -0
- package/dist/utils/events.js +88 -0
- package/dist/utils/events.js.map +1 -0
- package/dist/utils/languages.d.ts +7 -0
- package/dist/utils/languages.js +29 -0
- package/dist/utils/languages.js.map +1 -0
- package/dist/utils/media.d.ts +6 -0
- package/dist/utils/media.js +39 -0
- package/dist/utils/media.js.map +1 -0
- package/dist/utils/token.d.ts +13 -0
- package/dist/utils/token.js +59 -0
- package/dist/utils/token.js.map +1 -0
- package/dist/utils/validation.d.ts +1 -0
- package/dist/utils/validation.js +7 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +23 -50
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const LANGUAGES_SUPPORTED_EU = [
|
|
2
|
+
"en",
|
|
3
|
+
"en-GB",
|
|
4
|
+
"da",
|
|
5
|
+
"de",
|
|
6
|
+
"fr",
|
|
7
|
+
"sv",
|
|
8
|
+
"nl",
|
|
9
|
+
"no",
|
|
10
|
+
];
|
|
11
|
+
export const LANGUAGES_SUPPORTED_US = [
|
|
12
|
+
"en",
|
|
13
|
+
];
|
|
14
|
+
export const DEFAULT_DICTATION_CONFIG = {
|
|
15
|
+
automaticPunctuation: true,
|
|
16
|
+
primaryLanguage: "en",
|
|
17
|
+
spokenPunctuation: true,
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAwC;IACzE,IAAI;IACJ,OAAO;IACP,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;CACL,CAAC;AACF,MAAM,CAAC,MAAM,sBAAsB,GAAwC;IACzE,IAAI;CACL,CAAC;AACF,MAAM,CAAC,MAAM,wBAAwB,GAA2B;IAC9D,oBAAoB,EAAE,IAAI;IAC1B,eAAe,EAAE,IAAI;IACrB,iBAAiB,EAAE,IAAI;CACxB,CAAC","sourcesContent":["import type { Corti } from \"@corti/sdk\";\n\nexport const LANGUAGES_SUPPORTED_EU: Corti.TranscribeSupportedLanguage[] = [\n \"en\",\n \"en-GB\",\n \"da\",\n \"de\",\n \"fr\",\n \"sv\",\n \"nl\",\n \"no\",\n];\nexport const LANGUAGES_SUPPORTED_US: Corti.TranscribeSupportedLanguage[] = [\n \"en\",\n];\nexport const DEFAULT_DICTATION_CONFIG: Corti.TranscribeConfig = {\n automaticPunctuation: true,\n primaryLanguage: \"en\",\n spokenPunctuation: true,\n};\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Corti } from "@corti/sdk";
|
|
2
|
+
import { type CSSResultGroup, LitElement } from "lit";
|
|
3
|
+
import type { RecordingState } from "../types.js";
|
|
4
|
+
export declare const regionContext: {
|
|
5
|
+
__context__: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare const tenantNameContext: {
|
|
8
|
+
__context__: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
export declare const languagesContext: {
|
|
11
|
+
__context__: string[] | undefined;
|
|
12
|
+
};
|
|
13
|
+
export declare const devicesContext: {
|
|
14
|
+
__context__: MediaDeviceInfo[] | undefined;
|
|
15
|
+
};
|
|
16
|
+
export declare const selectedDeviceContext: {
|
|
17
|
+
__context__: MediaDeviceInfo | undefined;
|
|
18
|
+
};
|
|
19
|
+
export declare const recordingStateContext: {
|
|
20
|
+
__context__: RecordingState;
|
|
21
|
+
};
|
|
22
|
+
export declare const accessTokenContext: {
|
|
23
|
+
__context__: string | undefined;
|
|
24
|
+
};
|
|
25
|
+
export declare const dictationConfigContext: {
|
|
26
|
+
__context__: Corti.TranscribeConfig | undefined;
|
|
27
|
+
};
|
|
28
|
+
export declare const authConfigContext: {
|
|
29
|
+
__context__: Corti.BearerOptions | undefined;
|
|
30
|
+
};
|
|
31
|
+
export declare class DictationContext extends LitElement {
|
|
32
|
+
region?: string;
|
|
33
|
+
tenantName?: string;
|
|
34
|
+
recordingState: RecordingState;
|
|
35
|
+
private _accessToken?;
|
|
36
|
+
set accessToken(token: string | undefined);
|
|
37
|
+
get accessToken(): string | undefined;
|
|
38
|
+
private _authConfig?;
|
|
39
|
+
set authConfig(config: Corti.BearerOptions | undefined);
|
|
40
|
+
get authConfig(): Corti.BearerOptions | undefined;
|
|
41
|
+
dictationConfig?: Corti.TranscribeConfig;
|
|
42
|
+
languages?: string[];
|
|
43
|
+
devices?: MediaDeviceInfo[];
|
|
44
|
+
selectedDevice?: MediaDeviceInfo;
|
|
45
|
+
noWrapper: boolean;
|
|
46
|
+
static styles: CSSResultGroup;
|
|
47
|
+
constructor();
|
|
48
|
+
/**
|
|
49
|
+
* Sets the access token and parses region/tenant from it.
|
|
50
|
+
* @returns ServerConfig with environment, tenant, and accessToken
|
|
51
|
+
*/
|
|
52
|
+
setAccessToken(token: string | undefined): {
|
|
53
|
+
accessToken: string | undefined;
|
|
54
|
+
environment: undefined;
|
|
55
|
+
tenant: undefined;
|
|
56
|
+
} | {
|
|
57
|
+
accessToken: string;
|
|
58
|
+
environment: string | undefined;
|
|
59
|
+
tenant: string | undefined;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Sets the auth config and parses region/tenant from the initial token.
|
|
63
|
+
* @returns Promise with ServerConfig containing environment, tenant, and accessToken
|
|
64
|
+
*/
|
|
65
|
+
setAuthConfig(config?: Corti.BearerOptions): Promise<{
|
|
66
|
+
accessToken: string | undefined;
|
|
67
|
+
environment: undefined;
|
|
68
|
+
tenant: undefined;
|
|
69
|
+
} | {
|
|
70
|
+
accessToken: string;
|
|
71
|
+
environment: string | undefined;
|
|
72
|
+
tenant: string | undefined;
|
|
73
|
+
}>;
|
|
74
|
+
private _handleLanguageChanged;
|
|
75
|
+
private _handleDeviceChanged;
|
|
76
|
+
private _handleRecordingStateChanged;
|
|
77
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
78
|
+
}
|
|
79
|
+
declare global {
|
|
80
|
+
interface HTMLElementTagNameMap {
|
|
81
|
+
"dictation-context-provider": DictationContext;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { createContext, provide } from "@lit/context";
|
|
8
|
+
import { html, LitElement } from "lit";
|
|
9
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
10
|
+
import ComponentStyles from "../styles/ComponentStyles.js";
|
|
11
|
+
import DefaultThemeStyles from "../styles/default-theme.js";
|
|
12
|
+
import { getInitialToken } from "../utils/auth.js";
|
|
13
|
+
import { commaSeparatedConverter } from "../utils/converters.js";
|
|
14
|
+
import { errorEvent } from "../utils/events.js";
|
|
15
|
+
import { decodeToken } from "../utils/token.js";
|
|
16
|
+
export const regionContext = createContext("region");
|
|
17
|
+
export const tenantNameContext = createContext("tenantName");
|
|
18
|
+
export const languagesContext = createContext("languages");
|
|
19
|
+
export const devicesContext = createContext("devices");
|
|
20
|
+
export const selectedDeviceContext = createContext("selectedDevice");
|
|
21
|
+
export const recordingStateContext = createContext("recordingState");
|
|
22
|
+
export const accessTokenContext = createContext("accessToken");
|
|
23
|
+
export const dictationConfigContext = createContext("dictationConfig");
|
|
24
|
+
export const authConfigContext = createContext("authConfig");
|
|
25
|
+
let DictationContext = class DictationContext extends LitElement {
|
|
26
|
+
set accessToken(token) {
|
|
27
|
+
this.setAccessToken(token);
|
|
28
|
+
}
|
|
29
|
+
get accessToken() {
|
|
30
|
+
return this._accessToken;
|
|
31
|
+
}
|
|
32
|
+
set authConfig(config) {
|
|
33
|
+
this.setAuthConfig(config);
|
|
34
|
+
}
|
|
35
|
+
get authConfig() {
|
|
36
|
+
return this._authConfig;
|
|
37
|
+
}
|
|
38
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
39
|
+
// Lifecycle
|
|
40
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
this.recordingState = "stopped";
|
|
44
|
+
this.noWrapper = false;
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
+
// Private event handlers
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
this._handleLanguageChanged = (e) => {
|
|
49
|
+
const event = e;
|
|
50
|
+
this.languages = event.detail.languages;
|
|
51
|
+
this.dictationConfig = {
|
|
52
|
+
...this.dictationConfig,
|
|
53
|
+
primaryLanguage: event.detail.selectedLanguage,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
this._handleDeviceChanged = (e) => {
|
|
57
|
+
const event = e;
|
|
58
|
+
this.devices = event.detail.devices;
|
|
59
|
+
this.selectedDevice = event.detail.selectedDevice;
|
|
60
|
+
};
|
|
61
|
+
this._handleRecordingStateChanged = (e) => {
|
|
62
|
+
const event = e;
|
|
63
|
+
this.recordingState = event.detail.state;
|
|
64
|
+
};
|
|
65
|
+
this.addEventListener("languages-changed", this._handleLanguageChanged);
|
|
66
|
+
this.addEventListener("recording-devices-changed", this._handleDeviceChanged);
|
|
67
|
+
this.addEventListener("recording-state-changed", this._handleRecordingStateChanged);
|
|
68
|
+
}
|
|
69
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
// Public methods
|
|
71
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* Sets the access token and parses region/tenant from it.
|
|
74
|
+
* @returns ServerConfig with environment, tenant, and accessToken
|
|
75
|
+
*/
|
|
76
|
+
setAccessToken(token) {
|
|
77
|
+
this._accessToken = token;
|
|
78
|
+
this.region = undefined;
|
|
79
|
+
this.tenantName = undefined;
|
|
80
|
+
if (!token) {
|
|
81
|
+
return { accessToken: token, environment: undefined, tenant: undefined };
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const decoded = decodeToken(token);
|
|
85
|
+
this.region = decoded?.environment;
|
|
86
|
+
this.tenantName = decoded?.tenant;
|
|
87
|
+
return {
|
|
88
|
+
accessToken: token,
|
|
89
|
+
environment: decoded?.environment,
|
|
90
|
+
tenant: decoded?.tenant,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
this.dispatchEvent(errorEvent(error));
|
|
95
|
+
}
|
|
96
|
+
return { accessToken: token, environment: undefined, tenant: undefined };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Sets the auth config and parses region/tenant from the initial token.
|
|
100
|
+
* @returns Promise with ServerConfig containing environment, tenant, and accessToken
|
|
101
|
+
*/
|
|
102
|
+
async setAuthConfig(config) {
|
|
103
|
+
this._authConfig = config;
|
|
104
|
+
if (!config) {
|
|
105
|
+
return { accessToken: undefined, environment: undefined, tenant: undefined };
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const { accessToken } = await getInitialToken(config);
|
|
109
|
+
return this.setAccessToken(accessToken);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
this.dispatchEvent(errorEvent(error));
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
accessToken: undefined,
|
|
116
|
+
environment: undefined,
|
|
117
|
+
tenant: undefined,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
121
|
+
// Render
|
|
122
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
123
|
+
render() {
|
|
124
|
+
if (this.noWrapper) {
|
|
125
|
+
return html `<slot></slot>`;
|
|
126
|
+
}
|
|
127
|
+
return html `<div class="wrapper">
|
|
128
|
+
<slot></slot>
|
|
129
|
+
</div>`;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
133
|
+
// Static
|
|
134
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
135
|
+
DictationContext.styles = [DefaultThemeStyles, ComponentStyles];
|
|
136
|
+
__decorate([
|
|
137
|
+
provide({ context: regionContext }),
|
|
138
|
+
state()
|
|
139
|
+
], DictationContext.prototype, "region", void 0);
|
|
140
|
+
__decorate([
|
|
141
|
+
provide({ context: tenantNameContext }),
|
|
142
|
+
state()
|
|
143
|
+
], DictationContext.prototype, "tenantName", void 0);
|
|
144
|
+
__decorate([
|
|
145
|
+
provide({ context: recordingStateContext }),
|
|
146
|
+
state()
|
|
147
|
+
], DictationContext.prototype, "recordingState", void 0);
|
|
148
|
+
__decorate([
|
|
149
|
+
provide({ context: accessTokenContext }),
|
|
150
|
+
state()
|
|
151
|
+
], DictationContext.prototype, "_accessToken", void 0);
|
|
152
|
+
__decorate([
|
|
153
|
+
property({ type: String })
|
|
154
|
+
], DictationContext.prototype, "accessToken", null);
|
|
155
|
+
__decorate([
|
|
156
|
+
provide({ context: authConfigContext }),
|
|
157
|
+
state()
|
|
158
|
+
], DictationContext.prototype, "_authConfig", void 0);
|
|
159
|
+
__decorate([
|
|
160
|
+
property({ attribute: false, type: Object })
|
|
161
|
+
], DictationContext.prototype, "authConfig", null);
|
|
162
|
+
__decorate([
|
|
163
|
+
provide({ context: dictationConfigContext }),
|
|
164
|
+
property({ attribute: false, type: Object })
|
|
165
|
+
], DictationContext.prototype, "dictationConfig", void 0);
|
|
166
|
+
__decorate([
|
|
167
|
+
provide({ context: languagesContext }),
|
|
168
|
+
property({
|
|
169
|
+
converter: commaSeparatedConverter,
|
|
170
|
+
type: Array,
|
|
171
|
+
})
|
|
172
|
+
], DictationContext.prototype, "languages", void 0);
|
|
173
|
+
__decorate([
|
|
174
|
+
provide({ context: devicesContext }),
|
|
175
|
+
property({ attribute: false, type: Array })
|
|
176
|
+
], DictationContext.prototype, "devices", void 0);
|
|
177
|
+
__decorate([
|
|
178
|
+
provide({ context: selectedDeviceContext }),
|
|
179
|
+
property({ attribute: false, type: Object })
|
|
180
|
+
], DictationContext.prototype, "selectedDevice", void 0);
|
|
181
|
+
__decorate([
|
|
182
|
+
property({ type: Boolean })
|
|
183
|
+
], DictationContext.prototype, "noWrapper", void 0);
|
|
184
|
+
DictationContext = __decorate([
|
|
185
|
+
customElement("dictation-context-provider")
|
|
186
|
+
], DictationContext);
|
|
187
|
+
export { DictationContext };
|
|
188
|
+
//# sourceMappingURL=dictation-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictation-context.js","sourceRoot":"","sources":["../../../src/contexts/dictation-context.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Corti } from \"@corti/sdk\";\nimport { createContext, provide } from \"@lit/context\";\nimport { type CSSResultGroup, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport ComponentStyles from \"../styles/ComponentStyles.js\";\nimport DefaultThemeStyles from \"../styles/default-theme.js\";\nimport type { RecordingState } from \"../types.js\";\nimport { getInitialToken } from \"../utils/auth.js\";\nimport { commaSeparatedConverter } from \"../utils/converters.js\";\nimport { errorEvent } from \"../utils/events.js\";\nimport { decodeToken } from \"../utils/token.js\";\n\nexport const regionContext = createContext<string | undefined>(\"region\");\nexport const tenantNameContext = createContext<string | undefined>(\n \"tenantName\",\n);\nexport const languagesContext = createContext<string[] | undefined>(\n \"languages\",\n);\nexport const devicesContext = createContext<MediaDeviceInfo[] | undefined>(\n \"devices\",\n);\nexport const selectedDeviceContext = createContext<MediaDeviceInfo | undefined>(\n \"selectedDevice\",\n);\nexport const recordingStateContext =\n createContext<RecordingState>(\"recordingState\");\nexport const accessTokenContext = createContext<string | undefined>(\n \"accessToken\",\n);\nexport const dictationConfigContext = createContext<\n Corti.TranscribeConfig | undefined\n>(\"dictationConfig\");\nexport const authConfigContext = createContext<Corti.BearerOptions | undefined>(\n \"authConfig\",\n);\n\n@customElement(\"dictation-context-provider\")\nexport class DictationContext extends LitElement {\n // ─────────────────────────────────────────────────────────────────────────────\n // Context state\n // ─────────────────────────────────────────────────────────────────────────────\n\n @provide({ context: regionContext })\n @state()\n region?: string;\n\n @provide({ context: tenantNameContext })\n @state()\n tenantName?: string;\n\n @provide({ context: recordingStateContext })\n @state()\n recordingState: RecordingState = \"stopped\";\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Properties\n // ─────────────────────────────────────────────────────────────────────────────\n\n @provide({ context: accessTokenContext })\n @state()\n private _accessToken?: string;\n\n @property({ type: String })\n set accessToken(token: string | undefined) {\n this.setAccessToken(token);\n }\n\n get accessToken(): string | undefined {\n return this._accessToken;\n }\n\n @provide({ context: authConfigContext })\n @state()\n private _authConfig?: Corti.BearerOptions;\n\n @property({ attribute: false, type: Object })\n set authConfig(config: Corti.BearerOptions | undefined) {\n this.setAuthConfig(config);\n }\n\n get authConfig(): Corti.BearerOptions | undefined {\n return this._authConfig;\n }\n\n @provide({ context: dictationConfigContext })\n @property({ attribute: false, type: Object })\n dictationConfig?: Corti.TranscribeConfig;\n\n @provide({ context: languagesContext })\n @property({\n converter: commaSeparatedConverter,\n type: Array,\n })\n languages?: string[];\n\n @provide({ context: devicesContext })\n @property({ attribute: false, type: Array })\n devices?: MediaDeviceInfo[];\n\n @provide({ context: selectedDeviceContext })\n @property({ attribute: false, type: Object })\n selectedDevice?: MediaDeviceInfo;\n\n @property({ type: Boolean })\n noWrapper: boolean = false;\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Static\n // ─────────────────────────────────────────────────────────────────────────────\n\n static styles: CSSResultGroup = [DefaultThemeStyles, ComponentStyles];\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n super();\n this.addEventListener(\"languages-changed\", this._handleLanguageChanged);\n this.addEventListener(\n \"recording-devices-changed\",\n this._handleDeviceChanged,\n );\n this.addEventListener(\n \"recording-state-changed\",\n this._handleRecordingStateChanged,\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Public methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Sets the access token and parses region/tenant from it.\n * @returns ServerConfig with environment, tenant, and accessToken\n */\n public setAccessToken(token: string | undefined) {\n this._accessToken = token;\n this.region = undefined;\n this.tenantName = undefined;\n\n if (!token) {\n return { accessToken: token, environment: undefined, tenant: undefined };\n }\n\n try {\n const decoded = decodeToken(token);\n\n this.region = decoded?.environment;\n this.tenantName = decoded?.tenant;\n\n return {\n accessToken: token,\n environment: decoded?.environment,\n tenant: decoded?.tenant,\n };\n } catch (error) {\n this.dispatchEvent(errorEvent(error));\n }\n\n return { accessToken: token, environment: undefined, tenant: undefined };\n }\n\n /**\n * Sets the auth config and parses region/tenant from the initial token.\n * @returns Promise with ServerConfig containing environment, tenant, and accessToken\n */\n public async setAuthConfig(config?: Corti.BearerOptions) {\n this._authConfig = config;\n\n if (!config) {\n return { accessToken: undefined, environment: undefined, tenant: undefined };\n }\n\n try {\n const { accessToken } = await getInitialToken(config);\n\n return this.setAccessToken(accessToken);\n } catch (error) {\n this.dispatchEvent(errorEvent(error));\n }\n\n return {\n accessToken: undefined,\n environment: undefined,\n tenant: undefined,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private event handlers\n // ─────────────────────────────────────────────────────────────────────────────\n\n private _handleLanguageChanged = (e: Event) => {\n const event = e as CustomEvent;\n\n this.languages = event.detail.languages;\n this.dictationConfig = {\n ...this.dictationConfig,\n primaryLanguage: event.detail.selectedLanguage,\n };\n };\n\n private _handleDeviceChanged = (e: Event) => {\n const event = e as CustomEvent;\n\n this.devices = event.detail.devices;\n this.selectedDevice = event.detail.selectedDevice;\n };\n\n private _handleRecordingStateChanged = (e: Event) => {\n const event = e as CustomEvent;\n\n this.recordingState = event.detail.state;\n };\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Render\n // ─────────────────────────────────────────────────────────────────────────────\n\n render() {\n if (this.noWrapper) {\n return html`<slot></slot>`;\n }\n\n return html`<div class=\"wrapper\">\n <slot></slot>\n </div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"dictation-context-provider\": DictationContext;\n }\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Corti } from "@corti/sdk";
|
|
2
|
+
import type { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
|
+
interface DictationControllerHost extends ReactiveControllerHost {
|
|
4
|
+
_accessToken?: string;
|
|
5
|
+
_authConfig?: Corti.BearerOptions;
|
|
6
|
+
_region?: string;
|
|
7
|
+
_tenantName?: string;
|
|
8
|
+
}
|
|
9
|
+
export type TranscribeMessage = Corti.TranscribeConfigStatusMessage | Corti.TranscribeUsageMessage | Corti.TranscribeEndedMessage | Corti.TranscribeErrorMessage | Corti.TranscribeTranscriptMessage | Corti.TranscribeCommandMessage | Corti.TranscribeFlushedMessage;
|
|
10
|
+
interface WebSocketCallbacks {
|
|
11
|
+
onMessage?: (message: TranscribeMessage) => void;
|
|
12
|
+
onError?: (error: Error) => void;
|
|
13
|
+
onClose?: (event: unknown) => void;
|
|
14
|
+
onNetworkActivity?: (direction: "sent" | "received", data: unknown) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare class DictationController implements ReactiveController {
|
|
17
|
+
host: DictationControllerHost;
|
|
18
|
+
private _cortiClient;
|
|
19
|
+
private _webSocket;
|
|
20
|
+
private _closeTimeout?;
|
|
21
|
+
private _onNetworkActivity?;
|
|
22
|
+
constructor(host: DictationControllerHost);
|
|
23
|
+
hostDisconnected(): void;
|
|
24
|
+
connect(mediaRecorder: MediaRecorder | null, dictationConfig?: Corti.TranscribeConfig, callbacks?: WebSocketCallbacks): Promise<void>;
|
|
25
|
+
private setupWebSocketHandlers;
|
|
26
|
+
private setupMediaRecorder;
|
|
27
|
+
disconnect(onClose?: (event: unknown) => void): Promise<void>;
|
|
28
|
+
cleanup(): void;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { CortiClient } from "@corti/sdk";
|
|
2
|
+
import { DEFAULT_DICTATION_CONFIG } from "../constants.js";
|
|
3
|
+
export class DictationController {
|
|
4
|
+
constructor(host) {
|
|
5
|
+
this._cortiClient = null;
|
|
6
|
+
this._webSocket = null;
|
|
7
|
+
this.host = host;
|
|
8
|
+
host.addController(this);
|
|
9
|
+
}
|
|
10
|
+
hostDisconnected() {
|
|
11
|
+
this.cleanup();
|
|
12
|
+
}
|
|
13
|
+
async connect(mediaRecorder, dictationConfig = DEFAULT_DICTATION_CONFIG, callbacks = {}) {
|
|
14
|
+
if (!this.host._authConfig && !this.host._accessToken) {
|
|
15
|
+
throw new Error("Auth configuration or access token is required to connect");
|
|
16
|
+
}
|
|
17
|
+
if (!mediaRecorder) {
|
|
18
|
+
throw new Error("MediaRecorder is required to connect");
|
|
19
|
+
}
|
|
20
|
+
if (this._webSocket?.readyState === WebSocket.OPEN) {
|
|
21
|
+
throw new Error("Already connected. Disconnect before reconnecting.");
|
|
22
|
+
}
|
|
23
|
+
// Use authConfig if available, otherwise create one from accessToken
|
|
24
|
+
const auth = this.host._authConfig || {
|
|
25
|
+
accessToken: this.host._accessToken || "",
|
|
26
|
+
refreshAccessToken: () => ({
|
|
27
|
+
accessToken: this.host._accessToken || "",
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
this._cortiClient = new CortiClient({
|
|
31
|
+
auth,
|
|
32
|
+
environment: this.host._region,
|
|
33
|
+
tenantName: this.host._tenantName,
|
|
34
|
+
});
|
|
35
|
+
this._webSocket = await this._cortiClient.transcribe.connect({
|
|
36
|
+
configuration: dictationConfig,
|
|
37
|
+
});
|
|
38
|
+
this._onNetworkActivity = callbacks.onNetworkActivity;
|
|
39
|
+
this.setupMediaRecorder(mediaRecorder);
|
|
40
|
+
this.setupWebSocketHandlers(callbacks);
|
|
41
|
+
}
|
|
42
|
+
setupWebSocketHandlers(callbacks) {
|
|
43
|
+
if (!this._webSocket) {
|
|
44
|
+
throw new Error("WebSocket not initialized");
|
|
45
|
+
}
|
|
46
|
+
this._webSocket.on("message", (message) => {
|
|
47
|
+
this._onNetworkActivity?.("received", message);
|
|
48
|
+
if (callbacks.onMessage) {
|
|
49
|
+
callbacks.onMessage(message);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
this._webSocket.on("error", (event) => {
|
|
53
|
+
if (callbacks.onError) {
|
|
54
|
+
callbacks.onError(event);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
this._webSocket.on("close", (event) => {
|
|
58
|
+
if (callbacks.onClose) {
|
|
59
|
+
callbacks.onClose(event);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
setupMediaRecorder(mediaRecorder) {
|
|
64
|
+
mediaRecorder.ondataavailable = (event) => {
|
|
65
|
+
this._webSocket?.sendAudio(event.data);
|
|
66
|
+
this._onNetworkActivity?.("sent", {
|
|
67
|
+
size: event.data.size,
|
|
68
|
+
type: "audio",
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async disconnect(onClose) {
|
|
73
|
+
await new Promise((resolve, reject) => {
|
|
74
|
+
if (!this._webSocket || this._webSocket.readyState !== WebSocket.OPEN) {
|
|
75
|
+
resolve();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this._webSocket.on("close", (event) => {
|
|
79
|
+
if (this._closeTimeout) {
|
|
80
|
+
clearTimeout(this._closeTimeout);
|
|
81
|
+
this._closeTimeout = undefined;
|
|
82
|
+
}
|
|
83
|
+
if (onClose) {
|
|
84
|
+
onClose(event);
|
|
85
|
+
}
|
|
86
|
+
resolve();
|
|
87
|
+
});
|
|
88
|
+
this._webSocket.sendEnd({ type: "end" });
|
|
89
|
+
this._onNetworkActivity?.("sent", { type: "end" });
|
|
90
|
+
this._closeTimeout = window.setTimeout(() => {
|
|
91
|
+
// Reject the promise before closing the web socket, so the promise rejects before close event fires
|
|
92
|
+
reject(new Error("WebSocket close timeout"));
|
|
93
|
+
if (this._webSocket?.readyState === WebSocket.OPEN) {
|
|
94
|
+
this._webSocket.close();
|
|
95
|
+
}
|
|
96
|
+
}, 10000);
|
|
97
|
+
});
|
|
98
|
+
this.cleanup();
|
|
99
|
+
}
|
|
100
|
+
cleanup() {
|
|
101
|
+
if (this._closeTimeout) {
|
|
102
|
+
clearTimeout(this._closeTimeout);
|
|
103
|
+
this._closeTimeout = undefined;
|
|
104
|
+
}
|
|
105
|
+
if (this._webSocket?.readyState === WebSocket.OPEN) {
|
|
106
|
+
this._webSocket.close();
|
|
107
|
+
}
|
|
108
|
+
this._webSocket = null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=DictationController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DictationController.js","sourceRoot":"","sources":["../../../src/controllers/DictationController.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Corti, CortiClient } from \"@corti/sdk\";\nimport type { ReactiveController, ReactiveControllerHost } from \"lit\";\nimport { DEFAULT_DICTATION_CONFIG } from \"../constants.js\";\n\ntype TranscribeSocket = Awaited<\n ReturnType<CortiClient[\"transcribe\"][\"connect\"]>\n>;\n\ninterface DictationControllerHost extends ReactiveControllerHost {\n _accessToken?: string;\n _authConfig?: Corti.BearerOptions;\n _region?: string;\n _tenantName?: string;\n}\n\nexport type TranscribeMessage =\n | Corti.TranscribeConfigStatusMessage\n | Corti.TranscribeUsageMessage\n | Corti.TranscribeEndedMessage\n | Corti.TranscribeErrorMessage\n | Corti.TranscribeTranscriptMessage\n | Corti.TranscribeCommandMessage\n | Corti.TranscribeFlushedMessage;\n\ninterface WebSocketCallbacks {\n onMessage?: (message: TranscribeMessage) => void;\n onError?: (error: Error) => void;\n onClose?: (event: unknown) => void;\n onNetworkActivity?: (direction: \"sent\" | \"received\", data: unknown) => void;\n}\n\nexport class DictationController implements ReactiveController {\n host: DictationControllerHost;\n\n private _cortiClient: CortiClient | null = null;\n private _webSocket: TranscribeSocket | null = null;\n private _closeTimeout?: number;\n private _onNetworkActivity?: WebSocketCallbacks[\"onNetworkActivity\"];\n\n constructor(host: DictationControllerHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostDisconnected(): void {\n this.cleanup();\n }\n\n async connect(\n mediaRecorder: MediaRecorder | null,\n dictationConfig: Corti.TranscribeConfig = DEFAULT_DICTATION_CONFIG,\n callbacks: WebSocketCallbacks = {},\n ): Promise<void> {\n if (!this.host._authConfig && !this.host._accessToken) {\n throw new Error(\n \"Auth configuration or access token is required to connect\",\n );\n }\n\n if (!mediaRecorder) {\n throw new Error(\"MediaRecorder is required to connect\");\n }\n\n if (this._webSocket?.readyState === WebSocket.OPEN) {\n throw new Error(\"Already connected. Disconnect before reconnecting.\");\n }\n\n // Use authConfig if available, otherwise create one from accessToken\n const auth: Corti.BearerOptions = this.host._authConfig || {\n accessToken: this.host._accessToken || \"\",\n refreshAccessToken: () => ({\n accessToken: this.host._accessToken || \"\",\n }),\n };\n\n this._cortiClient = new CortiClient({\n auth,\n environment: this.host._region,\n tenantName: this.host._tenantName,\n });\n\n this._webSocket = await this._cortiClient.transcribe.connect({\n configuration: dictationConfig,\n });\n this._onNetworkActivity = callbacks.onNetworkActivity;\n this.setupMediaRecorder(mediaRecorder);\n this.setupWebSocketHandlers(callbacks);\n }\n\n private setupWebSocketHandlers(callbacks: WebSocketCallbacks): void {\n if (!this._webSocket) {\n throw new Error(\"WebSocket not initialized\");\n }\n\n this._webSocket.on(\"message\", (message) => {\n this._onNetworkActivity?.(\"received\", message);\n\n if (callbacks.onMessage) {\n callbacks.onMessage(message);\n }\n });\n\n this._webSocket.on(\"error\", (event) => {\n if (callbacks.onError) {\n callbacks.onError(event);\n }\n });\n\n this._webSocket.on(\"close\", (event) => {\n if (callbacks.onClose) {\n callbacks.onClose(event);\n }\n });\n }\n\n private setupMediaRecorder(mediaRecorder: MediaRecorder): void {\n mediaRecorder.ondataavailable = (event) => {\n this._webSocket?.sendAudio(event.data);\n this._onNetworkActivity?.(\"sent\", {\n size: event.data.size,\n type: \"audio\",\n });\n };\n }\n\n async disconnect(onClose?: (event: unknown) => void): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n if (!this._webSocket || this._webSocket.readyState !== WebSocket.OPEN) {\n resolve();\n return;\n }\n\n this._webSocket.on(\"close\", (event) => {\n if (this._closeTimeout) {\n clearTimeout(this._closeTimeout);\n this._closeTimeout = undefined;\n }\n\n if (onClose) {\n onClose(event);\n }\n\n resolve();\n });\n\n this._webSocket.sendEnd({ type: \"end\" });\n this._onNetworkActivity?.(\"sent\", { type: \"end\" });\n\n this._closeTimeout = window.setTimeout(() => {\n // Reject the promise before closing the web socket, so the promise rejects before close event fires\n reject(new Error(\"WebSocket close timeout\"));\n\n if (this._webSocket?.readyState === WebSocket.OPEN) {\n this._webSocket.close();\n }\n }, 10000);\n });\n\n this.cleanup();\n }\n\n cleanup(): void {\n if (this._closeTimeout) {\n clearTimeout(this._closeTimeout);\n this._closeTimeout = undefined;\n }\n\n if (this._webSocket?.readyState === WebSocket.OPEN) {\n this._webSocket.close();\n }\n\n this._webSocket = null;\n }\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactiveController, ReactiveControllerHost } from "lit";
|
|
2
|
+
interface MediaControllerHost extends ReactiveControllerHost {
|
|
3
|
+
_selectedDevice?: MediaDeviceInfo;
|
|
4
|
+
}
|
|
5
|
+
export declare class MediaController implements ReactiveController {
|
|
6
|
+
host: MediaControllerHost;
|
|
7
|
+
private _mediaStream;
|
|
8
|
+
private _audioContext;
|
|
9
|
+
private _analyser;
|
|
10
|
+
private _mediaRecorder;
|
|
11
|
+
private _visualiserInterval?;
|
|
12
|
+
private _audioLevel;
|
|
13
|
+
private _onTrackEnded?;
|
|
14
|
+
private _onAudioLevelChange?;
|
|
15
|
+
constructor(host: MediaControllerHost);
|
|
16
|
+
hostDisconnected(): void;
|
|
17
|
+
initialize(onTrackEnded?: () => void): Promise<void>;
|
|
18
|
+
getAudioLevel(): number;
|
|
19
|
+
startAudioLevelMonitoring(onAudioLevelChange?: (level: number) => void): void;
|
|
20
|
+
stopAudioLevelMonitoring(): void;
|
|
21
|
+
cleanup(): Promise<void>;
|
|
22
|
+
get mediaRecorder(): MediaRecorder | null;
|
|
23
|
+
get audioLevel(): number;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { calculateAudioLevel, createAudioAnalyzer, getMediaStream, } from "../utils/media.js";
|
|
2
|
+
export class MediaController {
|
|
3
|
+
constructor(host) {
|
|
4
|
+
this._mediaStream = null;
|
|
5
|
+
this._audioContext = null;
|
|
6
|
+
this._analyser = null;
|
|
7
|
+
this._mediaRecorder = null;
|
|
8
|
+
this._audioLevel = 0;
|
|
9
|
+
this.host = host;
|
|
10
|
+
host.addController(this);
|
|
11
|
+
}
|
|
12
|
+
hostDisconnected() {
|
|
13
|
+
this.cleanup();
|
|
14
|
+
}
|
|
15
|
+
async initialize(onTrackEnded) {
|
|
16
|
+
await this.cleanup();
|
|
17
|
+
this._onTrackEnded = onTrackEnded;
|
|
18
|
+
this._mediaStream = await getMediaStream(this.host._selectedDevice?.deviceId);
|
|
19
|
+
this._mediaStream.getTracks().forEach((track) => {
|
|
20
|
+
track.addEventListener("ended", () => {
|
|
21
|
+
if (this._onTrackEnded) {
|
|
22
|
+
this._onTrackEnded();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
const { audioContext, analyser } = createAudioAnalyzer(this._mediaStream);
|
|
27
|
+
this._audioContext = audioContext;
|
|
28
|
+
this._analyser = analyser;
|
|
29
|
+
this._mediaRecorder = new MediaRecorder(this._mediaStream);
|
|
30
|
+
}
|
|
31
|
+
getAudioLevel() {
|
|
32
|
+
return this._analyser ? calculateAudioLevel(this._analyser) : 0;
|
|
33
|
+
}
|
|
34
|
+
startAudioLevelMonitoring(onAudioLevelChange) {
|
|
35
|
+
this.stopAudioLevelMonitoring();
|
|
36
|
+
this._onAudioLevelChange = onAudioLevelChange;
|
|
37
|
+
this._visualiserInterval = window.setInterval(() => {
|
|
38
|
+
this._audioLevel = this.getAudioLevel() * 3;
|
|
39
|
+
this.host.requestUpdate();
|
|
40
|
+
if (this._onAudioLevelChange) {
|
|
41
|
+
this._onAudioLevelChange(this._audioLevel);
|
|
42
|
+
}
|
|
43
|
+
}, 150);
|
|
44
|
+
}
|
|
45
|
+
stopAudioLevelMonitoring() {
|
|
46
|
+
if (this._visualiserInterval) {
|
|
47
|
+
clearInterval(this._visualiserInterval);
|
|
48
|
+
this._visualiserInterval = undefined;
|
|
49
|
+
}
|
|
50
|
+
this._audioLevel = 0;
|
|
51
|
+
this.host.requestUpdate();
|
|
52
|
+
if (this._onAudioLevelChange) {
|
|
53
|
+
this._onAudioLevelChange(this._audioLevel);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async cleanup() {
|
|
57
|
+
this.stopAudioLevelMonitoring();
|
|
58
|
+
if (this._mediaRecorder?.state === "recording") {
|
|
59
|
+
this._mediaRecorder.stop();
|
|
60
|
+
}
|
|
61
|
+
if (this._mediaStream) {
|
|
62
|
+
this._mediaStream.getTracks().forEach((track) => {
|
|
63
|
+
track.stop();
|
|
64
|
+
});
|
|
65
|
+
this._mediaStream = null;
|
|
66
|
+
}
|
|
67
|
+
if (this._audioContext && this._audioContext.state !== "closed") {
|
|
68
|
+
await this._audioContext.close();
|
|
69
|
+
}
|
|
70
|
+
this._audioContext = null;
|
|
71
|
+
this._analyser = null;
|
|
72
|
+
this._mediaRecorder = null;
|
|
73
|
+
this._onTrackEnded = undefined;
|
|
74
|
+
this._onAudioLevelChange = undefined;
|
|
75
|
+
}
|
|
76
|
+
get mediaRecorder() {
|
|
77
|
+
return this._mediaRecorder;
|
|
78
|
+
}
|
|
79
|
+
get audioLevel() {
|
|
80
|
+
return this._audioLevel;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=MediaController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaController.js","sourceRoot":"","sources":["../../../src/controllers/MediaController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from \"lit\";\nimport {\n calculateAudioLevel,\n createAudioAnalyzer,\n getMediaStream,\n} from \"../utils/media.js\";\n\ninterface MediaControllerHost extends ReactiveControllerHost {\n _selectedDevice?: MediaDeviceInfo;\n}\n\nexport class MediaController implements ReactiveController {\n host: MediaControllerHost;\n\n private _mediaStream: MediaStream | null = null;\n private _audioContext: AudioContext | null = null;\n private _analyser: AnalyserNode | null = null;\n private _mediaRecorder: MediaRecorder | null = null;\n private _visualiserInterval?: number;\n private _audioLevel: number = 0;\n private _onTrackEnded?: () => void;\n private _onAudioLevelChange?: (level: number) => void;\n\n constructor(host: MediaControllerHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostDisconnected(): void {\n this.cleanup();\n }\n\n async initialize(onTrackEnded?: () => void): Promise<void> {\n await this.cleanup();\n\n this._onTrackEnded = onTrackEnded;\n this._mediaStream = await getMediaStream(\n this.host._selectedDevice?.deviceId,\n );\n\n this._mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.addEventListener(\"ended\", () => {\n if (this._onTrackEnded) {\n this._onTrackEnded();\n }\n });\n });\n\n const { audioContext, analyser } = createAudioAnalyzer(this._mediaStream);\n\n this._audioContext = audioContext;\n this._analyser = analyser;\n\n this._mediaRecorder = new MediaRecorder(this._mediaStream);\n }\n\n getAudioLevel(): number {\n return this._analyser ? calculateAudioLevel(this._analyser) : 0;\n }\n\n startAudioLevelMonitoring(onAudioLevelChange?: (level: number) => void): void {\n this.stopAudioLevelMonitoring();\n\n this._onAudioLevelChange = onAudioLevelChange;\n\n this._visualiserInterval = window.setInterval(() => {\n this._audioLevel = this.getAudioLevel() * 3;\n this.host.requestUpdate();\n \n if (this._onAudioLevelChange) {\n this._onAudioLevelChange(this._audioLevel);\n }\n }, 150);\n }\n\n stopAudioLevelMonitoring(): void {\n if (this._visualiserInterval) {\n clearInterval(this._visualiserInterval);\n this._visualiserInterval = undefined;\n }\n\n this._audioLevel = 0;\n this.host.requestUpdate();\n \n if (this._onAudioLevelChange) {\n this._onAudioLevelChange(this._audioLevel);\n }\n }\n\n async cleanup(): Promise<void> {\n this.stopAudioLevelMonitoring();\n\n if (this._mediaRecorder?.state === \"recording\") {\n this._mediaRecorder.stop();\n }\n\n if (this._mediaStream) {\n this._mediaStream.getTracks().forEach((track) => {\n track.stop();\n });\n this._mediaStream = null;\n }\n\n if (this._audioContext && this._audioContext.state !== \"closed\") {\n await this._audioContext.close();\n }\n\n this._audioContext = null;\n\n this._analyser = null;\n this._mediaRecorder = null;\n this._onTrackEnded = undefined;\n this._onAudioLevelChange = undefined;\n }\n\n get mediaRecorder(): MediaRecorder | null {\n return this._mediaRecorder;\n }\n\n get audioLevel(): number {\n return this._audioLevel;\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class IconMicOn extends LitElement {
|
|
3
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
4
|
+
}
|
|
5
|
+
export declare class IconMicOff extends LitElement {
|
|
6
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
7
|
+
}
|
|
8
|
+
export declare class IconRecording extends LitElement {
|
|
9
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
10
|
+
}
|
|
11
|
+
export declare class IconSettings extends LitElement {
|
|
12
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
13
|
+
}
|
|
14
|
+
export declare class IconLoadingSpinner extends LitElement {
|
|
15
|
+
static styles: import("lit").CSSResult;
|
|
16
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
17
|
+
}
|