@corti/dictation-web 0.1.5 → 0.1.7

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.
@@ -1,21 +1,21 @@
1
- import { getAudioDevices } from './utils.js';
1
+ import { getAudioDevices, getMediaStream } from './utils.js';
2
2
  import { AudioService } from './audioService.js';
3
3
  import { DictationService } from './DictationService.js';
4
4
  export class RecorderManager extends EventTarget {
5
5
  constructor() {
6
- super(...arguments);
6
+ super();
7
7
  this.devices = [];
8
- this.selectedDevice = '';
9
8
  this.recordingState = 'stopped';
10
9
  this._mediaStream = null;
11
10
  this._audioService = null;
12
11
  this._dictationService = null;
12
+ navigator.mediaDevices.addEventListener('devicechange', this.handleDevicesChange.bind(this));
13
13
  }
14
14
  async initialize() {
15
15
  const deviceResponse = await getAudioDevices();
16
16
  this.devices = deviceResponse.devices;
17
- this.selectedDevice = deviceResponse.defaultDeviceId || '';
18
- return deviceResponse;
17
+ this.selectedDevice = deviceResponse.defaultDevice;
18
+ return { devices: this.devices, selectedDevice: this.selectedDevice };
19
19
  }
20
20
  dispatchCustomEvent(eventName, detail) {
21
21
  this.dispatchEvent(new CustomEvent(eventName, {
@@ -24,34 +24,81 @@ export class RecorderManager extends EventTarget {
24
24
  composed: true,
25
25
  }));
26
26
  }
27
+ async handleDevicesChange() {
28
+ const deviceResponse = await getAudioDevices();
29
+ this.devices = deviceResponse.devices;
30
+ if (!this.devices.find(device => device.deviceId === this.selectedDevice?.deviceId)) {
31
+ this.selectedDevice = deviceResponse.defaultDevice;
32
+ }
33
+ this.dispatchCustomEvent('recording-devices-changed', {
34
+ devices: deviceResponse.devices,
35
+ selectedDevice: this.selectedDevice || deviceResponse.defaultDevice,
36
+ });
37
+ }
27
38
  async startRecording(params) {
28
39
  this._updateRecordingState('initializing');
29
- // Get media stream and initialize audio service.
30
40
  try {
31
- this._mediaStream = await navigator.mediaDevices.getUserMedia({
32
- audio: { deviceId: this.selectedDevice },
41
+ this._mediaStream = await getMediaStream(params.debug_displayAudio
42
+ ? 'display_audio'
43
+ : this.selectedDevice?.deviceId);
44
+ this._mediaStream.getTracks().forEach((track) => {
45
+ track.addEventListener('ended', () => {
46
+ if (this.recordingState === 'recording') {
47
+ this.dispatchCustomEvent('error', {
48
+ message: 'Microphone access was lost.',
49
+ });
50
+ this.stopRecording();
51
+ }
52
+ });
33
53
  });
34
54
  this._audioService = new AudioService(this._mediaStream);
35
55
  }
36
56
  catch (error) {
37
57
  this.dispatchCustomEvent('error', error);
38
- this._updateRecordingState('stopped');
58
+ this.stopRecording();
39
59
  return;
40
60
  }
41
61
  // Initialize dictation service.
42
62
  try {
43
63
  this._dictationService = new DictationService(this._mediaStream, params);
64
+ // Forward custom events from dictation service
65
+ this._dictationService.addEventListener('error', e => {
66
+ this.dispatchEvent(new CustomEvent('error', {
67
+ detail: e.detail,
68
+ bubbles: true,
69
+ composed: true,
70
+ }));
71
+ this.stopRecording();
72
+ });
73
+ this._dictationService.addEventListener('stream-closed', () => this.stopRecording());
74
+ this._dictationService.addEventListener('transcript', e => this.dispatchEvent(new CustomEvent('transcript', {
75
+ detail: e.detail,
76
+ bubbles: true,
77
+ composed: true,
78
+ })));
79
+ this._dictationService.addEventListener('command', e => this.dispatchEvent(new CustomEvent('command', {
80
+ detail: e.detail,
81
+ bubbles: true,
82
+ composed: true,
83
+ })));
44
84
  }
45
85
  catch (error) {
46
86
  this.dispatchCustomEvent('error', error);
47
87
  this.stopRecording();
48
88
  return;
49
89
  }
50
- // Forward dictation service events.
51
- this._dictationService.addEventListener('error', e => this.dispatchCustomEvent('error', e.detail));
52
- this._dictationService.addEventListener('stream-closed', () => this.stopRecording());
53
- this._dictationService.addEventListener('transcript', e => this.dispatchCustomEvent('transcript', e.detail));
54
- this._dictationService.startRecording();
90
+ try {
91
+ this._dictationService?.startRecording();
92
+ }
93
+ catch (error) {
94
+ this.dispatchEvent(new CustomEvent('error', {
95
+ detail: error,
96
+ bubbles: true,
97
+ composed: true,
98
+ }));
99
+ this.stopRecording();
100
+ return;
101
+ }
55
102
  this._updateRecordingState('recording');
56
103
  // Update audio level visualization.
57
104
  this._visualiserInterval = window.setInterval(() => {
@@ -69,8 +116,8 @@ export class RecorderManager extends EventTarget {
69
116
  }
70
117
  if (this._mediaStream) {
71
118
  this._mediaStream.getTracks().forEach(track => track.stop());
72
- this._mediaStream = null;
73
119
  }
120
+ this.dispatchCustomEvent('audio-level-changed', { audioLevel: 0 });
74
121
  await this._dictationService?.stopRecording();
75
122
  this._updateRecordingState('stopped');
76
123
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAAhD;;QACS,YAAO,GAAsB,EAAE,CAAC;QAEhC,mBAAc,GAAW,EAAE,CAAC;QAE5B,mBAAc,GAAmB,SAAS,CAAC;QAE1C,iBAAY,GAAuB,IAAI,CAAC;QAExC,kBAAa,GAAwB,IAAI,CAAC;QAE1C,sBAAiB,GAA4B,IAAI,CAAC;IA8F5D,CAAC;IA1FC,KAAK,CAAC,UAAU;QACd,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,eAAe,IAAI,EAAE,CAAC;QAC3D,OAAO,cAAc,CAAC;IACxB,CAAC;IACO,mBAAmB,CAAC,SAAiB,EAAE,MAAe;QAC5D,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;YACzB,MAAM;YACN,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAGpB;QACC,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAE3C,iDAAiD;QACjD,IAAI,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBAC5D,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE;aACzC,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,oCAAoC;QACpC,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CACnD,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAG,CAAiB,CAAC,MAAM,CAAC,CAC7D,CAAC;QACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,eAAe,EAAE,GAAG,EAAE,CAC5D,IAAI,CAAC,aAAa,EAAE,CACrB,CAAC;QACF,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CACxD,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAG,CAAiB,CAAC,MAAM,CAAC,CAClE,CAAC;QAEF,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,CAAC;QACxC,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAExC,oCAAoC;QACpC,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa;gBAC9B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,GAAG,CAAC;gBACxC,CAAC,CAAC,CAAC,CAAC;YACN,IAAI,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,aAAa,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACxC,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACvC,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,MAAM,IAAI,CAAC,iBAAiB,EAAE,aAAa,EAAE,CAAC;QAC9C,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAEO,qBAAqB,CAAC,KAAqB;QACjD,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,yBAAyB,EAAE;YACzC,MAAM,EAAE,EAAE,KAAK,EAAE;YACjB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { getAudioDevices } from './utils.js';\nimport { AudioService } from './audioService.js';\nimport { DictationService } from './DictationService.js';\nimport type { DictationConfig, RecordingState } from './types.js';\n\nexport class RecorderManager extends EventTarget {\n public devices: MediaDeviceInfo[] = [];\n\n public selectedDevice: string = '';\n\n public recordingState: RecordingState = 'stopped';\n\n private _mediaStream: MediaStream | null = null;\n\n private _audioService: AudioService | null = null;\n\n private _dictationService: DictationService | null = null;\n\n private _visualiserInterval?: number;\n\n async initialize() {\n const deviceResponse = await getAudioDevices();\n this.devices = deviceResponse.devices;\n this.selectedDevice = deviceResponse.defaultDeviceId || '';\n return deviceResponse;\n }\n private dispatchCustomEvent(eventName: string, detail: unknown): void {\n this.dispatchEvent(\n new CustomEvent(eventName, {\n detail,\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n async startRecording(params: {\n dictationConfig: DictationConfig;\n authToken: string;\n }): Promise<void> {\n this._updateRecordingState('initializing');\n\n // Get media stream and initialize audio service.\n try {\n this._mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { deviceId: this.selectedDevice },\n });\n this._audioService = new AudioService(this._mediaStream);\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this._updateRecordingState('stopped');\n return;\n }\n\n // Initialize dictation service.\n try {\n this._dictationService = new DictationService(this._mediaStream, params);\n } catch (error) {\n this.dispatchCustomEvent('error', error);\n this.stopRecording();\n return;\n }\n\n // Forward dictation service events.\n this._dictationService.addEventListener('error', e =>\n this.dispatchCustomEvent('error', (e as CustomEvent).detail),\n );\n this._dictationService.addEventListener('stream-closed', () =>\n this.stopRecording(),\n );\n this._dictationService.addEventListener('transcript', e =>\n this.dispatchCustomEvent('transcript', (e as CustomEvent).detail),\n );\n\n this._dictationService.startRecording();\n this._updateRecordingState('recording');\n\n // Update audio level visualization.\n this._visualiserInterval = window.setInterval(() => {\n const level = this._audioService\n ? this._audioService.getAudioLevel() * 3\n : 0;\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: level });\n }, 150);\n }\n\n async stopRecording() {\n this._updateRecordingState('stopping');\n if (this._visualiserInterval) {\n clearInterval(this._visualiserInterval);\n this._visualiserInterval = undefined;\n }\n if (this._mediaStream) {\n this._mediaStream.getTracks().forEach(track => track.stop());\n this._mediaStream = null;\n }\n await this._dictationService?.stopRecording();\n this._updateRecordingState('stopped');\n }\n\n private _updateRecordingState(state: RecordingState) {\n this.recordingState = state;\n this.dispatchEvent(\n new CustomEvent('recording-state-changed', {\n detail: { state },\n bubbles: true,\n composed: true,\n }),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"RecorderManager.js","sourceRoot":"","sources":["../src/RecorderManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAudioDevices, getMediaStream } from './utils.js';\r\nimport { AudioService } from './audioService.js';\r\nimport { DictationService } from './DictationService.js';\r\nimport type { DictationConfig, RecordingState } from './types.js';\r\n\r\nexport class RecorderManager extends EventTarget {\r\n public devices: MediaDeviceInfo[] = [];\r\n\r\n public selectedDevice: MediaDeviceInfo | undefined;\r\n\r\n public recordingState: RecordingState = 'stopped';\r\n\r\n private _mediaStream: MediaStream | null = null;\r\n\r\n private _audioService: AudioService | null = null;\r\n\r\n private _dictationService: DictationService | null = null;\r\n\r\n private _visualiserInterval?: number;\r\n\r\n constructor() {\r\n super();\r\n navigator.mediaDevices.addEventListener(\r\n 'devicechange',\r\n this.handleDevicesChange.bind(this),\r\n );\r\n }\r\n\r\n async initialize() {\r\n const deviceResponse = await getAudioDevices();\r\n this.devices = deviceResponse.devices;\r\n this.selectedDevice = deviceResponse.defaultDevice;\r\n return { devices: this.devices, selectedDevice: this.selectedDevice };\r\n }\r\n\r\n private dispatchCustomEvent(eventName: string, detail?: unknown): void {\r\n this.dispatchEvent(\r\n new CustomEvent(eventName, {\r\n detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n private async handleDevicesChange() {\r\n const deviceResponse = await getAudioDevices();\r\n this.devices = deviceResponse.devices;\r\n if (\r\n !this.devices.find(\r\n device => device.deviceId === this.selectedDevice?.deviceId,\r\n )\r\n ) {\r\n this.selectedDevice = deviceResponse.defaultDevice;\r\n }\r\n this.dispatchCustomEvent('recording-devices-changed', {\r\n devices: deviceResponse.devices,\r\n selectedDevice: this.selectedDevice || deviceResponse.defaultDevice,\r\n });\r\n }\r\n\r\n async startRecording(params: {\r\n dictationConfig: DictationConfig;\r\n authToken: string;\r\n debug_displayAudio?: boolean;\r\n }): Promise<void> {\r\n this._updateRecordingState('initializing');\r\n\r\n try {\r\n this._mediaStream = await getMediaStream(\r\n params.debug_displayAudio\r\n ? 'display_audio'\r\n : this.selectedDevice?.deviceId,\r\n );\r\n\r\n this._mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\r\n track.addEventListener('ended', () => {\r\n if (this.recordingState === 'recording') {\r\n this.dispatchCustomEvent('error', {\r\n message: 'Microphone access was lost.',\r\n });\r\n this.stopRecording();\r\n }\r\n });\r\n });\r\n\r\n this._audioService = new AudioService(this._mediaStream);\r\n } catch (error) {\r\n this.dispatchCustomEvent('error', error);\r\n this.stopRecording();\r\n return;\r\n }\r\n\r\n // Initialize dictation service.\r\n try {\r\n this._dictationService = new DictationService(this._mediaStream, params);\r\n\r\n // Forward custom events from dictation service\r\n this._dictationService.addEventListener('error', e => {\r\n this.dispatchEvent(\r\n new CustomEvent('error', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.stopRecording();\r\n });\r\n this._dictationService.addEventListener('stream-closed', () =>\r\n this.stopRecording(),\r\n );\r\n this._dictationService.addEventListener('transcript', e =>\r\n this.dispatchEvent(\r\n new CustomEvent('transcript', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n ),\r\n );\r\n this._dictationService.addEventListener('command', e =>\r\n this.dispatchEvent(\r\n new CustomEvent('command', {\r\n detail: (e as CustomEvent).detail,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n ),\r\n );\r\n } catch (error) {\r\n this.dispatchCustomEvent('error', error);\r\n this.stopRecording();\r\n return;\r\n }\r\n\r\n try {\r\n this._dictationService?.startRecording();\r\n } catch (error) {\r\n this.dispatchEvent(\r\n new CustomEvent('error', {\r\n detail: error,\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.stopRecording();\r\n return;\r\n }\r\n this._updateRecordingState('recording');\r\n\r\n // Update audio level visualization.\r\n this._visualiserInterval = window.setInterval(() => {\r\n const level = this._audioService\r\n ? this._audioService.getAudioLevel() * 3\r\n : 0;\r\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: level });\r\n }, 150);\r\n }\r\n\r\n async stopRecording() {\r\n this._updateRecordingState('stopping');\r\n if (this._visualiserInterval) {\r\n clearInterval(this._visualiserInterval);\r\n this._visualiserInterval = undefined;\r\n }\r\n if (this._mediaStream) {\r\n this._mediaStream.getTracks().forEach(track => track.stop());\r\n }\r\n this.dispatchCustomEvent('audio-level-changed', { audioLevel: 0 });\r\n await this._dictationService?.stopRecording();\r\n this._updateRecordingState('stopped');\r\n }\r\n\r\n private _updateRecordingState(state: RecordingState) {\r\n this.recordingState = state;\r\n this.dispatchEvent(\r\n new CustomEvent('recording-state-changed', {\r\n detail: { state },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n}\r\n"]}
package/dist/bundle.js CHANGED
@@ -623,8 +623,8 @@ async function getAudioDevices() {
623
623
  try {
624
624
  const devices = await navigator.mediaDevices.enumerateDevices();
625
625
  const audioDevices = devices.filter((device) => device.kind === "audioinput");
626
- const defaultDeviceId = audioDevices.length > 0 ? audioDevices[0].deviceId : void 0;
627
- return { devices: audioDevices, defaultDeviceId };
626
+ const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : void 0;
627
+ return { devices: audioDevices, defaultDevice };
628
628
  } catch (error) {
629
629
  console.error("Error enumerating devices:", error);
630
630
  return { devices: [] };
@@ -633,7 +633,7 @@ async function getAudioDevices() {
633
633
  function decodeToken(token) {
634
634
  const parts = token.split(".");
635
635
  if (parts.length < 2) {
636
- throw new Error("Invalid token format: expected header.payload.signature");
636
+ throw new Error("Invalid token format");
637
637
  }
638
638
  const base64Url = parts[1];
639
639
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
@@ -663,6 +663,25 @@ function decodeToken(token) {
663
663
  };
664
664
  }
665
665
  }
666
+ async function getMediaStream(deviceId) {
667
+ if (!deviceId) {
668
+ throw new Error("No device ID provided");
669
+ }
670
+ if (deviceId === "display_audio") {
671
+ const stream = await navigator.mediaDevices.getDisplayMedia({
672
+ audio: true,
673
+ video: true
674
+ });
675
+ stream.getTracks().forEach((track) => {
676
+ if (track.kind === "video") {
677
+ stream.removeTrack(track);
678
+ }
679
+ });
680
+ return stream;
681
+ }
682
+ const constraints = deviceId !== "default" ? { audio: { deviceId: { exact: deviceId } } } : { audio: true };
683
+ return await navigator.mediaDevices.getUserMedia(constraints);
684
+ }
666
685
 
667
686
  // dist/audioService.js
668
687
  var AudioService = class {
@@ -697,7 +716,6 @@ var DictationService = class extends EventTarget {
697
716
  if (!config) {
698
717
  throw new Error("Invalid token");
699
718
  }
700
- this.serverConfig = config;
701
719
  this.mediaRecorder.ondataavailable = (event) => {
702
720
  if (this.webSocket?.readyState === WebSocket.OPEN) {
703
721
  this.webSocket.send(event.data);
@@ -712,7 +730,16 @@ var DictationService = class extends EventTarget {
712
730
  }));
713
731
  }
714
732
  startRecording() {
715
- const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.authToken}`;
733
+ const serverConfig = decodeToken(this.authToken);
734
+ if (!serverConfig) {
735
+ this.dispatchEvent(new CustomEvent("error", {
736
+ detail: "Invalid token",
737
+ bubbles: true,
738
+ composed: true
739
+ }));
740
+ return;
741
+ }
742
+ const url = `wss://api.${serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${serverConfig.tenant}&token=Bearer%20${this.authToken}`;
716
743
  this.webSocket = new WebSocket(url);
717
744
  this.webSocket.onopen = () => {
718
745
  this.webSocket.send(JSON.stringify({
@@ -722,10 +749,22 @@ var DictationService = class extends EventTarget {
722
749
  };
723
750
  this.webSocket.onmessage = (event) => {
724
751
  const message = JSON.parse(event.data);
725
- if (message.type === "config") {
726
- this.mediaRecorder.start(250);
727
- } else if (message.type === "transcript") {
728
- this.dispatchCustomEvent("transcript", message);
752
+ switch (message.type) {
753
+ case "CONFIG_ACCEPTED":
754
+ this.mediaRecorder.start(250);
755
+ break;
756
+ case "CONFIG_DENIED":
757
+ this.dispatchCustomEvent("error", message);
758
+ return this.stopRecording();
759
+ case "transcript":
760
+ this.dispatchCustomEvent("transcript", message);
761
+ break;
762
+ case "command":
763
+ this.dispatchCustomEvent("command", message);
764
+ break;
765
+ default:
766
+ console.warn(`Unhandled message type: ${message.type}`);
767
+ break;
729
768
  }
730
769
  };
731
770
  this.webSocket.onerror = (event) => {
@@ -736,7 +775,7 @@ var DictationService = class extends EventTarget {
736
775
  };
737
776
  }
738
777
  async stopRecording() {
739
- this.mediaRecorder.stop();
778
+ this.mediaRecorder?.stop();
740
779
  if (this.webSocket?.readyState === WebSocket.OPEN) {
741
780
  this.webSocket.send(JSON.stringify({ type: "end" }));
742
781
  }
@@ -755,19 +794,19 @@ var DictationService = class extends EventTarget {
755
794
  // dist/RecorderManager.js
756
795
  var RecorderManager = class extends EventTarget {
757
796
  constructor() {
758
- super(...arguments);
797
+ super();
759
798
  this.devices = [];
760
- this.selectedDevice = "";
761
799
  this.recordingState = "stopped";
762
800
  this._mediaStream = null;
763
801
  this._audioService = null;
764
802
  this._dictationService = null;
803
+ navigator.mediaDevices.addEventListener("devicechange", this.handleDevicesChange.bind(this));
765
804
  }
766
805
  async initialize() {
767
806
  const deviceResponse = await getAudioDevices();
768
807
  this.devices = deviceResponse.devices;
769
- this.selectedDevice = deviceResponse.defaultDeviceId || "";
770
- return deviceResponse;
808
+ this.selectedDevice = deviceResponse.defaultDevice;
809
+ return { devices: this.devices, selectedDevice: this.selectedDevice };
771
810
  }
772
811
  dispatchCustomEvent(eventName, detail) {
773
812
  this.dispatchEvent(new CustomEvent(eventName, {
@@ -776,29 +815,74 @@ var RecorderManager = class extends EventTarget {
776
815
  composed: true
777
816
  }));
778
817
  }
818
+ async handleDevicesChange() {
819
+ const deviceResponse = await getAudioDevices();
820
+ this.devices = deviceResponse.devices;
821
+ if (!this.devices.find((device) => device.deviceId === this.selectedDevice?.deviceId)) {
822
+ this.selectedDevice = deviceResponse.defaultDevice;
823
+ }
824
+ this.dispatchCustomEvent("recording-devices-changed", {
825
+ devices: deviceResponse.devices,
826
+ selectedDevice: this.selectedDevice || deviceResponse.defaultDevice
827
+ });
828
+ }
779
829
  async startRecording(params) {
780
830
  this._updateRecordingState("initializing");
781
831
  try {
782
- this._mediaStream = await navigator.mediaDevices.getUserMedia({
783
- audio: { deviceId: this.selectedDevice }
832
+ this._mediaStream = await getMediaStream(params.debug_displayAudio ? "display_audio" : this.selectedDevice?.deviceId);
833
+ this._mediaStream.getTracks().forEach((track) => {
834
+ track.addEventListener("ended", () => {
835
+ if (this.recordingState === "recording") {
836
+ this.dispatchCustomEvent("error", {
837
+ message: "Microphone access was lost."
838
+ });
839
+ this.stopRecording();
840
+ }
841
+ });
784
842
  });
785
843
  this._audioService = new AudioService(this._mediaStream);
786
844
  } catch (error) {
787
845
  this.dispatchCustomEvent("error", error);
788
- this._updateRecordingState("stopped");
846
+ this.stopRecording();
789
847
  return;
790
848
  }
791
849
  try {
792
850
  this._dictationService = new DictationService(this._mediaStream, params);
851
+ this._dictationService.addEventListener("error", (e5) => {
852
+ this.dispatchEvent(new CustomEvent("error", {
853
+ detail: e5.detail,
854
+ bubbles: true,
855
+ composed: true
856
+ }));
857
+ this.stopRecording();
858
+ });
859
+ this._dictationService.addEventListener("stream-closed", () => this.stopRecording());
860
+ this._dictationService.addEventListener("transcript", (e5) => this.dispatchEvent(new CustomEvent("transcript", {
861
+ detail: e5.detail,
862
+ bubbles: true,
863
+ composed: true
864
+ })));
865
+ this._dictationService.addEventListener("command", (e5) => this.dispatchEvent(new CustomEvent("command", {
866
+ detail: e5.detail,
867
+ bubbles: true,
868
+ composed: true
869
+ })));
793
870
  } catch (error) {
794
871
  this.dispatchCustomEvent("error", error);
795
872
  this.stopRecording();
796
873
  return;
797
874
  }
798
- this._dictationService.addEventListener("error", (e5) => this.dispatchCustomEvent("error", e5.detail));
799
- this._dictationService.addEventListener("stream-closed", () => this.stopRecording());
800
- this._dictationService.addEventListener("transcript", (e5) => this.dispatchCustomEvent("transcript", e5.detail));
801
- this._dictationService.startRecording();
875
+ try {
876
+ this._dictationService?.startRecording();
877
+ } catch (error) {
878
+ this.dispatchEvent(new CustomEvent("error", {
879
+ detail: error,
880
+ bubbles: true,
881
+ composed: true
882
+ }));
883
+ this.stopRecording();
884
+ return;
885
+ }
802
886
  this._updateRecordingState("recording");
803
887
  this._visualiserInterval = window.setInterval(() => {
804
888
  const level = this._audioService ? this._audioService.getAudioLevel() * 3 : 0;
@@ -813,8 +897,8 @@ var RecorderManager = class extends EventTarget {
813
897
  }
814
898
  if (this._mediaStream) {
815
899
  this._mediaStream.getTracks().forEach((track) => track.stop());
816
- this._mediaStream = null;
817
900
  }
901
+ this.dispatchCustomEvent("audio-level-changed", { audioLevel: 0 });
818
902
  await this._dictationService?.stopRecording();
819
903
  this._updateRecordingState("stopped");
820
904
  }
@@ -943,7 +1027,9 @@ var CalloutStyles = i`
943
1027
  display: flex;
944
1028
  font-size: 0.9rem;
945
1029
  gap: 8px;
946
- align-items: flex-start;
1030
+ align-items: center;
1031
+ max-width: 100%;
1032
+ height: fit-content;
947
1033
  &.red {
948
1034
  background: var(--callout-red-background);
949
1035
  border: 1px solid var(--callout-red-border);
@@ -954,6 +1040,11 @@ var CalloutStyles = i`
954
1040
  border: 1px solid var(--callout-orange-border);
955
1041
  color: var(--callout-orange-text);
956
1042
  }
1043
+ &.small {
1044
+ width: 100%;
1045
+ padding: 6px;
1046
+ font-size: 0.7rem;
1047
+ }
957
1048
  }
958
1049
  `;
959
1050
  var callout_default = CalloutStyles;
@@ -967,17 +1058,33 @@ var __decorate = function(decorators, target, key, desc) {
967
1058
  };
968
1059
  var SettingsMenu = class SettingsMenu2 extends r4 {
969
1060
  constructor() {
970
- super(...arguments);
971
- this.devices = [];
972
- this.selectedDevice = "";
1061
+ super();
973
1062
  this.selectedLanguage = "";
974
1063
  this.settingsDisabled = false;
1064
+ this._devices = [];
1065
+ navigator.mediaDevices.addEventListener("devicechange", this.handleDevicesChange.bind(this));
1066
+ }
1067
+ // on load, get the available devices
1068
+ async connectedCallback() {
1069
+ super.connectedCallback();
1070
+ const deviceResponse = await getAudioDevices();
1071
+ this._devices = deviceResponse.devices;
1072
+ }
1073
+ async handleDevicesChange() {
1074
+ const deviceResponse = await getAudioDevices();
1075
+ this._devices = deviceResponse.devices;
975
1076
  }
976
1077
  _selectDevice(deviceId) {
977
- this.selectedDevice = deviceId;
978
- const device = this.devices.find((d3) => d3.deviceId === deviceId);
979
- this.dispatchEvent(new CustomEvent("recording-device-changed", {
980
- detail: device,
1078
+ const device = this._devices.find((d3) => d3.deviceId === deviceId);
1079
+ if (!device) {
1080
+ return;
1081
+ }
1082
+ this.selectedDevice = device;
1083
+ this.dispatchEvent(new CustomEvent("recording-devices-changed", {
1084
+ detail: {
1085
+ devices: this._devices,
1086
+ selectedDevice: device
1087
+ },
981
1088
  bubbles: true,
982
1089
  composed: true
983
1090
  }));
@@ -1007,10 +1114,10 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
1007
1114
  }}
1008
1115
  ?disabled=${this.settingsDisabled}
1009
1116
  >
1010
- ${this.devices.map((device) => x`
1117
+ ${this._devices.map((device) => x`
1011
1118
  <option
1012
1119
  value=${device.deviceId}
1013
- ?selected=${this.selectedDevice === device.deviceId}
1120
+ ?selected=${this.selectedDevice === device}
1014
1121
  >
1015
1122
  ${device.label || "Unknown Device"}
1016
1123
  </option>
@@ -1084,9 +1191,6 @@ SettingsMenu.styles = [
1084
1191
  select_default,
1085
1192
  callout_default
1086
1193
  ];
1087
- __decorate([
1088
- n4({ type: Array })
1089
- ], SettingsMenu.prototype, "devices", void 0);
1090
1194
  __decorate([
1091
1195
  n4({ type: String })
1092
1196
  ], SettingsMenu.prototype, "selectedDevice", void 0);
@@ -1096,6 +1200,9 @@ __decorate([
1096
1200
  __decorate([
1097
1201
  n4({ type: Boolean })
1098
1202
  ], SettingsMenu.prototype, "settingsDisabled", void 0);
1203
+ __decorate([
1204
+ r6()
1205
+ ], SettingsMenu.prototype, "_devices", void 0);
1099
1206
  SettingsMenu = __decorate([
1100
1207
  t3("settings-menu")
1101
1208
  ], SettingsMenu);
@@ -1399,6 +1506,7 @@ var ComponentStyles = i`
1399
1506
  width: min-content;
1400
1507
  gap: 4px;
1401
1508
  height: 46px;
1509
+ width: 98px;
1402
1510
  box-sizing: border-box;
1403
1511
  overflow: hidden;
1404
1512
  }
@@ -1449,19 +1557,28 @@ var __decorate4 = function(decorators, target, key, desc) {
1449
1557
  var CortiDictation = class extends r4 {
1450
1558
  constructor() {
1451
1559
  super(...arguments);
1452
- this.devices = [];
1453
- this.recordingState = "stopped";
1454
1560
  this.dictationConfig = DEFAULT_DICTATION_CONFIG;
1561
+ this.debug_displayAudio = false;
1455
1562
  this._audioLevel = 0;
1563
+ this._recordingState = "stopped";
1564
+ this._devices = [];
1456
1565
  this.recorderManager = new RecorderManager();
1457
1566
  }
1458
1567
  async connectedCallback() {
1459
1568
  super.connectedCallback();
1460
- await this.recorderManager.initialize();
1461
- this.devices = this.recorderManager.devices;
1569
+ const devices = await this.recorderManager.initialize();
1570
+ if (devices.selectedDevice) {
1571
+ this._selectedDevice = this.recorderManager.selectedDevice;
1572
+ this._devices = this.recorderManager.devices;
1573
+ this.dispatchEvent(new CustomEvent("ready"));
1574
+ }
1462
1575
  const eventHandlers = {
1463
1576
  "recording-state-changed": (e5) => {
1464
- this.recordingState = e5.detail.state;
1577
+ this._recordingState = e5.detail.state;
1578
+ },
1579
+ "devices-changed": () => {
1580
+ this._devices = [...this.recorderManager.devices];
1581
+ this.requestUpdate();
1465
1582
  },
1466
1583
  "audio-level-changed": (e5) => {
1467
1584
  this._audioLevel = e5.detail.audioLevel;
@@ -1470,9 +1587,12 @@ var CortiDictation = class extends r4 {
1470
1587
  };
1471
1588
  const eventsToRelay = [
1472
1589
  "recording-state-changed",
1590
+ "recording-devices-changed",
1473
1591
  "audio-level-changed",
1474
1592
  "error",
1475
- "transcript"
1593
+ "transcript",
1594
+ "command",
1595
+ "ready"
1476
1596
  ];
1477
1597
  eventsToRelay.forEach((eventName) => {
1478
1598
  this.recorderManager.addEventListener(eventName, (e5) => {
@@ -1491,45 +1611,57 @@ var CortiDictation = class extends r4 {
1491
1611
  toggleRecording() {
1492
1612
  this._toggleRecording();
1493
1613
  }
1494
- _toggleRecording() {
1614
+ get selectedDevice() {
1615
+ return this.recorderManager.selectedDevice || null;
1616
+ }
1617
+ get recordingState() {
1618
+ return this._recordingState;
1619
+ }
1620
+ get devices() {
1621
+ return this._devices;
1622
+ }
1623
+ async setRecordingDevice(device) {
1624
+ this.recorderManager.selectedDevice = device;
1625
+ this._selectedDevice = device;
1495
1626
  if (!this.authToken)
1496
1627
  return;
1497
- if (this.recordingState === "recording") {
1498
- this.recorderManager.stopRecording();
1499
- } else if (this.recordingState === "stopped") {
1500
- this.recorderManager.startRecording({
1628
+ if (this._recordingState === "recording") {
1629
+ await this.recorderManager.stopRecording();
1630
+ await this.recorderManager.startRecording({
1501
1631
  dictationConfig: this.dictationConfig,
1502
1632
  authToken: this.authToken
1503
1633
  });
1504
1634
  }
1505
1635
  }
1506
- // Handle device change events if needed
1507
- async _onRecordingDeviceChanged(event) {
1508
- const customEvent = event;
1636
+ _toggleRecording() {
1509
1637
  if (!this.authToken)
1510
1638
  return;
1511
- this.recorderManager.selectedDevice = customEvent.detail.deviceId;
1512
- if (this.recordingState === "recording") {
1513
- await this.recorderManager.stopRecording();
1514
- await this.recorderManager.startRecording({
1639
+ if (this._recordingState === "recording") {
1640
+ this.recorderManager.stopRecording();
1641
+ } else if (this._recordingState === "stopped") {
1642
+ this.recorderManager.startRecording({
1515
1643
  dictationConfig: this.dictationConfig,
1516
- authToken: this.authToken
1644
+ authToken: this.authToken,
1645
+ debug_displayAudio: this.debug_displayAudio
1517
1646
  });
1518
1647
  }
1519
1648
  }
1649
+ // Handle device change events if needed
1650
+ async _onRecordingDevicesChanged(event) {
1651
+ const customEvent = event;
1652
+ this.setRecordingDevice(customEvent.detail.selectedDevice);
1653
+ }
1520
1654
  render() {
1521
1655
  const isConfigured = this.authToken;
1522
1656
  if (!isConfigured) {
1523
1657
  return x`
1524
1658
  <div class="wrapper">
1525
- <div class="callout red tiny">
1526
- Please configure the server settings in the parent component.
1527
- </div>
1659
+ <div class="callout red small">No Auth Token</div>
1528
1660
  </div>
1529
1661
  `;
1530
1662
  }
1531
- const isLoading = this.recordingState === "initializing" || this.recordingState === "stopping";
1532
- const isRecording = this.recordingState === "recording";
1663
+ const isLoading = this._recordingState === "initializing" || this._recordingState === "stopping";
1664
+ const isRecording = this._recordingState === "recording";
1533
1665
  return x`
1534
1666
  <div class="wrapper">
1535
1667
  <button
@@ -1544,31 +1676,36 @@ var CortiDictation = class extends r4 {
1544
1676
  </button>
1545
1677
 
1546
1678
  <settings-menu
1547
- .devices=${this.devices}
1548
- .selectedDevice=${this.recorderManager.selectedDevice}
1549
- ?settingsDisabled=${this.recordingState !== "stopped"}
1550
- @recording-device-changed=${this._onRecordingDeviceChanged}
1679
+ .selectedDevice=${this._selectedDevice}
1680
+ ?settingsDisabled=${this._recordingState !== "stopped"}
1681
+ @recording-devices-changed=${this._onRecordingDevicesChanged}
1551
1682
  ></settings-menu>
1552
1683
  </div>
1553
1684
  `;
1554
1685
  }
1555
1686
  };
1556
1687
  CortiDictation.styles = [buttons_default, theme_default, ComponentStyles_default, callout_default];
1557
- __decorate4([
1558
- n4({ type: Array })
1559
- ], CortiDictation.prototype, "devices", void 0);
1560
- __decorate4([
1561
- n4({ type: String, reflect: true })
1562
- ], CortiDictation.prototype, "recordingState", void 0);
1563
1688
  __decorate4([
1564
1689
  n4({ type: Object })
1565
1690
  ], CortiDictation.prototype, "dictationConfig", void 0);
1566
1691
  __decorate4([
1567
1692
  n4({ type: String })
1568
1693
  ], CortiDictation.prototype, "authToken", void 0);
1694
+ __decorate4([
1695
+ n4({ type: Boolean })
1696
+ ], CortiDictation.prototype, "debug_displayAudio", void 0);
1569
1697
  __decorate4([
1570
1698
  r6()
1571
1699
  ], CortiDictation.prototype, "_audioLevel", void 0);
1700
+ __decorate4([
1701
+ r6()
1702
+ ], CortiDictation.prototype, "_recordingState", void 0);
1703
+ __decorate4([
1704
+ r6()
1705
+ ], CortiDictation.prototype, "_selectedDevice", void 0);
1706
+ __decorate4([
1707
+ r6()
1708
+ ], CortiDictation.prototype, "_devices", void 0);
1572
1709
  var CortiDictation_default = CortiDictation;
1573
1710
 
1574
1711
  // dist/index.js
@@ -1,9 +1,12 @@
1
1
  import { LitElement, TemplateResult, CSSResultGroup } from 'lit';
2
2
  export declare class SettingsMenu extends LitElement {
3
- devices: MediaDeviceInfo[];
4
- selectedDevice: string;
3
+ selectedDevice: MediaDeviceInfo | undefined;
5
4
  selectedLanguage: string;
6
5
  settingsDisabled: boolean;
6
+ private _devices;
7
+ constructor();
8
+ connectedCallback(): Promise<void>;
9
+ private handleDevicesChange;
7
10
  static styles: CSSResultGroup;
8
11
  private _selectDevice;
9
12
  render(): TemplateResult;