@azure/ai-voicelive 1.0.0-beta.1 → 1.0.0-beta.2
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/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/models/index.d.ts +1 -1
- package/dist/browser/models/index.js +1 -1
- package/dist/browser/models/index.js.map +1 -1
- package/dist/browser/models/models.d.ts +357 -25
- package/dist/browser/models/models.js +361 -56
- package/dist/browser/models/models.js.map +1 -1
- package/dist/browser/protocol/messageParser.d.ts +1 -1
- package/dist/browser/protocol/messageParser.js +19 -76
- package/dist/browser/protocol/messageParser.js.map +1 -1
- package/dist/browser/voiceLiveSession.d.ts +2 -2
- package/dist/browser/voiceLiveSession.js +11 -10
- package/dist/browser/voiceLiveSession.js.map +1 -1
- package/dist/browser/websocket/websocket-browser.mjs.map +1 -0
- package/dist/browser/websocket/{websocketBrowser.d.ts → websocket.d.ts} +8 -2
- package/dist/{react-native/websocket/websocketBrowser.js → browser/websocket/websocket.js} +43 -3
- package/dist/browser/websocket/websocketFactory.d.ts +0 -11
- package/dist/browser/websocket/websocketFactory.js +2 -66
- package/dist/browser/websocket/websocketFactory.js.map +1 -1
- package/dist/browser/websocket/websocketLike.d.ts +3 -0
- package/dist/browser/websocket/websocketLike.js.map +1 -1
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +6 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/models/index.d.ts +1 -1
- package/dist/commonjs/models/index.js +6 -1
- package/dist/commonjs/models/index.js.map +1 -1
- package/dist/commonjs/models/models.d.ts +357 -25
- package/dist/commonjs/models/models.js +386 -59
- package/dist/commonjs/models/models.js.map +1 -1
- package/dist/commonjs/protocol/messageParser.d.ts +1 -1
- package/dist/commonjs/protocol/messageParser.js +18 -75
- package/dist/commonjs/protocol/messageParser.js.map +1 -1
- package/dist/commonjs/tsdoc-metadata.json +1 -1
- package/dist/commonjs/voiceLiveSession.d.ts +2 -2
- package/dist/commonjs/voiceLiveSession.js +20 -19
- package/dist/commonjs/voiceLiveSession.js.map +1 -1
- package/dist/{esm/websocket/websocketNode.d.ts → commonjs/websocket/websocket.d.ts} +2 -2
- package/dist/commonjs/websocket/{websocketNode.js → websocket.js} +31 -6
- package/dist/commonjs/websocket/websocket.js.map +1 -0
- package/dist/commonjs/websocket/websocketFactory.d.ts +0 -11
- package/dist/commonjs/websocket/websocketFactory.js +2 -68
- package/dist/commonjs/websocket/websocketFactory.js.map +1 -1
- package/dist/commonjs/websocket/websocketLike.d.ts +3 -0
- package/dist/commonjs/websocket/websocketLike.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/models/index.d.ts +1 -1
- package/dist/esm/models/index.js +1 -1
- package/dist/esm/models/index.js.map +1 -1
- package/dist/esm/models/models.d.ts +357 -25
- package/dist/esm/models/models.js +361 -56
- package/dist/esm/models/models.js.map +1 -1
- package/dist/esm/protocol/messageParser.d.ts +1 -1
- package/dist/esm/protocol/messageParser.js +19 -76
- package/dist/esm/protocol/messageParser.js.map +1 -1
- package/dist/esm/voiceLiveSession.d.ts +2 -2
- package/dist/esm/voiceLiveSession.js +11 -10
- package/dist/esm/voiceLiveSession.js.map +1 -1
- package/dist/{react-native/websocket/websocketNode.d.ts → esm/websocket/websocket.d.ts} +2 -2
- package/dist/{browser/websocket/websocketNode.js → esm/websocket/websocket.js} +29 -4
- package/dist/esm/websocket/websocket.js.map +1 -0
- package/dist/esm/websocket/websocketFactory.d.ts +0 -11
- package/dist/esm/websocket/websocketFactory.js +2 -66
- package/dist/esm/websocket/websocketFactory.js.map +1 -1
- package/dist/esm/websocket/websocketLike.d.ts +3 -0
- package/dist/esm/websocket/websocketLike.js.map +1 -1
- package/dist/react-native/index.d.ts +1 -1
- package/dist/react-native/index.js +1 -1
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native/models/index.d.ts +1 -1
- package/dist/react-native/models/index.js +1 -1
- package/dist/react-native/models/index.js.map +1 -1
- package/dist/react-native/models/models.d.ts +357 -25
- package/dist/react-native/models/models.js +361 -56
- package/dist/react-native/models/models.js.map +1 -1
- package/dist/react-native/protocol/messageParser.d.ts +1 -1
- package/dist/react-native/protocol/messageParser.js +19 -76
- package/dist/react-native/protocol/messageParser.js.map +1 -1
- package/dist/react-native/voiceLiveSession.d.ts +2 -2
- package/dist/react-native/voiceLiveSession.js +11 -10
- package/dist/react-native/voiceLiveSession.js.map +1 -1
- package/dist/{commonjs/websocket/websocketNode.d.ts → react-native/websocket/websocket.d.ts} +2 -2
- package/dist/{esm/websocket/websocketNode.js → react-native/websocket/websocket.js} +29 -4
- package/dist/react-native/websocket/websocket.js.map +1 -0
- package/dist/react-native/websocket/websocketFactory.d.ts +0 -11
- package/dist/react-native/websocket/websocketFactory.js +2 -66
- package/dist/react-native/websocket/websocketFactory.js.map +1 -1
- package/dist/react-native/websocket/websocketLike.d.ts +3 -0
- package/dist/react-native/websocket/websocketLike.js.map +1 -1
- package/package.json +20 -7
- package/dist/browser/websocket/websocketBrowser.js +0 -175
- package/dist/browser/websocket/websocketBrowser.js.map +0 -1
- package/dist/browser/websocket/websocketNode.d.ts +0 -26
- package/dist/browser/websocket/websocketNode.js.map +0 -1
- package/dist/commonjs/websocket/websocketBrowser.d.ts +0 -26
- package/dist/commonjs/websocket/websocketBrowser.js +0 -179
- package/dist/commonjs/websocket/websocketBrowser.js.map +0 -1
- package/dist/commonjs/websocket/websocketNode.js.map +0 -1
- package/dist/esm/websocket/websocketBrowser.d.ts +0 -26
- package/dist/esm/websocket/websocketBrowser.js +0 -175
- package/dist/esm/websocket/websocketBrowser.js.map +0 -1
- package/dist/esm/websocket/websocketNode.js.map +0 -1
- package/dist/react-native/websocket/websocketBrowser.d.ts +0 -26
- package/dist/react-native/websocket/websocketBrowser.js.map +0 -1
- package/dist/react-native/websocket/websocketNode.js +0 -180
- package/dist/react-native/websocket/websocketNode.js.map +0 -1
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.VoiceLiveMessageParser = void 0;
|
|
6
|
+
const logger_js_1 = require("../logger.js");
|
|
7
|
+
const index_js_1 = require("../models/index.js");
|
|
6
8
|
const models_js_1 = require("../models/models.js");
|
|
7
9
|
/**
|
|
8
10
|
* Parses and serializes Voice Live protocol messages
|
|
@@ -40,8 +42,20 @@ class VoiceLiveMessageParser {
|
|
|
40
42
|
return null; // Unknown message format
|
|
41
43
|
}
|
|
42
44
|
catch (error) {
|
|
43
|
-
|
|
44
|
-
return
|
|
45
|
+
logger_js_1.logger.error("Failed to parse incoming message:", error);
|
|
46
|
+
return {
|
|
47
|
+
type: "server",
|
|
48
|
+
event: {
|
|
49
|
+
type: index_js_1.KnownServerEventType.Error,
|
|
50
|
+
error: {
|
|
51
|
+
type: "error",
|
|
52
|
+
code: "MessageParsingError",
|
|
53
|
+
message: "Failed to parse incoming message data. " +
|
|
54
|
+
(error instanceof Error ? error.message : String(error)),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
raw: data,
|
|
58
|
+
};
|
|
45
59
|
}
|
|
46
60
|
}
|
|
47
61
|
/**
|
|
@@ -69,85 +83,14 @@ class VoiceLiveMessageParser {
|
|
|
69
83
|
*/
|
|
70
84
|
_isValidServerEventType(type) {
|
|
71
85
|
// Based on the comprehensive analysis in EXISTING_TYPES_ANALYSIS.md
|
|
72
|
-
|
|
73
|
-
// Error handling
|
|
74
|
-
"error",
|
|
75
|
-
// Session management
|
|
76
|
-
"session.created",
|
|
77
|
-
"session.updated",
|
|
78
|
-
"session.avatar.connecting",
|
|
79
|
-
// Audio buffer events
|
|
80
|
-
"input_audio_buffer.committed",
|
|
81
|
-
"input_audio_buffer.cleared",
|
|
82
|
-
"input_audio_buffer.speech_started",
|
|
83
|
-
"input_audio_buffer.speech_stopped",
|
|
84
|
-
// Conversation item events
|
|
85
|
-
"conversation.item.created",
|
|
86
|
-
"conversation.item.truncated",
|
|
87
|
-
"conversation.item.deleted",
|
|
88
|
-
"conversation.item.retrieved",
|
|
89
|
-
"conversation.item.input_audio_transcription.completed",
|
|
90
|
-
"conversation.item.input_audio_transcription.failed",
|
|
91
|
-
"conversation.item.input_audio_transcription.delta",
|
|
92
|
-
// Response lifecycle events
|
|
93
|
-
"response.created",
|
|
94
|
-
"response.done",
|
|
95
|
-
"response.output_item.added",
|
|
96
|
-
"response.output_item.done",
|
|
97
|
-
// Content streaming events
|
|
98
|
-
"response.content_part.added",
|
|
99
|
-
"response.content_part.done",
|
|
100
|
-
"response.text.delta",
|
|
101
|
-
"response.text.done",
|
|
102
|
-
// Audio streaming events
|
|
103
|
-
"response.audio_transcript.delta",
|
|
104
|
-
"response.audio_transcript.done",
|
|
105
|
-
"response.audio.delta",
|
|
106
|
-
"response.audio.done",
|
|
107
|
-
// Animation events
|
|
108
|
-
"response.animation.blendshape.delta",
|
|
109
|
-
"response.animation.blendshape.done",
|
|
110
|
-
"response.animation.viseme.delta",
|
|
111
|
-
"response.animation.viseme.done",
|
|
112
|
-
// Timestamp events
|
|
113
|
-
"response.audio.timestamp.delta",
|
|
114
|
-
"response.audio.timestamp.done",
|
|
115
|
-
// Function call events
|
|
116
|
-
"response.function_call_arguments.delta",
|
|
117
|
-
"response.function_call_arguments.done",
|
|
118
|
-
];
|
|
119
|
-
return validServerTypes.includes(type);
|
|
86
|
+
return Object.values(index_js_1.KnownServerEventType).includes(type);
|
|
120
87
|
}
|
|
121
88
|
/**
|
|
122
89
|
* Validates if the type string represents a valid client event type
|
|
123
90
|
*/
|
|
124
91
|
_isValidClientEventType(type) {
|
|
125
92
|
// Based on the comprehensive analysis in EXISTING_TYPES_ANALYSIS.md
|
|
126
|
-
|
|
127
|
-
// Session management
|
|
128
|
-
"session.update",
|
|
129
|
-
"session.avatar.connect",
|
|
130
|
-
// Turn-based audio
|
|
131
|
-
"input_audio_turn.start",
|
|
132
|
-
"input_audio_turn.append",
|
|
133
|
-
"input_audio_turn.end",
|
|
134
|
-
"input_audio_turn.cancel",
|
|
135
|
-
// Buffer-based audio
|
|
136
|
-
"input_audio_buffer.append",
|
|
137
|
-
"input_audio_buffer.commit",
|
|
138
|
-
"input_audio_buffer.clear",
|
|
139
|
-
// Audio control
|
|
140
|
-
"input_audio.clear",
|
|
141
|
-
// Conversation management
|
|
142
|
-
"conversation.item.create",
|
|
143
|
-
"conversation.item.truncate",
|
|
144
|
-
"conversation.item.delete",
|
|
145
|
-
"conversation.item.retrieve",
|
|
146
|
-
// Response management
|
|
147
|
-
"response.create",
|
|
148
|
-
"response.cancel",
|
|
149
|
-
];
|
|
150
|
-
return validClientTypes.includes(type);
|
|
93
|
+
return Object.values(models_js_1.KnownClientEventType).includes(type);
|
|
151
94
|
}
|
|
152
95
|
}
|
|
153
96
|
exports.VoiceLiveMessageParser = VoiceLiveMessageParser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageParser.js","sourceRoot":"","sources":["../../../src/protocol/messageParser.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;
|
|
1
|
+
{"version":3,"file":"messageParser.js","sourceRoot":"","sources":["../../../src/protocol/messageParser.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAElC,4CAAsC;AACtC,iDAI4B;AAC5B,mDAM6B;AAc7B;;GAEG;AACH,MAAa,sBAAsB;IACjC;;OAEG;IACH,oBAAoB,CAAC,IAA0B;QAC7C,IAAI,CAAC;YACH,IAAI,WAAmB,CAAC;YAExB,IAAI,IAAI,YAAY,WAAW,EAAE,CAAC;gBAChC,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,WAAW,GAAG,IAAI,CAAC;YACrB,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAE3C,0DAA0D;YAC1D,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,OAAO;oBACL,IAAI,EAAE,QAAQ;oBACd,KAAK,EAAE,IAAA,wCAA4B,EAAC,UAAU,CAAC;oBAC/C,GAAG,EAAE,IAAI;iBACV,CAAC;YACJ,CAAC;YAED,iFAAiF;YACjF,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,OAAO;oBACL,IAAI,EAAE,QAAQ;oBACd,KAAK,EAAE,UAA8B;oBACrC,GAAG,EAAE,IAAI;iBACV,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,CAAC,CAAC,yBAAyB;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kBAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;YACzD,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,+BAAoB,CAAC,KAAK;oBAChC,KAAK,EAAE;wBACL,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,qBAAqB;wBAC3B,OAAO,EACL,yCAAyC;4BACzC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;qBAChC;iBACT;gBACrB,GAAG,EAAE,IAAI;aACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,wBAAwB,CAAC,KAAuB;QAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,sCAA0B,EAAC,KAAK,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,IAAS;QAC9B,mDAAmD;QACnD,OAAO,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,IAAS;QAC9B,mDAAmD;QACnD,OAAO,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,IAAY;QAC1C,oEAAoE;QACpE,OAAO,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC,CAAC,QAAQ,CAAC,IAA4B,CAAC,CAAC;IACpF,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,IAAY;QAC1C,oEAAoE;QACpE,OAAO,MAAM,CAAC,MAAM,CAAC,gCAAoB,CAAC,CAAC,QAAQ,CAAC,IAA4B,CAAC,CAAC;IACpF,CAAC;CACF;AA5FD,wDA4FC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { logger } from \"../logger.js\";\nimport {\n type ServerEventUnion,\n type ClientEventUnion,\n KnownServerEventType,\n} from \"../models/index.js\";\nimport {\n clientEventUnionSerializer,\n KnownClientEventType,\n type ServerEventError,\n type ServerEventErrorDetails,\n serverEventUnionDeserializer,\n} from \"../models/models.js\";\n\n/**\n * Parsed message containing event data and metadata\n */\nexport interface ParsedMessage {\n /** Type of event: client or server */\n type: \"client\" | \"server\";\n /** Parsed event data */\n event: ClientEventUnion | ServerEventUnion;\n /** Original raw data for debugging */\n raw: string | ArrayBuffer;\n}\n\n/**\n * Parses and serializes Voice Live protocol messages\n */\nexport class VoiceLiveMessageParser {\n /**\n * Parses incoming WebSocket message data into typed events\n */\n parseIncomingMessage(data: string | ArrayBuffer): ParsedMessage | null {\n try {\n let messageText: string;\n\n if (data instanceof ArrayBuffer) {\n messageText = new TextDecoder().decode(data);\n } else {\n messageText = data;\n }\n\n const parsedData = JSON.parse(messageText);\n\n // Validate and type the message based on the 'type' field\n if (this._isServerEvent(parsedData)) {\n return {\n type: \"server\",\n event: serverEventUnionDeserializer(parsedData),\n raw: data,\n };\n }\n\n // Handle unexpected client events (shouldn't normally receive these from server)\n if (this._isClientEvent(parsedData)) {\n return {\n type: \"client\",\n event: parsedData as ClientEventUnion,\n raw: data,\n };\n }\n\n return null; // Unknown message format\n } catch (error) {\n logger.error(\"Failed to parse incoming message:\", error);\n return {\n type: \"server\",\n event: {\n type: KnownServerEventType.Error,\n error: {\n type: \"error\",\n code: \"MessageParsingError\",\n message:\n \"Failed to parse incoming message data. \" +\n (error instanceof Error ? error.message : String(error)),\n } as ServerEventErrorDetails,\n } as ServerEventError,\n raw: data,\n };\n }\n }\n\n /**\n * Serializes outgoing client events for WebSocket transmission\n */\n serializeOutgoingMessage(event: ClientEventUnion): string {\n return JSON.stringify(clientEventUnionSerializer(event));\n }\n\n /**\n * Checks if the parsed data represents a server event\n */\n private _isServerEvent(data: any): boolean {\n // Check if data matches ServerEventUnion structure\n return data && typeof data.type === \"string\" && this._isValidServerEventType(data.type);\n }\n\n /**\n * Checks if the parsed data represents a client event\n */\n private _isClientEvent(data: any): boolean {\n // Check if data matches ClientEventUnion structure\n return data && typeof data.type === \"string\" && this._isValidClientEventType(data.type);\n }\n\n /**\n * Validates if the type string represents a valid server event type\n */\n private _isValidServerEventType(type: string): boolean {\n // Based on the comprehensive analysis in EXISTING_TYPES_ANALYSIS.md\n return Object.values(KnownServerEventType).includes(type as KnownServerEventType);\n }\n\n /**\n * Validates if the type string represents a valid client event type\n */\n private _isValidClientEventType(type: string): boolean {\n // Based on the comprehensive analysis in EXISTING_TYPES_ANALYSIS.md\n return Object.values(KnownClientEventType).includes(type as KnownClientEventType);\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { KeyCredential, TokenCredential } from "@azure/core-auth";
|
|
2
2
|
import type { AbortSignalLike } from "@azure/abort-controller";
|
|
3
|
-
import type
|
|
3
|
+
import { type RequestSession, type ClientEventUnion, type ConversationRequestItem } from "./models/index.js";
|
|
4
4
|
import { ConnectionState } from "./websocket/connectionManager.js";
|
|
5
5
|
import type { VoiceLiveSessionHandlers, VoiceLiveSubscription } from "./handlers/sessionHandlers.js";
|
|
6
6
|
export interface VoiceLiveSessionOptions {
|
|
@@ -45,6 +45,7 @@ export declare class VoiceLiveSession {
|
|
|
45
45
|
private readonly _options;
|
|
46
46
|
private readonly _messageParser;
|
|
47
47
|
private readonly _model;
|
|
48
|
+
private readonly _apiVersion;
|
|
48
49
|
private _connectionManager?;
|
|
49
50
|
private _sessionId?;
|
|
50
51
|
private _activeTurnId?;
|
|
@@ -70,7 +71,6 @@ export declare class VoiceLiveSession {
|
|
|
70
71
|
disconnect(): Promise<void>;
|
|
71
72
|
/**
|
|
72
73
|
* Subscribe to VoiceLive session events using strongly-typed handlers.
|
|
73
|
-
* This follows the Azure SDK pattern used by EventHub, Service Bus, etc.
|
|
74
74
|
*
|
|
75
75
|
* @param handlers - Handler functions for different types of events
|
|
76
76
|
* @returns A subscription object that can be used to stop receiving events
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.VoiceLiveSession = void 0;
|
|
6
|
+
const index_js_1 = require("./models/index.js");
|
|
6
7
|
const connectionManager_js_1 = require("./websocket/connectionManager.js");
|
|
7
8
|
const websocketFactory_js_1 = require("./websocket/websocketFactory.js");
|
|
8
9
|
const messageParser_js_1 = require("./protocol/messageParser.js");
|
|
9
10
|
const credentialHandler_js_1 = require("./auth/credentialHandler.js");
|
|
10
|
-
const
|
|
11
|
+
const index_js_2 = require("./errors/index.js");
|
|
11
12
|
const logger_js_1 = require("./logger.js");
|
|
12
13
|
const subscriptionManager_js_1 = require("./handlers/subscriptionManager.js");
|
|
13
14
|
/**
|
|
@@ -22,6 +23,7 @@ class VoiceLiveSession {
|
|
|
22
23
|
_options;
|
|
23
24
|
_messageParser;
|
|
24
25
|
_model;
|
|
26
|
+
_apiVersion;
|
|
25
27
|
_connectionManager;
|
|
26
28
|
_sessionId;
|
|
27
29
|
_activeTurnId;
|
|
@@ -43,6 +45,7 @@ class VoiceLiveSession {
|
|
|
43
45
|
this._options = this._buildDefaultOptions(options);
|
|
44
46
|
this._messageParser = new messageParser_js_1.VoiceLiveMessageParser();
|
|
45
47
|
this._model = model;
|
|
48
|
+
this._apiVersion = apiVersion;
|
|
46
49
|
// Initialize handler-based subscription management
|
|
47
50
|
this._subscriptionManager = new subscriptionManager_js_1.SubscriptionManager();
|
|
48
51
|
logger_js_1.logger.info("VoiceLiveSession created", {
|
|
@@ -67,8 +70,7 @@ class VoiceLiveSession {
|
|
|
67
70
|
model: this._model,
|
|
68
71
|
});
|
|
69
72
|
// Get WebSocket URL with authentication and model
|
|
70
|
-
const wsUrl = await this._credentialHandler.getWebSocketUrl(this._endpoint,
|
|
71
|
-
this._model);
|
|
73
|
+
const wsUrl = await this._credentialHandler.getWebSocketUrl(this._endpoint, this._apiVersion, this._model);
|
|
72
74
|
const authHeaders = await this._credentialHandler.getAuthHeaders();
|
|
73
75
|
// Create connection manager
|
|
74
76
|
const websocketFactory = new websocketFactory_js_1.VoiceLiveWebSocketFactory();
|
|
@@ -89,11 +91,11 @@ class VoiceLiveSession {
|
|
|
89
91
|
catch (error) {
|
|
90
92
|
logger_js_1.logger.error("Failed to connect to Voice Live service", { error });
|
|
91
93
|
// Use error classification
|
|
92
|
-
if (error instanceof
|
|
94
|
+
if (error instanceof index_js_2.VoiceLiveConnectionError) {
|
|
93
95
|
throw error;
|
|
94
96
|
}
|
|
95
97
|
else {
|
|
96
|
-
throw (0,
|
|
98
|
+
throw (0, index_js_2.classifyConnectionError)(error);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
}
|
|
@@ -120,7 +122,6 @@ class VoiceLiveSession {
|
|
|
120
122
|
}
|
|
121
123
|
/**
|
|
122
124
|
* Subscribe to VoiceLive session events using strongly-typed handlers.
|
|
123
|
-
* This follows the Azure SDK pattern used by EventHub, Service Bus, etc.
|
|
124
125
|
*
|
|
125
126
|
* @param handlers - Handler functions for different types of events
|
|
126
127
|
* @returns A subscription object that can be used to stop receiving events
|
|
@@ -143,7 +144,7 @@ class VoiceLiveSession {
|
|
|
143
144
|
async updateSession(session, options = {}) {
|
|
144
145
|
this._ensureConnected();
|
|
145
146
|
const updateEvent = {
|
|
146
|
-
type:
|
|
147
|
+
type: index_js_1.KnownClientEventType.SessionUpdate,
|
|
147
148
|
session: session,
|
|
148
149
|
eventId: this._generateEventId(),
|
|
149
150
|
};
|
|
@@ -158,7 +159,7 @@ class VoiceLiveSession {
|
|
|
158
159
|
if (options.turnId) {
|
|
159
160
|
// Turn-based audio
|
|
160
161
|
const appendEvent = {
|
|
161
|
-
type:
|
|
162
|
+
type: index_js_1.KnownClientEventType.InputAudioTurnAppend,
|
|
162
163
|
audio: audioBase64,
|
|
163
164
|
turnId: options.turnId,
|
|
164
165
|
eventId: this._generateEventId(),
|
|
@@ -168,7 +169,7 @@ class VoiceLiveSession {
|
|
|
168
169
|
else {
|
|
169
170
|
// Buffer-based audio (VAD mode)
|
|
170
171
|
const bufferEvent = {
|
|
171
|
-
type:
|
|
172
|
+
type: index_js_1.KnownClientEventType.InputAudioBufferAppend,
|
|
172
173
|
audio: audioBase64,
|
|
173
174
|
eventId: this._generateEventId(),
|
|
174
175
|
};
|
|
@@ -183,7 +184,7 @@ class VoiceLiveSession {
|
|
|
183
184
|
const turnId = options.turnId || this._generateTurnId();
|
|
184
185
|
this._activeTurnId = turnId;
|
|
185
186
|
const startEvent = {
|
|
186
|
-
type:
|
|
187
|
+
type: index_js_1.KnownClientEventType.InputAudioTurnStart,
|
|
187
188
|
turnId: turnId,
|
|
188
189
|
eventId: this._generateEventId(),
|
|
189
190
|
};
|
|
@@ -197,10 +198,10 @@ class VoiceLiveSession {
|
|
|
197
198
|
this._ensureConnected();
|
|
198
199
|
const targetTurnId = turnId || this._activeTurnId;
|
|
199
200
|
if (!targetTurnId) {
|
|
200
|
-
throw new
|
|
201
|
+
throw new index_js_2.VoiceLiveConnectionError("No active audio turn to end", "INVALID_STATE");
|
|
201
202
|
}
|
|
202
203
|
const endEvent = {
|
|
203
|
-
type:
|
|
204
|
+
type: index_js_1.KnownClientEventType.InputAudioTurnEnd,
|
|
204
205
|
turnId: targetTurnId,
|
|
205
206
|
eventId: this._generateEventId(),
|
|
206
207
|
};
|
|
@@ -215,7 +216,7 @@ class VoiceLiveSession {
|
|
|
215
216
|
async addConversationItem(item, options = {}) {
|
|
216
217
|
this._ensureConnected();
|
|
217
218
|
const createEvent = {
|
|
218
|
-
type:
|
|
219
|
+
type: index_js_1.KnownClientEventType.ConversationItemCreate,
|
|
219
220
|
item: item,
|
|
220
221
|
eventId: this._generateEventId(),
|
|
221
222
|
};
|
|
@@ -351,7 +352,7 @@ class VoiceLiveSession {
|
|
|
351
352
|
}
|
|
352
353
|
_handleServerEvent(event) {
|
|
353
354
|
// Extract session information from events
|
|
354
|
-
if (event.type ===
|
|
355
|
+
if (event.type === index_js_1.KnownServerEventType.SessionCreated && event.session?.id) {
|
|
355
356
|
this._sessionId = event.session.id;
|
|
356
357
|
logger_js_1.logger.info("Session created", { sessionId: this._sessionId });
|
|
357
358
|
}
|
|
@@ -389,7 +390,7 @@ class VoiceLiveSession {
|
|
|
389
390
|
}
|
|
390
391
|
async _sendEvent(event, options) {
|
|
391
392
|
if (!this._connectionManager?.isConnected) {
|
|
392
|
-
throw new
|
|
393
|
+
throw new index_js_2.VoiceLiveConnectionError("Not connected to Voice Live service", "NOT_CONNECTED");
|
|
393
394
|
}
|
|
394
395
|
try {
|
|
395
396
|
const serialized = this._messageParser.serializeOutgoingMessage(event);
|
|
@@ -397,21 +398,21 @@ class VoiceLiveSession {
|
|
|
397
398
|
logger_js_1.logger.info("Sent event", { type: event.type, eventId: event.eventId });
|
|
398
399
|
}
|
|
399
400
|
catch (error) {
|
|
400
|
-
if (error instanceof
|
|
401
|
+
if (error instanceof index_js_2.VoiceLiveConnectionError) {
|
|
401
402
|
throw error;
|
|
402
403
|
}
|
|
403
|
-
throw (0,
|
|
404
|
+
throw (0, index_js_2.classifyConnectionError)(error);
|
|
404
405
|
}
|
|
405
406
|
}
|
|
406
407
|
_ensureConnected() {
|
|
407
408
|
this._ensureNotDisposed();
|
|
408
409
|
if (!this.isConnected) {
|
|
409
|
-
throw new
|
|
410
|
+
throw new index_js_2.VoiceLiveConnectionError("Must be connected to Voice Live service", "NOT_CONNECTED");
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
_ensureNotDisposed() {
|
|
413
414
|
if (this._disposed) {
|
|
414
|
-
throw new
|
|
415
|
+
throw new index_js_2.VoiceLiveConnectionError("Session is permanently dead and cannot be used. Create a new session to continue.", "SESSION_DEAD");
|
|
415
416
|
}
|
|
416
417
|
}
|
|
417
418
|
_generateEventId() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voiceLiveSession.js","sourceRoot":"","sources":["../../src/voiceLiveSession.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { KeyCredential, TokenCredential } from \"@azure/core-auth\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport type {\n RequestSession,\n ClientEventSessionUpdate,\n ClientEventUnion,\n ClientEventInputAudioBufferAppend,\n ClientEventInputAudioTurnStart,\n ClientEventInputAudioTurnAppend,\n ClientEventInputAudioTurnEnd,\n ConversationRequestItem,\n ClientEventConversationItemCreate,\n ServerEventUnion,\n} from \"./models/index.js\";\nimport { ConnectionManager, ConnectionState } from \"./websocket/connectionManager.js\";\nimport { VoiceLiveWebSocketFactory } from \"./websocket/websocketFactory.js\";\nimport { VoiceLiveMessageParser } from \"./protocol/messageParser.js\";\nimport { CredentialHandler } from \"./auth/credentialHandler.js\";\nimport { VoiceLiveConnectionError, classifyConnectionError } from \"./errors/index.js\";\nimport { logger } from \"./logger.js\";\nimport type {\n VoiceLiveSessionHandlers,\n VoiceLiveSubscription,\n ConnectionContext,\n SessionContext,\n ConnectedEventArgs,\n DisconnectedEventArgs,\n ErrorEventArgs,\n} from \"./handlers/sessionHandlers.js\";\nimport { SubscriptionManager } from \"./handlers/subscriptionManager.js\";\n\nexport interface VoiceLiveSessionOptions {\n /** Connection timeout in milliseconds */\n connectionTimeoutInMs?: number;\n /** Enable debug logging for development */\n enableDebugLogging?: boolean;\n}\n\nexport interface CreateSessionOptions extends VoiceLiveSessionOptions {}\n\nexport interface StartSessionOptions extends VoiceLiveSessionOptions {}\nexport interface ConnectOptions {\n /** Abort signal to cancel connection attempt */\n abortSignal?: AbortSignalLike;\n /** Override connection timeout for this operation */\n timeoutInMs?: number;\n}\n\nexport interface SendEventOptions {\n /** Abort signal to cancel send operation */\n abortSignal?: AbortSignalLike;\n /** Timeout for send operation */\n timeoutInMs?: number;\n}\n\nexport interface AudioStreamOptions extends SendEventOptions {\n /** Turn ID for turn-based audio (if not provided, uses buffer mode) */\n turnId?: string;\n}\n\nexport interface TurnOptions extends SendEventOptions {\n /** Custom turn ID (if not provided, one will be generated) */\n turnId?: string;\n}\n\n/**\n * Represents a WebSocket-based session for real-time voice communication with the Azure VoiceLive service.\n *\n * This class manages the connection, handles real-time communication, and provides access to all\n * interactive features including audio streaming, conversation management, and avatar control.\n */\nexport class VoiceLiveSession {\n private readonly _endpoint: string;\n private readonly _credentialHandler: CredentialHandler;\n private readonly _options: Required<VoiceLiveSessionOptions>;\n private readonly _messageParser: VoiceLiveMessageParser;\n private readonly _model: string;\n private _connectionManager?: ConnectionManager;\n private _sessionId?: string;\n private _activeTurnId?: string;\n private _disposed = false;\n\n // Handler-based subscription management\n private readonly _subscriptionManager: SubscriptionManager;\n\n /**\n * Creates an instance of VoiceLiveSession.\n *\n * @param endpoint - The Voice Live service endpoint URL\n * @param credential - Azure TokenCredential or KeyCredential for authentication\n * @param apiVersion - API version to use for the Voice Live service\n * @param model - The model name to use for the session\n * @param options - Optional configuration for the session\n */\n constructor(\n endpoint: string,\n credential: TokenCredential | KeyCredential,\n apiVersion: string,\n model: string,\n options: VoiceLiveSessionOptions = {},\n ) {\n this._endpoint = this._normalizeEndpoint(endpoint);\n this._credentialHandler = new CredentialHandler(credential);\n this._options = this._buildDefaultOptions(options);\n this._messageParser = new VoiceLiveMessageParser();\n this._model = model;\n\n // Initialize handler-based subscription management\n this._subscriptionManager = new SubscriptionManager();\n\n logger.info(\"VoiceLiveSession created\", {\n endpoint: this._endpoint,\n model: this._model,\n apiVersion: apiVersion,\n enableDebugLogging: this._options.enableDebugLogging,\n });\n }\n\n /**\n * Establishes connection to the Voice Live service with authentication.\n */\n async connect(options: ConnectOptions = {}): Promise<void> {\n this._ensureNotDisposed();\n\n if (this.isConnected) {\n logger.info(\"VoiceLiveSession already connected\");\n return;\n }\n\n try {\n logger.info(\"Connecting to Voice Live service\", {\n endpoint: this._endpoint,\n model: this._model,\n });\n\n // Get WebSocket URL with authentication and model\n const wsUrl = await this._credentialHandler.getWebSocketUrl(\n this._endpoint,\n \"2025-10-01\", // TODO: make this configurable through constructor\n this._model,\n );\n const authHeaders = await this._credentialHandler.getAuthHeaders();\n\n // Create connection manager\n const websocketFactory = new VoiceLiveWebSocketFactory();\n this._connectionManager = new ConnectionManager(\n () =>\n websocketFactory.create({\n headers: { ...authHeaders },\n connectionTimeoutInMs: this._options.connectionTimeoutInMs,\n compression: true,\n }),\n {\n endpoint: wsUrl,\n connectionTimeout: options.timeoutInMs || this._options.connectionTimeoutInMs,\n },\n );\n\n // Setup connection event handlers\n this._setupConnectionEventHandlers();\n\n // Connect with proper error handling\n await this._connectionManager.connect(options.abortSignal);\n\n logger.info(\"Successfully connected to Voice Live service\");\n } catch (error) {\n logger.error(\"Failed to connect to Voice Live service\", { error });\n\n // Use error classification\n if (error instanceof VoiceLiveConnectionError) {\n throw error;\n } else {\n throw classifyConnectionError(error);\n }\n }\n }\n\n /**\n * Disconnects from the Voice Live service and cleans up resources.\n */\n async disconnect(): Promise<void> {\n if (!this._connectionManager) {\n return;\n }\n\n logger.info(\"Disconnecting from Voice Live service\");\n\n try {\n await this._connectionManager.disconnect();\n } catch (error) {\n logger.error(\"Error during disconnect\", { error });\n } finally {\n this._connectionManager = undefined;\n this._sessionId = undefined;\n this._activeTurnId = undefined;\n logger.info(\"Disconnected from Voice Live service\");\n }\n }\n\n /**\n * Subscribe to VoiceLive session events using strongly-typed handlers.\n * This follows the Azure SDK pattern used by EventHub, Service Bus, etc.\n *\n * @param handlers - Handler functions for different types of events\n * @returns A subscription object that can be used to stop receiving events\n */\n subscribe(handlers: VoiceLiveSessionHandlers): VoiceLiveSubscription {\n this._ensureNotDisposed();\n\n logger.info(\"Creating VoiceLive session subscription\");\n return this._subscriptionManager.createSubscription(handlers);\n }\n\n /**\n * Sends a custom client event to the service.\n */\n async sendEvent(event: ClientEventUnion, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n await this._sendEvent(event, options);\n }\n\n /**\n * Updates the session configuration with the service.\n */\n async updateSession(session: RequestSession, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n\n const updateEvent: ClientEventSessionUpdate = {\n type: \"session.update\",\n session: session,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(updateEvent, options);\n }\n\n /**\n * Sends audio data to the service using turn-based or buffer-based approach.\n */\n async sendAudio(\n audioData: ArrayBuffer | Uint8Array,\n options: AudioStreamOptions = {},\n ): Promise<void> {\n this._ensureConnected();\n\n const audioBase64 = this._arrayBufferToBase64(audioData);\n\n if (options.turnId) {\n // Turn-based audio\n const appendEvent: ClientEventInputAudioTurnAppend = {\n type: \"input_audio.turn.append\",\n audio: audioBase64,\n turnId: options.turnId,\n eventId: this._generateEventId(),\n };\n await this._sendEvent(appendEvent, options);\n } else {\n // Buffer-based audio (VAD mode)\n const bufferEvent: ClientEventInputAudioBufferAppend = {\n type: \"input_audio_buffer.append\",\n audio: audioBase64,\n eventId: this._generateEventId(),\n };\n await this._sendEvent(bufferEvent, options);\n }\n }\n\n /**\n * Starts a new audio turn for turn-based audio input.\n */\n async startAudioTurn(options: TurnOptions = {}): Promise<string> {\n this._ensureConnected();\n\n const turnId = options.turnId || this._generateTurnId();\n this._activeTurnId = turnId;\n\n const startEvent: ClientEventInputAudioTurnStart = {\n type: \"input_audio.turn.start\",\n turnId: turnId,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(startEvent, options);\n return turnId;\n }\n\n /**\n * Ends the current audio turn.\n */\n async endAudioTurn(turnId?: string, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n\n const targetTurnId = turnId || this._activeTurnId;\n if (!targetTurnId) {\n throw new VoiceLiveConnectionError(\"No active audio turn to end\", \"INVALID_STATE\");\n }\n\n const endEvent: ClientEventInputAudioTurnEnd = {\n type: \"input_audio.turn.end\",\n turnId: targetTurnId,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(endEvent, options);\n\n if (targetTurnId === this._activeTurnId) {\n this._activeTurnId = undefined;\n }\n }\n\n /**\n * Adds a conversation item (message) to the conversation.\n */\n async addConversationItem(\n item: ConversationRequestItem,\n options: SendEventOptions = {},\n ): Promise<void> {\n this._ensureConnected();\n\n const createEvent: ClientEventConversationItemCreate = {\n type: \"conversation.item.create\",\n item: item,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(createEvent, options);\n }\n\n /**\n * Indicates whether the session is currently connected to the Voice Live service.\n */\n get isConnected(): boolean {\n return this._connectionManager?.isConnected || false;\n }\n\n /**\n * Gets the current connection state of the session.\n */\n get connectionState(): ConnectionState {\n return this._connectionManager?.state || ConnectionState.Disconnected;\n }\n\n /**\n * Gets the current session ID.\n */\n get sessionId(): string | undefined {\n return this._sessionId;\n }\n\n /**\n * Gets the current active audio turn ID.\n */\n get activeTurnId(): string | undefined {\n return this._activeTurnId;\n }\n\n /**\n * Disposes the session and cleans up resources.\n */\n async dispose(): Promise<void> {\n if (this._disposed) {\n return;\n }\n\n logger.info(\"Disposing VoiceLiveSession\");\n\n try {\n // Close all subscriptions first\n await this._subscriptionManager.closeAll();\n\n // Then disconnect\n await this.disconnect();\n } catch (error) {\n logger.error(\"Error during session disposal\", { error });\n } finally {\n this._disposed = true;\n logger.info(\"VoiceLiveSession disposed\");\n }\n }\n\n // Private methods\n\n private _buildDefaultOptions(\n options: VoiceLiveSessionOptions,\n ): Required<VoiceLiveSessionOptions> {\n return {\n connectionTimeoutInMs: options.connectionTimeoutInMs || 30000,\n enableDebugLogging: options.enableDebugLogging ?? false,\n };\n }\n\n private _normalizeEndpoint(endpoint: string): string {\n // Ensure endpoint has proper protocol\n if (!endpoint.startsWith(\"http://\") && !endpoint.startsWith(\"https://\")) {\n endpoint = `https://${endpoint}`;\n }\n\n // Remove trailing slash\n return endpoint.replace(/\\/$/, \"\");\n }\n\n private _setupConnectionEventHandlers(): void {\n if (!this._connectionManager) return;\n\n this._connectionManager.updateEventHandlers({\n onStateChange: (state, previousState) => {\n logger.info(\"Connection state changed\", { state, previousState });\n\n // Handle connection state changes for handler-based subscriptions\n if (state === ConnectionState.Connected && previousState === ConnectionState.Connecting) {\n this._notifyConnectionEvent(\"connected\", {\n connectionId: `conn_${Date.now()}`,\n timestamp: new Date(),\n });\n } else if (\n state === ConnectionState.Disconnected &&\n previousState === ConnectionState.Connected\n ) {\n this._notifyConnectionEvent(\"disconnected\", {\n code: 1006, // Abnormal closure\n reason: \"Connection lost during session\",\n wasClean: false,\n timestamp: new Date(),\n });\n this._markSessionAsDead(\n \"Connection lost during session - session is permanently unusable\",\n );\n }\n },\n onMessage: (data) => {\n this._handleIncomingMessage(data);\n },\n onError: (error) => {\n logger.error(\"Connection error - marking session as dead\", { error });\n this._notifyConnectionEvent(\"error\", {\n error: error,\n context: \"WebSocket connection error\",\n recoverable: false,\n timestamp: new Date(),\n });\n this._markSessionAsDead(`Connection error: ${error.message}`);\n },\n });\n }\n\n private _markSessionAsDead(reason: string): void {\n if (this._disposed) return;\n\n logger.error(\"Session marked as permanently dead\", { reason });\n\n // Mark as disposed to prevent further use\n this._disposed = true;\n\n // Clean up connection manager\n this._connectionManager = undefined;\n this._sessionId = undefined;\n this._activeTurnId = undefined;\n }\n\n private _handleIncomingMessage(data: string | ArrayBuffer): void {\n try {\n logger.info(\"Message received\", {\n type: typeof data,\n size: typeof data === \"string\" ? data.length : data.byteLength,\n });\n\n // Parse and process the message\n const parsed = this._messageParser.parseIncomingMessage(data);\n if (parsed && parsed.type === \"server\") {\n // Handle server events\n this._handleServerEvent(parsed.event);\n }\n } catch (error) {\n logger.error(\"Error handling incoming message\", { error });\n }\n }\n\n private _handleServerEvent(event: any): void {\n // Extract session information from events\n if (event.type === \"session.created\" && event.session?.id) {\n this._sessionId = event.session.id;\n logger.info(\"Session created\", { sessionId: this._sessionId });\n }\n\n // Notify handler-based subscriptions\n this._notifyServerEvent(event);\n }\n\n private _notifyConnectionEvent(\n eventType: \"connected\" | \"disconnected\" | \"error\",\n args: ConnectedEventArgs | DisconnectedEventArgs | ErrorEventArgs,\n ): void {\n const context: ConnectionContext = {\n endpoint: this._endpoint,\n sessionId: this._sessionId,\n timestamp: new Date(),\n model: this._model,\n };\n\n // Fire and forget - don't await to avoid blocking\n this._subscriptionManager.processConnectionEvent(eventType, args, context).catch((error) => {\n logger.error(\"Error processing connection event in handlers\", { eventType, error });\n });\n }\n\n private _notifyServerEvent(event: ServerEventUnion): void {\n if (!this._sessionId) {\n // Can't notify server events without a session ID\n return;\n }\n\n const context: SessionContext = {\n endpoint: this._endpoint,\n sessionId: this._sessionId,\n timestamp: new Date(),\n model: this._model,\n conversationId: undefined, // Could extract from event if available\n };\n\n // Fire and forget - don't await to avoid blocking\n this._subscriptionManager.processServerEvent(event, context).catch((error) => {\n logger.error(\"Error processing server event in handlers\", { eventType: event.type, error });\n });\n }\n\n private async _sendEvent(event: ClientEventUnion, options: SendEventOptions): Promise<void> {\n if (!this._connectionManager?.isConnected) {\n throw new VoiceLiveConnectionError(\"Not connected to Voice Live service\", \"NOT_CONNECTED\");\n }\n\n try {\n const serialized = this._messageParser.serializeOutgoingMessage(event);\n await this._connectionManager.send(serialized, options.abortSignal);\n\n logger.info(\"Sent event\", { type: event.type, eventId: (event as any).eventId });\n } catch (error) {\n if (error instanceof VoiceLiveConnectionError) {\n throw error;\n }\n\n throw classifyConnectionError(error);\n }\n }\n\n private _ensureConnected(): void {\n this._ensureNotDisposed();\n if (!this.isConnected) {\n throw new VoiceLiveConnectionError(\n \"Must be connected to Voice Live service\",\n \"NOT_CONNECTED\",\n );\n }\n }\n\n private _ensureNotDisposed(): void {\n if (this._disposed) {\n throw new VoiceLiveConnectionError(\n \"Session is permanently dead and cannot be used. Create a new session to continue.\",\n \"SESSION_DEAD\",\n );\n }\n }\n\n private _generateEventId(): string {\n return `evt_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n }\n\n private _generateTurnId(): string {\n return `turn_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n }\n\n private _arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"voiceLiveSession.js","sourceRoot":"","sources":["../../src/voiceLiveSession.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { KeyCredential, TokenCredential } from \"@azure/core-auth\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport {\n type RequestSession,\n type ClientEventSessionUpdate,\n type ClientEventUnion,\n type ClientEventInputAudioBufferAppend,\n type ClientEventInputAudioTurnStart,\n type ClientEventInputAudioTurnAppend,\n type ClientEventInputAudioTurnEnd,\n type ConversationRequestItem,\n type ClientEventConversationItemCreate,\n type ServerEventUnion,\n KnownClientEventType,\n KnownServerEventType,\n} from \"./models/index.js\";\nimport { ConnectionManager, ConnectionState } from \"./websocket/connectionManager.js\";\nimport { VoiceLiveWebSocketFactory } from \"./websocket/websocketFactory.js\";\nimport { VoiceLiveMessageParser } from \"./protocol/messageParser.js\";\nimport { CredentialHandler } from \"./auth/credentialHandler.js\";\nimport { VoiceLiveConnectionError, classifyConnectionError } from \"./errors/index.js\";\nimport { logger } from \"./logger.js\";\nimport type {\n VoiceLiveSessionHandlers,\n VoiceLiveSubscription,\n ConnectionContext,\n SessionContext,\n ConnectedEventArgs,\n DisconnectedEventArgs,\n ErrorEventArgs,\n} from \"./handlers/sessionHandlers.js\";\nimport { SubscriptionManager } from \"./handlers/subscriptionManager.js\";\n\nexport interface VoiceLiveSessionOptions {\n /** Connection timeout in milliseconds */\n connectionTimeoutInMs?: number;\n /** Enable debug logging for development */\n enableDebugLogging?: boolean;\n}\n\nexport interface CreateSessionOptions extends VoiceLiveSessionOptions {}\n\nexport interface StartSessionOptions extends VoiceLiveSessionOptions {}\nexport interface ConnectOptions {\n /** Abort signal to cancel connection attempt */\n abortSignal?: AbortSignalLike;\n /** Override connection timeout for this operation */\n timeoutInMs?: number;\n}\n\nexport interface SendEventOptions {\n /** Abort signal to cancel send operation */\n abortSignal?: AbortSignalLike;\n /** Timeout for send operation */\n timeoutInMs?: number;\n}\n\nexport interface AudioStreamOptions extends SendEventOptions {\n /** Turn ID for turn-based audio (if not provided, uses buffer mode) */\n turnId?: string;\n}\n\nexport interface TurnOptions extends SendEventOptions {\n /** Custom turn ID (if not provided, one will be generated) */\n turnId?: string;\n}\n\n/**\n * Represents a WebSocket-based session for real-time voice communication with the Azure VoiceLive service.\n *\n * This class manages the connection, handles real-time communication, and provides access to all\n * interactive features including audio streaming, conversation management, and avatar control.\n */\nexport class VoiceLiveSession {\n private readonly _endpoint: string;\n private readonly _credentialHandler: CredentialHandler;\n private readonly _options: Required<VoiceLiveSessionOptions>;\n private readonly _messageParser: VoiceLiveMessageParser;\n private readonly _model: string;\n private readonly _apiVersion: string;\n private _connectionManager?: ConnectionManager;\n private _sessionId?: string;\n private _activeTurnId?: string;\n private _disposed = false;\n // Handler-based subscription management\n private readonly _subscriptionManager: SubscriptionManager;\n\n /**\n * Creates an instance of VoiceLiveSession.\n *\n * @param endpoint - The Voice Live service endpoint URL\n * @param credential - Azure TokenCredential or KeyCredential for authentication\n * @param apiVersion - API version to use for the Voice Live service\n * @param model - The model name to use for the session\n * @param options - Optional configuration for the session\n */\n constructor(\n endpoint: string,\n credential: TokenCredential | KeyCredential,\n apiVersion: string,\n model: string,\n options: VoiceLiveSessionOptions = {},\n ) {\n this._endpoint = this._normalizeEndpoint(endpoint);\n this._credentialHandler = new CredentialHandler(credential);\n this._options = this._buildDefaultOptions(options);\n this._messageParser = new VoiceLiveMessageParser();\n this._model = model;\n this._apiVersion = apiVersion;\n\n // Initialize handler-based subscription management\n this._subscriptionManager = new SubscriptionManager();\n\n logger.info(\"VoiceLiveSession created\", {\n endpoint: this._endpoint,\n model: this._model,\n apiVersion: apiVersion,\n enableDebugLogging: this._options.enableDebugLogging,\n });\n }\n\n /**\n * Establishes connection to the Voice Live service with authentication.\n */\n async connect(options: ConnectOptions = {}): Promise<void> {\n this._ensureNotDisposed();\n\n if (this.isConnected) {\n logger.info(\"VoiceLiveSession already connected\");\n return;\n }\n\n try {\n logger.info(\"Connecting to Voice Live service\", {\n endpoint: this._endpoint,\n model: this._model,\n });\n\n // Get WebSocket URL with authentication and model\n const wsUrl = await this._credentialHandler.getWebSocketUrl(\n this._endpoint,\n this._apiVersion,\n this._model,\n );\n const authHeaders = await this._credentialHandler.getAuthHeaders();\n\n // Create connection manager\n const websocketFactory = new VoiceLiveWebSocketFactory();\n this._connectionManager = new ConnectionManager(\n () =>\n websocketFactory.create({\n headers: { ...authHeaders },\n connectionTimeoutInMs: this._options.connectionTimeoutInMs,\n compression: true,\n }),\n {\n endpoint: wsUrl,\n connectionTimeout: options.timeoutInMs || this._options.connectionTimeoutInMs,\n },\n );\n\n // Setup connection event handlers\n this._setupConnectionEventHandlers();\n\n // Connect with proper error handling\n await this._connectionManager.connect(options.abortSignal);\n\n logger.info(\"Successfully connected to Voice Live service\");\n } catch (error) {\n logger.error(\"Failed to connect to Voice Live service\", { error });\n\n // Use error classification\n if (error instanceof VoiceLiveConnectionError) {\n throw error;\n } else {\n throw classifyConnectionError(error);\n }\n }\n }\n\n /**\n * Disconnects from the Voice Live service and cleans up resources.\n */\n async disconnect(): Promise<void> {\n if (!this._connectionManager) {\n return;\n }\n\n logger.info(\"Disconnecting from Voice Live service\");\n\n try {\n await this._connectionManager.disconnect();\n } catch (error) {\n logger.error(\"Error during disconnect\", { error });\n } finally {\n this._connectionManager = undefined;\n this._sessionId = undefined;\n this._activeTurnId = undefined;\n logger.info(\"Disconnected from Voice Live service\");\n }\n }\n\n /**\n * Subscribe to VoiceLive session events using strongly-typed handlers.\n *\n * @param handlers - Handler functions for different types of events\n * @returns A subscription object that can be used to stop receiving events\n */\n subscribe(handlers: VoiceLiveSessionHandlers): VoiceLiveSubscription {\n this._ensureNotDisposed();\n\n logger.info(\"Creating VoiceLive session subscription\");\n return this._subscriptionManager.createSubscription(handlers);\n }\n\n /**\n * Sends a custom client event to the service.\n */\n async sendEvent(event: ClientEventUnion, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n await this._sendEvent(event, options);\n }\n\n /**\n * Updates the session configuration with the service.\n */\n async updateSession(session: RequestSession, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n\n const updateEvent: ClientEventSessionUpdate = {\n type: KnownClientEventType.SessionUpdate,\n session: session,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(updateEvent, options);\n }\n\n /**\n * Sends audio data to the service using turn-based or buffer-based approach.\n */\n async sendAudio(\n audioData: ArrayBuffer | Uint8Array,\n options: AudioStreamOptions = {},\n ): Promise<void> {\n this._ensureConnected();\n\n const audioBase64 = this._arrayBufferToBase64(audioData);\n\n if (options.turnId) {\n // Turn-based audio\n const appendEvent: ClientEventInputAudioTurnAppend = {\n type: KnownClientEventType.InputAudioTurnAppend,\n audio: audioBase64,\n turnId: options.turnId,\n eventId: this._generateEventId(),\n };\n await this._sendEvent(appendEvent, options);\n } else {\n // Buffer-based audio (VAD mode)\n const bufferEvent: ClientEventInputAudioBufferAppend = {\n type: KnownClientEventType.InputAudioBufferAppend,\n audio: audioBase64,\n eventId: this._generateEventId(),\n };\n await this._sendEvent(bufferEvent, options);\n }\n }\n\n /**\n * Starts a new audio turn for turn-based audio input.\n */\n async startAudioTurn(options: TurnOptions = {}): Promise<string> {\n this._ensureConnected();\n\n const turnId = options.turnId || this._generateTurnId();\n this._activeTurnId = turnId;\n\n const startEvent: ClientEventInputAudioTurnStart = {\n type: KnownClientEventType.InputAudioTurnStart,\n turnId: turnId,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(startEvent, options);\n return turnId;\n }\n\n /**\n * Ends the current audio turn.\n */\n async endAudioTurn(turnId?: string, options: SendEventOptions = {}): Promise<void> {\n this._ensureConnected();\n\n const targetTurnId = turnId || this._activeTurnId;\n if (!targetTurnId) {\n throw new VoiceLiveConnectionError(\"No active audio turn to end\", \"INVALID_STATE\");\n }\n\n const endEvent: ClientEventInputAudioTurnEnd = {\n type: KnownClientEventType.InputAudioTurnEnd,\n turnId: targetTurnId,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(endEvent, options);\n\n if (targetTurnId === this._activeTurnId) {\n this._activeTurnId = undefined;\n }\n }\n\n /**\n * Adds a conversation item (message) to the conversation.\n */\n async addConversationItem(\n item: ConversationRequestItem,\n options: SendEventOptions = {},\n ): Promise<void> {\n this._ensureConnected();\n\n const createEvent: ClientEventConversationItemCreate = {\n type: KnownClientEventType.ConversationItemCreate,\n item: item,\n eventId: this._generateEventId(),\n };\n\n await this._sendEvent(createEvent, options);\n }\n\n /**\n * Indicates whether the session is currently connected to the Voice Live service.\n */\n get isConnected(): boolean {\n return this._connectionManager?.isConnected || false;\n }\n\n /**\n * Gets the current connection state of the session.\n */\n get connectionState(): ConnectionState {\n return this._connectionManager?.state || ConnectionState.Disconnected;\n }\n\n /**\n * Gets the current session ID.\n */\n get sessionId(): string | undefined {\n return this._sessionId;\n }\n\n /**\n * Gets the current active audio turn ID.\n */\n get activeTurnId(): string | undefined {\n return this._activeTurnId;\n }\n\n /**\n * Disposes the session and cleans up resources.\n */\n async dispose(): Promise<void> {\n if (this._disposed) {\n return;\n }\n\n logger.info(\"Disposing VoiceLiveSession\");\n\n try {\n // Close all subscriptions first\n await this._subscriptionManager.closeAll();\n\n // Then disconnect\n await this.disconnect();\n } catch (error) {\n logger.error(\"Error during session disposal\", { error });\n } finally {\n this._disposed = true;\n logger.info(\"VoiceLiveSession disposed\");\n }\n }\n\n // Private methods\n\n private _buildDefaultOptions(\n options: VoiceLiveSessionOptions,\n ): Required<VoiceLiveSessionOptions> {\n return {\n connectionTimeoutInMs: options.connectionTimeoutInMs || 30000,\n enableDebugLogging: options.enableDebugLogging ?? false,\n };\n }\n\n private _normalizeEndpoint(endpoint: string): string {\n // Ensure endpoint has proper protocol\n if (!endpoint.startsWith(\"http://\") && !endpoint.startsWith(\"https://\")) {\n endpoint = `https://${endpoint}`;\n }\n\n // Remove trailing slash\n return endpoint.replace(/\\/$/, \"\");\n }\n\n private _setupConnectionEventHandlers(): void {\n if (!this._connectionManager) return;\n\n this._connectionManager.updateEventHandlers({\n onStateChange: (state, previousState) => {\n logger.info(\"Connection state changed\", { state, previousState });\n\n // Handle connection state changes for handler-based subscriptions\n if (state === ConnectionState.Connected && previousState === ConnectionState.Connecting) {\n this._notifyConnectionEvent(\"connected\", {\n connectionId: `conn_${Date.now()}`,\n timestamp: new Date(),\n });\n } else if (\n state === ConnectionState.Disconnected &&\n previousState === ConnectionState.Connected\n ) {\n this._notifyConnectionEvent(\"disconnected\", {\n code: 1006, // Abnormal closure\n reason: \"Connection lost during session\",\n wasClean: false,\n timestamp: new Date(),\n });\n this._markSessionAsDead(\n \"Connection lost during session - session is permanently unusable\",\n );\n }\n },\n onMessage: (data) => {\n this._handleIncomingMessage(data);\n },\n onError: (error) => {\n logger.error(\"Connection error - marking session as dead\", { error });\n this._notifyConnectionEvent(\"error\", {\n error: error,\n context: \"WebSocket connection error\",\n recoverable: false,\n timestamp: new Date(),\n });\n this._markSessionAsDead(`Connection error: ${error.message}`);\n },\n });\n }\n\n private _markSessionAsDead(reason: string): void {\n if (this._disposed) return;\n\n logger.error(\"Session marked as permanently dead\", { reason });\n\n // Mark as disposed to prevent further use\n this._disposed = true;\n\n // Clean up connection manager\n this._connectionManager = undefined;\n this._sessionId = undefined;\n this._activeTurnId = undefined;\n }\n\n private _handleIncomingMessage(data: string | ArrayBuffer): void {\n try {\n logger.info(\"Message received\", {\n type: typeof data,\n size: typeof data === \"string\" ? data.length : data.byteLength,\n });\n\n // Parse and process the message\n const parsed = this._messageParser.parseIncomingMessage(data);\n if (parsed && parsed.type === \"server\") {\n // Handle server events\n this._handleServerEvent(parsed.event);\n }\n } catch (error) {\n logger.error(\"Error handling incoming message\", { error });\n }\n }\n\n private _handleServerEvent(event: any): void {\n // Extract session information from events\n if (event.type === KnownServerEventType.SessionCreated && event.session?.id) {\n this._sessionId = event.session.id;\n logger.info(\"Session created\", { sessionId: this._sessionId });\n }\n\n // Notify handler-based subscriptions\n this._notifyServerEvent(event);\n }\n\n private _notifyConnectionEvent(\n eventType: \"connected\" | \"disconnected\" | \"error\",\n args: ConnectedEventArgs | DisconnectedEventArgs | ErrorEventArgs,\n ): void {\n const context: ConnectionContext = {\n endpoint: this._endpoint,\n sessionId: this._sessionId,\n timestamp: new Date(),\n model: this._model,\n };\n\n // Fire and forget - don't await to avoid blocking\n this._subscriptionManager.processConnectionEvent(eventType, args, context).catch((error) => {\n logger.error(\"Error processing connection event in handlers\", { eventType, error });\n });\n }\n\n private _notifyServerEvent(event: ServerEventUnion): void {\n if (!this._sessionId) {\n // Can't notify server events without a session ID\n return;\n }\n\n const context: SessionContext = {\n endpoint: this._endpoint,\n sessionId: this._sessionId,\n timestamp: new Date(),\n model: this._model,\n conversationId: undefined, // Could extract from event if available\n };\n\n // Fire and forget - don't await to avoid blocking\n this._subscriptionManager.processServerEvent(event, context).catch((error) => {\n logger.error(\"Error processing server event in handlers\", { eventType: event.type, error });\n });\n }\n\n private async _sendEvent(event: ClientEventUnion, options: SendEventOptions): Promise<void> {\n if (!this._connectionManager?.isConnected) {\n throw new VoiceLiveConnectionError(\"Not connected to Voice Live service\", \"NOT_CONNECTED\");\n }\n\n try {\n const serialized = this._messageParser.serializeOutgoingMessage(event);\n await this._connectionManager.send(serialized, options.abortSignal);\n\n logger.info(\"Sent event\", { type: event.type, eventId: (event as any).eventId });\n } catch (error) {\n if (error instanceof VoiceLiveConnectionError) {\n throw error;\n }\n\n throw classifyConnectionError(error);\n }\n }\n\n private _ensureConnected(): void {\n this._ensureNotDisposed();\n if (!this.isConnected) {\n throw new VoiceLiveConnectionError(\n \"Must be connected to Voice Live service\",\n \"NOT_CONNECTED\",\n );\n }\n }\n\n private _ensureNotDisposed(): void {\n if (this._disposed) {\n throw new VoiceLiveConnectionError(\n \"Session is permanently dead and cannot be used. Create a new session to continue.\",\n \"SESSION_DEAD\",\n );\n }\n }\n\n private _generateEventId(): string {\n return `evt_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n }\n\n private _generateTurnId(): string {\n return `turn_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n }\n\n private _arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { WebSocketState, type VoiceLiveWebSocketLike, type WebSocketFactoryOptio
|
|
|
3
3
|
/**
|
|
4
4
|
* Node.js WebSocket implementation using 'ws' library
|
|
5
5
|
*/
|
|
6
|
-
export declare class
|
|
6
|
+
export declare class VoiceLiveWebSocket implements VoiceLiveWebSocketLike {
|
|
7
7
|
private _ws?;
|
|
8
8
|
private _url?;
|
|
9
9
|
private _options;
|
|
@@ -23,4 +23,4 @@ export declare class VoiceLiveWebSocketNode implements VoiceLiveWebSocketLike {
|
|
|
23
23
|
get readyState(): WebSocketState;
|
|
24
24
|
get url(): string | undefined;
|
|
25
25
|
}
|
|
26
|
-
//# sourceMappingURL=
|
|
26
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
// Copyright (c) Microsoft Corporation.
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.
|
|
5
|
+
exports.VoiceLiveWebSocket = void 0;
|
|
6
6
|
const tslib_1 = require("tslib");
|
|
7
7
|
const ws_1 = tslib_1.__importDefault(require("ws"));
|
|
8
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
9
|
+
const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
|
|
8
10
|
const websocketLike_js_1 = require("./websocketLike.js");
|
|
9
11
|
const connectionErrors_js_1 = require("../errors/connectionErrors.js");
|
|
10
12
|
/**
|
|
11
13
|
* Node.js WebSocket implementation using 'ws' library
|
|
12
14
|
*/
|
|
13
|
-
class
|
|
15
|
+
class VoiceLiveWebSocket {
|
|
14
16
|
_ws;
|
|
15
17
|
_url;
|
|
16
18
|
_options;
|
|
@@ -50,11 +52,34 @@ class VoiceLiveWebSocketNode {
|
|
|
50
52
|
abortSignal.addEventListener("abort", abortHandler);
|
|
51
53
|
}
|
|
52
54
|
try {
|
|
53
|
-
|
|
55
|
+
const wsOptions = {
|
|
54
56
|
headers: this._options.headers,
|
|
55
57
|
maxPayload: this._options.maxMessageSize,
|
|
56
58
|
perMessageDeflate: this._options.compression,
|
|
57
|
-
}
|
|
59
|
+
};
|
|
60
|
+
// Detect proxy settings from environment variables (HTTPS_PROXY, HTTP_PROXY)
|
|
61
|
+
const proxySettings = (0, core_rest_pipeline_1.getDefaultProxySettings)();
|
|
62
|
+
if (proxySettings) {
|
|
63
|
+
const { host, port, username, password } = proxySettings;
|
|
64
|
+
// Build proxy URL with authentication if provided
|
|
65
|
+
let proxyUrl = host;
|
|
66
|
+
if (!proxyUrl.includes("://")) {
|
|
67
|
+
proxyUrl = `http://${proxyUrl}`;
|
|
68
|
+
}
|
|
69
|
+
// Remove trailing slash if present
|
|
70
|
+
proxyUrl = proxyUrl.replace(/\/$/, "");
|
|
71
|
+
// Add port
|
|
72
|
+
proxyUrl = `${proxyUrl}:${port}`;
|
|
73
|
+
// Add authentication if provided
|
|
74
|
+
if (username && password) {
|
|
75
|
+
const pUrl = new URL(proxyUrl);
|
|
76
|
+
pUrl.username = username;
|
|
77
|
+
pUrl.password = password;
|
|
78
|
+
proxyUrl = pUrl.toString();
|
|
79
|
+
}
|
|
80
|
+
wsOptions.agent = new https_proxy_agent_1.HttpsProxyAgent(proxyUrl);
|
|
81
|
+
}
|
|
82
|
+
this._ws = new ws_1.default(url, protocols, wsOptions);
|
|
58
83
|
this._url = url;
|
|
59
84
|
this._ws.on("open", () => {
|
|
60
85
|
clearTimeout(timeoutId);
|
|
@@ -181,5 +206,5 @@ class VoiceLiveWebSocketNode {
|
|
|
181
206
|
return this._url;
|
|
182
207
|
}
|
|
183
208
|
}
|
|
184
|
-
exports.
|
|
185
|
-
//# sourceMappingURL=
|
|
209
|
+
exports.VoiceLiveWebSocket = VoiceLiveWebSocket;
|
|
210
|
+
//# sourceMappingURL=websocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/websocket/websocket.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport WebSocket from \"ws\";\nimport { HttpsProxyAgent } from \"https-proxy-agent\";\nimport { getDefaultProxySettings } from \"@azure/core-rest-pipeline\";\nimport {\n WebSocketState,\n type VoiceLiveWebSocketLike,\n type WebSocketFactoryOptions,\n} from \"./websocketLike.js\";\nimport { VoiceLiveConnectionError, VoiceLiveErrorCodes } from \"../errors/connectionErrors.js\";\n\n/**\n * Node.js WebSocket implementation using 'ws' library\n */\nexport class VoiceLiveWebSocket implements VoiceLiveWebSocketLike {\n private _ws?: WebSocket;\n private _url?: string;\n private _options: WebSocketFactoryOptions;\n\n private _onOpen?: () => void;\n private _onClose?: (code: number, reason: string) => void;\n private _onMessage?: (data: string | ArrayBuffer) => void;\n private _onError?: (error: Error) => void;\n\n constructor(options: WebSocketFactoryOptions = {}) {\n this._options = {\n connectionTimeoutInMs: 30000,\n maxMessageSize: 1024 * 1024, // 1MB\n compression: true,\n ...options,\n };\n }\n\n async connect(url: string, protocols?: string[], abortSignal?: AbortSignalLike): Promise<void> {\n if (this._ws && this._ws.readyState !== WebSocket.CLOSED) {\n throw new VoiceLiveConnectionError(\n \"WebSocket is already connected or connecting\",\n VoiceLiveErrorCodes.AlreadyConnected,\n );\n }\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new VoiceLiveConnectionError(\n `WebSocket connection timeout after ${this._options.connectionTimeoutInMs}ms`,\n VoiceLiveErrorCodes.ConnectionTimeout,\n ),\n );\n }, this._options.connectionTimeoutInMs);\n\n // Handle abort signal\n const abortHandler = (): void => {\n clearTimeout(timeoutId);\n if (this._ws) {\n this._ws.terminate();\n }\n reject(\n new VoiceLiveConnectionError(\n \"WebSocket connection aborted\",\n VoiceLiveErrorCodes.OperationCancelled,\n ),\n );\n };\n\n if (abortSignal) {\n if (abortSignal.aborted) {\n abortHandler();\n return;\n }\n abortSignal.addEventListener(\"abort\", abortHandler);\n }\n\n try {\n const wsOptions: WebSocket.ClientOptions = {\n headers: this._options.headers,\n maxPayload: this._options.maxMessageSize,\n perMessageDeflate: this._options.compression,\n };\n\n // Detect proxy settings from environment variables (HTTPS_PROXY, HTTP_PROXY)\n const proxySettings = getDefaultProxySettings();\n if (proxySettings) {\n const { host, port, username, password } = proxySettings;\n\n // Build proxy URL with authentication if provided\n let proxyUrl = host;\n if (!proxyUrl.includes(\"://\")) {\n proxyUrl = `http://${proxyUrl}`;\n }\n\n // Remove trailing slash if present\n proxyUrl = proxyUrl.replace(/\\/$/, \"\");\n\n // Add port\n proxyUrl = `${proxyUrl}:${port}`;\n\n // Add authentication if provided\n if (username && password) {\n const pUrl = new URL(proxyUrl);\n pUrl.username = username;\n pUrl.password = password;\n proxyUrl = pUrl.toString();\n }\n\n wsOptions.agent = new HttpsProxyAgent(proxyUrl);\n }\n\n this._ws = new WebSocket(url, protocols, wsOptions);\n\n this._url = url;\n\n this._ws.on(\"open\", () => {\n clearTimeout(timeoutId);\n if (abortSignal) {\n abortSignal.removeEventListener(\"abort\", abortHandler);\n }\n this._onOpen?.();\n resolve();\n });\n\n this._ws.on(\"close\", (code: number, reason: Buffer) => {\n clearTimeout(timeoutId);\n if (abortSignal) {\n abortSignal.removeEventListener(\"abort\", abortHandler);\n }\n this._onClose?.(code, reason.toString());\n });\n\n this._ws.on(\"message\", (data: WebSocket.Data) => {\n if (typeof data === \"string\") {\n this._onMessage?.(data);\n } else if (data instanceof Buffer) {\n // Convert Buffer to ArrayBuffer\n const arrayBuffer = new ArrayBuffer(data.length);\n const view = new Uint8Array(arrayBuffer);\n view.set(data);\n this._onMessage?.(arrayBuffer);\n } else if (data instanceof ArrayBuffer) {\n this._onMessage?.(data);\n } else {\n // Handle other data types by converting to ArrayBuffer\n const buffer = Buffer.from(data as any);\n const arrayBuffer = new ArrayBuffer(buffer.length);\n const view = new Uint8Array(arrayBuffer);\n view.set(buffer);\n this._onMessage?.(arrayBuffer);\n }\n });\n\n this._ws.on(\"error\", (error: Error) => {\n clearTimeout(timeoutId);\n if (abortSignal) {\n abortSignal.removeEventListener(\"abort\", abortHandler);\n }\n this._onError?.(error);\n reject(\n new VoiceLiveConnectionError(\n `WebSocket error: ${error.message}`,\n VoiceLiveErrorCodes.WebSocketError,\n \"websocket_connection\",\n true, // Potentially recoverable\n error,\n ),\n );\n });\n } catch (error) {\n clearTimeout(timeoutId);\n if (abortSignal) {\n abortSignal.removeEventListener(\"abort\", abortHandler);\n }\n reject(\n new VoiceLiveConnectionError(\n `Failed to create WebSocket: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n VoiceLiveErrorCodes.ConnectionFailed,\n \"websocket_creation\",\n false,\n error instanceof Error ? error : new Error(String(error)),\n ),\n );\n }\n });\n }\n\n async disconnect(code: number = 1000, reason?: string): Promise<void> {\n if (!this._ws || this._ws.readyState === WebSocket.CLOSED) {\n return;\n }\n\n return new Promise((resolve) => {\n const closeHandler = (): void => {\n resolve();\n };\n\n if (this._ws!.readyState === WebSocket.CLOSING) {\n this._ws!.once(\"close\", closeHandler);\n } else {\n this._ws!.once(\"close\", closeHandler);\n this._ws!.close(code, reason);\n }\n });\n }\n\n async send(data: string | ArrayBuffer, abortSignal?: AbortSignalLike): Promise<void> {\n if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n throw new VoiceLiveConnectionError(\n \"WebSocket is not connected\",\n VoiceLiveErrorCodes.NotConnected,\n );\n }\n\n if (abortSignal?.aborted) {\n throw new VoiceLiveConnectionError(\n \"Send operation aborted\",\n VoiceLiveErrorCodes.OperationCancelled,\n );\n }\n\n return new Promise((resolve, reject) => {\n const abortHandler = (): void => {\n reject(\n new VoiceLiveConnectionError(\n \"Send operation aborted\",\n VoiceLiveErrorCodes.OperationCancelled,\n ),\n );\n };\n\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", abortHandler);\n }\n\n this._ws!.send(data, (error?: Error) => {\n if (abortSignal) {\n abortSignal.removeEventListener(\"abort\", abortHandler);\n }\n\n if (error) {\n reject(\n new VoiceLiveConnectionError(\n `Failed to send WebSocket message: ${error.message}`,\n VoiceLiveErrorCodes.WebSocketError,\n \"message_send\",\n true,\n error,\n ),\n );\n } else {\n resolve();\n }\n });\n });\n }\n\n onOpen(handler: () => void): void {\n this._onOpen = handler;\n }\n\n onClose(handler: (code: number, reason: string) => void): void {\n this._onClose = handler;\n }\n\n onMessage(handler: (data: string | ArrayBuffer) => void): void {\n this._onMessage = handler;\n }\n\n onError(handler: (error: Error) => void): void {\n this._onError = handler;\n }\n\n get isConnected(): boolean {\n return this._ws?.readyState === WebSocket.OPEN;\n }\n\n get readyState(): WebSocketState {\n if (!this._ws) return WebSocketState.Closed;\n return this._ws.readyState as WebSocketState;\n }\n\n get url(): string | undefined {\n return this._url;\n }\n}\n"]}
|