@livekit/agents 1.0.5 → 1.0.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.
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/inference/api_protos.cjs +104 -0
- package/dist/inference/api_protos.cjs.map +1 -0
- package/dist/inference/api_protos.d.cts +222 -0
- package/dist/inference/api_protos.d.ts +222 -0
- package/dist/inference/api_protos.d.ts.map +1 -0
- package/dist/inference/api_protos.js +70 -0
- package/dist/inference/api_protos.js.map +1 -0
- package/dist/inference/index.cjs +56 -0
- package/dist/inference/index.cjs.map +1 -0
- package/dist/inference/index.d.cts +8 -0
- package/dist/inference/index.d.ts +8 -0
- package/dist/inference/index.d.ts.map +1 -0
- package/dist/inference/index.js +23 -0
- package/dist/inference/index.js.map +1 -0
- package/dist/inference/llm.cjs +299 -0
- package/dist/inference/llm.cjs.map +1 -0
- package/dist/inference/llm.d.cts +107 -0
- package/dist/inference/llm.d.ts +107 -0
- package/dist/inference/llm.d.ts.map +1 -0
- package/dist/inference/llm.js +270 -0
- package/dist/inference/llm.js.map +1 -0
- package/dist/inference/stt.cjs +313 -0
- package/dist/inference/stt.cjs.map +1 -0
- package/dist/inference/stt.d.cts +87 -0
- package/dist/inference/stt.d.ts +87 -0
- package/dist/inference/stt.d.ts.map +1 -0
- package/dist/inference/stt.js +292 -0
- package/dist/inference/stt.js.map +1 -0
- package/dist/inference/tts.cjs +324 -0
- package/dist/inference/tts.cjs.map +1 -0
- package/dist/inference/tts.d.cts +77 -0
- package/dist/inference/tts.d.ts +77 -0
- package/dist/inference/tts.d.ts.map +1 -0
- package/dist/inference/tts.js +306 -0
- package/dist/inference/tts.js.map +1 -0
- package/dist/inference/utils.cjs +76 -0
- package/dist/inference/utils.cjs.map +1 -0
- package/dist/inference/utils.d.cts +5 -0
- package/dist/inference/utils.d.ts +5 -0
- package/dist/inference/utils.d.ts.map +1 -0
- package/dist/inference/utils.js +51 -0
- package/dist/inference/utils.js.map +1 -0
- package/dist/llm/remote_chat_context.cjs.map +1 -1
- package/dist/llm/remote_chat_context.d.cts +2 -0
- package/dist/llm/remote_chat_context.d.ts +2 -0
- package/dist/llm/remote_chat_context.d.ts.map +1 -1
- package/dist/llm/remote_chat_context.js.map +1 -1
- package/dist/tts/tts.cjs +1 -1
- package/dist/tts/tts.cjs.map +1 -1
- package/dist/tts/tts.js +1 -1
- package/dist/tts/tts.js.map +1 -1
- package/dist/utils.cjs +11 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -0
- package/dist/utils.js.map +1 -1
- package/dist/voice/agent.cjs +16 -3
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +5 -3
- package/dist/voice/agent.d.ts +5 -3
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +20 -3
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent_activity.cjs +4 -2
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +4 -2
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +16 -3
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +4 -3
- package/dist/voice/agent_session.d.ts +4 -3
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +20 -3
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/events.cjs +2 -0
- package/dist/voice/events.cjs.map +1 -1
- package/dist/voice/events.d.cts +4 -1
- package/dist/voice/events.d.ts +4 -1
- package/dist/voice/events.d.ts.map +1 -1
- package/dist/voice/events.js +2 -0
- package/dist/voice/events.js.map +1 -1
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.cts +1 -0
- package/dist/voice/generation.d.ts +1 -0
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js.map +1 -1
- package/dist/voice/room_io/_input.cjs +9 -0
- package/dist/voice/room_io/_input.cjs.map +1 -1
- package/dist/voice/room_io/_input.d.ts.map +1 -1
- package/dist/voice/room_io/_input.js +10 -0
- package/dist/voice/room_io/_input.js.map +1 -1
- package/dist/voice/room_io/_output.cjs +1 -1
- package/dist/voice/room_io/_output.cjs.map +1 -1
- package/dist/voice/room_io/_output.d.cts +1 -0
- package/dist/voice/room_io/_output.d.ts +1 -0
- package/dist/voice/room_io/_output.d.ts.map +1 -1
- package/dist/voice/room_io/_output.js +1 -1
- package/dist/voice/room_io/_output.js.map +1 -1
- package/dist/voice/room_io/room_io.cjs +1 -1
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.cts +20 -0
- package/dist/voice/room_io/room_io.d.ts +20 -0
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +1 -1
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/dist/voice/transcription/synchronizer.cjs +1 -1
- package/dist/voice/transcription/synchronizer.cjs.map +1 -1
- package/dist/voice/transcription/synchronizer.d.cts +1 -0
- package/dist/voice/transcription/synchronizer.d.ts +1 -0
- package/dist/voice/transcription/synchronizer.d.ts.map +1 -1
- package/dist/voice/transcription/synchronizer.js +1 -1
- package/dist/voice/transcription/synchronizer.js.map +1 -1
- package/dist/worker.cjs +3 -3
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +3 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +4 -4
- package/dist/worker.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +2 -1
- package/src/inference/api_protos.ts +82 -0
- package/src/inference/index.ts +32 -0
- package/src/inference/llm.ts +463 -0
- package/src/inference/stt.ts +444 -0
- package/src/inference/tts.ts +432 -0
- package/src/inference/utils.ts +66 -0
- package/src/llm/remote_chat_context.ts +2 -2
- package/src/tts/tts.ts +1 -1
- package/src/utils.ts +11 -0
- package/src/voice/agent.ts +31 -7
- package/src/voice/agent_activity.ts +2 -0
- package/src/voice/agent_session.ts +30 -6
- package/src/voice/events.ts +6 -0
- package/src/voice/generation.ts +1 -1
- package/src/voice/room_io/_input.ts +12 -1
- package/src/voice/room_io/_output.ts +1 -1
- package/src/voice/room_io/room_io.ts +21 -2
- package/src/voice/transcription/synchronizer.ts +1 -1
- package/src/worker.ts +5 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/voice/generation.ts"],"names":[],"mappings":";AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,YAAY,CAAC;AAE9E,OAAO,EACL,KAAK,WAAW,EAEhB,YAAY,EACZ,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,UAAU,EACf,KAAK,WAAW,EAIjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAsB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,aAAa,EAAqC,MAAM,YAAY,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/voice/generation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/generation.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { AudioResampler } from '@livekit/rtc-node';\nimport type { ReadableStream, ReadableStreamDefaultReader } from 'stream/web';\nimport { ZodObject } from 'zod';\nimport {\n type ChatContext,\n ChatMessage,\n FunctionCall,\n FunctionCallOutput,\n} from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport {\n type ToolChoice,\n type ToolContext,\n isAgentHandoff,\n isFunctionTool,\n isToolError,\n} from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { Future, Task, shortuuid, toError } from '../utils.js';\nimport { type Agent, type ModelSettings, asyncLocalStorage, isStopResponse } from './agent.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { AudioOutput, LLMNode, TTSNode, TextOutput } from './io.js';\nimport { RunContext } from './run_context.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\n/* @internal */\nexport class _LLMGenerationData {\n generatedText: string = '';\n generatedToolCalls: FunctionCall[];\n id: string;\n\n constructor(\n public readonly textStream: ReadableStream<string>,\n public readonly toolCallStream: ReadableStream<FunctionCall>,\n ) {\n this.id = shortuuid('item_');\n this.generatedToolCalls = [];\n }\n}\n\n// TODO(brian): remove this class in favor of ToolOutput\nexport class _ToolOutput {\n output: _JsOutput[];\n firstToolFut: Future;\n\n constructor() {\n this.output = [];\n this.firstToolFut = new Future();\n }\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _SanitizedOutput {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n replyRequired: boolean;\n agentTask?: Agent;\n\n constructor(\n toolCall: FunctionCall,\n toolCallOutput: FunctionCallOutput | undefined,\n replyRequired: boolean,\n agentTask: Agent | undefined,\n ) {\n this.toolCall = toolCall;\n this.toolCallOutput = toolCallOutput;\n this.replyRequired = replyRequired;\n this.agentTask = agentTask;\n }\n\n static create(params: {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n replyRequired?: boolean;\n agentTask?: Agent;\n }) {\n const { toolCall, toolCallOutput, replyRequired = true, agentTask } = params;\n return new _SanitizedOutput(toolCall, toolCallOutput, replyRequired, agentTask);\n }\n}\n\nfunction isValidToolOutput(toolOutput: unknown): boolean {\n const validTypes = ['string', 'number', 'boolean'];\n\n if (validTypes.includes(typeof toolOutput)) {\n return true;\n }\n\n if (toolOutput === undefined || toolOutput === null) {\n return true;\n }\n\n if (Array.isArray(toolOutput)) {\n return toolOutput.every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Set) {\n return Array.from(toolOutput).every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Map) {\n return Array.from(toolOutput.values()).every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Object) {\n return Object.entries(toolOutput).every(\n ([key, value]) => validTypes.includes(typeof key) && isValidToolOutput(value),\n );\n }\n\n return false;\n}\n\nexport class ToolExecutionOutput {\n constructor(\n public readonly toolCall: FunctionCall,\n public readonly toolCallOutput: FunctionCallOutput | undefined,\n public readonly agentTask: Agent | undefined,\n public readonly rawOutput: unknown,\n public readonly rawException: Error | undefined,\n public readonly replyRequired: boolean,\n ) {}\n\n static create(params: {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n agentTask?: Agent;\n rawOutput: unknown;\n rawException?: Error;\n replyRequired?: boolean;\n }) {\n const {\n toolCall,\n toolCallOutput,\n agentTask,\n rawOutput,\n rawException,\n replyRequired = true,\n } = params;\n return new ToolExecutionOutput(\n toolCall,\n toolCallOutput,\n agentTask,\n rawOutput,\n rawException,\n replyRequired,\n );\n }\n}\n\nexport interface ToolOutput {\n output: ToolExecutionOutput[];\n firstToolStartedFuture: Future<void>;\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _JsOutput {\n toolCall: FunctionCall;\n output: unknown;\n exception?: Error;\n\n #logger = log();\n\n constructor(toolCall: FunctionCall, output: unknown, exception: Error | undefined) {\n this.toolCall = toolCall;\n this.output = output;\n this.exception = exception;\n }\n\n static create(params: { toolCall: FunctionCall; output?: unknown; exception?: Error }) {\n const { toolCall, output = undefined, exception = undefined } = params;\n return new _JsOutput(toolCall, output, exception);\n }\n\n sanitize(): _SanitizedOutput {\n if (isToolError(this.exception)) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: this.exception.message,\n isError: true,\n }),\n });\n }\n\n if (isStopResponse(this.exception)) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n });\n }\n\n if (this.exception !== undefined) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: 'An internal error occurred while executing the tool.', // Don't send the actual error message, as it may contain sensitive information\n isError: true,\n }),\n });\n }\n\n let agentTask: Agent | undefined = undefined;\n let toolOutput: unknown = this.output;\n if (isAgentHandoff(this.output)) {\n agentTask = this.output.agent;\n toolOutput = this.output.returns;\n }\n\n if (!isValidToolOutput(toolOutput)) {\n this.#logger.error(\n {\n callId: this.toolCall.callId,\n function: this.toolCall.name,\n },\n `AI function ${this.toolCall.name} returned an invalid output`,\n );\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: undefined,\n });\n }\n\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n isError: false,\n }),\n replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n agentTask,\n });\n }\n}\n\nexport function createToolOutput(params: {\n toolCall: FunctionCall;\n output?: unknown;\n exception?: Error;\n}): ToolExecutionOutput {\n const { toolCall, output, exception } = params;\n const logger = log();\n\n // support returning Exception instead of raising them (for devex purposes inside evals)\n let finalOutput = output;\n let finalException = exception;\n if (output instanceof Error) {\n finalException = output;\n finalOutput = undefined;\n }\n\n if (isToolError(finalException)) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: finalException.message,\n isError: true,\n }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n if (isStopResponse(finalException)) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n if (finalException !== undefined) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: 'An internal error occurred', // Don't send the actual error message, as it may contain sensitive information\n isError: true,\n }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n let agentTask: Agent | undefined = undefined;\n let toolOutput: unknown = finalOutput;\n if (isAgentHandoff(finalOutput)) {\n agentTask = finalOutput.agent;\n toolOutput = finalOutput.returns;\n }\n\n if (!isValidToolOutput(toolOutput)) {\n logger.error(\n {\n callId: toolCall.callId,\n output: finalOutput,\n },\n `AI function ${toolCall.name} returned an invalid output`,\n );\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n isError: false,\n }),\n replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n agentTask,\n rawOutput: finalOutput,\n rawException: finalException,\n });\n}\n\nconst INSTRUCTIONS_MESSAGE_ID = 'lk.agent_task.instructions';\n\n/**\n * Update the instruction message in the chat context or insert a new one if missing.\n *\n * This function looks for an existing instruction message in the chat context using the identifier\n * 'INSTRUCTIONS_MESSAGE_ID'.\n *\n * @param options - The options for updating the instructions.\n * @param options.chatCtx - The chat context to update.\n * @param options.instructions - The instructions to add.\n * @param options.addIfMissing - Whether to add the instructions if they are missing.\n */\nexport function updateInstructions(options: {\n chatCtx: ChatContext;\n instructions: string;\n addIfMissing: boolean;\n}) {\n const { chatCtx, instructions, addIfMissing } = options;\n\n const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n if (idx !== undefined) {\n if (chatCtx.items[idx]!.type === 'message') {\n // create a new instance to avoid mutating the original\n chatCtx.items[idx] = ChatMessage.create({\n id: INSTRUCTIONS_MESSAGE_ID,\n role: 'system',\n content: [instructions],\n createdAt: chatCtx.items[idx]!.createdAt,\n });\n } else {\n throw new Error('expected the instructions inside the chatCtx to be of type \"message\"');\n }\n } else if (addIfMissing) {\n // insert the instructions at the beginning of the chat context\n chatCtx.items.unshift(\n ChatMessage.create({\n id: INSTRUCTIONS_MESSAGE_ID,\n role: 'system',\n content: [instructions],\n }),\n );\n }\n}\n\nexport function performLLMInference(\n node: LLMNode,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n controller: AbortController,\n): [Task<void>, _LLMGenerationData] {\n const textStream = new IdentityTransform<string>();\n const toolCallStream = new IdentityTransform<FunctionCall>();\n\n const textWriter = textStream.writable.getWriter();\n const toolCallWriter = toolCallStream.writable.getWriter();\n const data = new _LLMGenerationData(textStream.readable, toolCallStream.readable);\n\n const inferenceTask = async (signal: AbortSignal) => {\n let llmStreamReader: ReadableStreamDefaultReader<string | ChatChunk> | null = null;\n let llmStream: ReadableStream<string | ChatChunk> | null = null;\n\n try {\n llmStream = await node(chatCtx, toolCtx, modelSettings);\n if (llmStream === null) {\n await textWriter.close();\n return;\n }\n\n // TODO(brian): add support for dynamic tools\n\n llmStreamReader = llmStream.getReader();\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: chunk } = await llmStreamReader.read();\n if (done) {\n break;\n }\n\n if (typeof chunk === 'string') {\n data.generatedText += chunk;\n await textWriter.write(chunk);\n // TODO(shubhra): better way to check??\n } else {\n if (chunk.delta === undefined) {\n continue;\n }\n\n if (chunk.delta.toolCalls) {\n for (const tool of chunk.delta.toolCalls) {\n if (tool.type !== 'function_call') continue;\n\n const toolCall = FunctionCall.create({\n callId: `${data.id}/fnc_${data.generatedToolCalls.length}`,\n name: tool.name,\n args: tool.args,\n });\n\n data.generatedToolCalls.push(toolCall);\n await toolCallWriter.write(toolCall);\n }\n }\n\n if (chunk.delta.content) {\n data.generatedText += chunk.delta.content;\n await textWriter.write(chunk.delta.content);\n }\n }\n\n // No need to check if chunk is of type other than ChatChunk or string like in\n // Python since chunk is defined in the type ChatChunk | string in TypeScript\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n // Abort signal was triggered, handle gracefully\n return;\n }\n throw error;\n } finally {\n llmStreamReader?.releaseLock();\n await llmStream?.cancel();\n await textWriter.close();\n await toolCallWriter.close();\n }\n };\n\n return [\n Task.from((controller) => inferenceTask(controller.signal), controller, 'performLLMInference'),\n data,\n ];\n}\n\nexport function performTTSInference(\n node: TTSNode,\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n controller: AbortController,\n): [Task<void>, ReadableStream<AudioFrame>] {\n const audioStream = new IdentityTransform<AudioFrame>();\n const outputWriter = audioStream.writable.getWriter();\n const audioOutputStream = audioStream.readable;\n\n const inferenceTask = async (signal: AbortSignal) => {\n let ttsStreamReader: ReadableStreamDefaultReader<AudioFrame> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n\n try {\n ttsStream = await node(text, modelSettings);\n if (ttsStream === null) {\n await outputWriter.close();\n return;\n }\n\n ttsStreamReader = ttsStream.getReader();\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: chunk } = await ttsStreamReader.read();\n if (done) {\n break;\n }\n await outputWriter.write(chunk);\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n // Abort signal was triggered, handle gracefully\n return;\n }\n throw error;\n } finally {\n ttsStreamReader?.releaseLock();\n await ttsStream?.cancel();\n await outputWriter.close();\n }\n };\n\n return [\n Task.from((controller) => inferenceTask(controller.signal), controller, 'performTTSInference'),\n audioOutputStream,\n ];\n}\n\nexport interface _TextOut {\n text: string;\n firstTextFut: Future;\n}\n\nasync function forwardText(\n source: ReadableStream<string>,\n out: _TextOut,\n signal: AbortSignal,\n textOutput: TextOutput | null,\n): Promise<void> {\n const reader = source.getReader();\n try {\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: delta } = await reader.read();\n if (done) break;\n out.text += delta;\n if (textOutput !== null) {\n await textOutput.captureText(delta);\n }\n if (!out.firstTextFut.done) {\n out.firstTextFut.resolve();\n }\n }\n } finally {\n if (textOutput !== null) {\n textOutput.flush();\n }\n reader?.releaseLock();\n }\n}\n\nexport function performTextForwarding(\n source: ReadableStream<string>,\n controller: AbortController,\n textOutput: TextOutput | null,\n): [Task<void>, _TextOut] {\n const out = {\n text: '',\n firstTextFut: new Future(),\n };\n return [\n Task.from(\n (controller) => forwardText(source, out, controller.signal, textOutput),\n controller,\n 'performTextForwarding',\n ),\n out,\n ];\n}\n\nexport interface _AudioOut {\n audio: Array<AudioFrame>;\n firstFrameFut: Future;\n}\n\nasync function forwardAudio(\n ttsStream: ReadableStream<AudioFrame>,\n audioOuput: AudioOutput,\n out: _AudioOut,\n signal?: AbortSignal,\n): Promise<void> {\n const reader = ttsStream.getReader();\n let resampler: AudioResampler | null = null;\n\n try {\n while (true) {\n if (signal?.aborted) {\n break;\n }\n\n const { done, value: frame } = await reader.read();\n if (done) break;\n\n out.audio.push(frame);\n\n if (\n !out.firstFrameFut.done &&\n audioOuput.sampleRate &&\n audioOuput.sampleRate !== frame.sampleRate &&\n !resampler\n ) {\n resampler = new AudioResampler(frame.sampleRate, audioOuput.sampleRate, 1);\n }\n\n if (resampler) {\n for (const f of resampler.push(frame)) {\n await audioOuput.captureFrame(f);\n }\n } else {\n await audioOuput.captureFrame(frame);\n }\n\n // set the first frame future if not already set\n // (after completing the first frame)\n if (!out.firstFrameFut.done) {\n out.firstFrameFut.resolve();\n }\n }\n } finally {\n reader?.releaseLock();\n if (resampler) {\n for (const f of resampler.flush()) {\n await audioOuput.captureFrame(f);\n }\n }\n audioOuput.flush();\n }\n}\n\nexport function performAudioForwarding(\n ttsStream: ReadableStream<AudioFrame>,\n audioOutput: AudioOutput,\n controller: AbortController,\n): [Task<void>, _AudioOut] {\n const out = {\n audio: [],\n firstFrameFut: new Future(),\n };\n return [\n Task.from(\n (controller) => forwardAudio(ttsStream, audioOutput, out, controller.signal),\n controller,\n 'performAudioForwarding',\n ),\n out,\n ];\n}\n\nexport function performToolExecutions({\n session,\n speechHandle,\n toolCtx,\n toolChoice,\n toolCallStream,\n onToolExecutionStarted = () => {},\n onToolExecutionCompleted = () => {},\n controller,\n}: {\n session: AgentSession;\n speechHandle: SpeechHandle;\n toolCtx: ToolContext;\n toolChoice?: ToolChoice;\n toolCallStream: ReadableStream<FunctionCall>;\n onToolExecutionStarted?: (toolCall: FunctionCall) => void;\n onToolExecutionCompleted?: (toolExecutionOutput: ToolExecutionOutput) => void;\n controller: AbortController;\n}): [Task<void>, ToolOutput] {\n const logger = log();\n const toolOutput: ToolOutput = {\n output: [],\n firstToolStartedFuture: new Future(),\n };\n\n const toolCompleted = (out: ToolExecutionOutput) => {\n onToolExecutionCompleted(out);\n toolOutput.output.push(out);\n };\n\n const executeToolsTask = async (controller: AbortController) => {\n const signal = controller.signal;\n const reader = toolCallStream.getReader();\n\n const tasks: Promise<any>[] = [];\n while (!signal.aborted) {\n const { done, value: toolCall } = await reader.read();\n if (signal.aborted) break;\n if (done) break;\n\n if (toolChoice === 'none') {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n \"received a tool call with toolChoice set to 'none', ignoring\",\n );\n continue;\n }\n\n // TODO(brian): assert other toolChoice values\n\n const tool = toolCtx[toolCall.name];\n if (!tool) {\n logger.warn(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n `unknown AI function ${toolCall.name}`,\n );\n continue;\n }\n\n if (!isFunctionTool(tool)) {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n `unknown tool type: ${typeof tool}`,\n );\n continue;\n }\n\n let parsedArgs: object | undefined;\n\n // Ensure valid arguments\n try {\n const jsonArgs = JSON.parse(toolCall.args);\n\n if (tool.parameters instanceof ZodObject) {\n parsedArgs = tool.parameters.parse(jsonArgs);\n } else {\n parsedArgs = jsonArgs;\n }\n } catch (rawError) {\n const error = toError(rawError);\n logger.error(\n {\n function: toolCall.name,\n arguments: toolCall.args,\n speech_id: speechHandle.id,\n error: error.message,\n },\n `tried to call AI function ${toolCall.name} with invalid arguments`,\n );\n toolCompleted(\n createToolOutput({\n toolCall,\n exception: error,\n }),\n );\n continue;\n }\n\n if (!toolOutput.firstToolStartedFuture.done) {\n toolOutput.firstToolStartedFuture.resolve();\n }\n\n onToolExecutionStarted(toolCall);\n\n logger.info(\n {\n function: toolCall.name,\n arguments: parsedArgs,\n speech_id: speechHandle.id,\n },\n 'Executing LLM tool call',\n );\n\n const toolExecution = asyncLocalStorage.run({ functionCall: toolCall }, async () => {\n return await tool.execute(parsedArgs, {\n ctx: new RunContext(session, speechHandle, toolCall),\n toolCallId: toolCall.callId,\n abortSignal: signal,\n });\n });\n\n const tracableToolExecution = async (toolExecTask: Promise<unknown>) => {\n // TODO(brian): add tracing\n\n // await for task to complete, if task is aborted, set exception\n let toolOutput: ToolExecutionOutput | undefined;\n try {\n const { result, isAborted } = await waitUntilAborted(toolExecTask, signal);\n toolOutput = createToolOutput({\n toolCall,\n exception: isAborted ? new Error('tool call was aborted') : undefined,\n output: isAborted ? undefined : result,\n });\n } catch (rawError) {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n error: toError(rawError).message,\n },\n 'exception occurred while executing tool',\n );\n toolOutput = createToolOutput({\n toolCall,\n exception: toError(rawError),\n });\n } finally {\n if (!toolOutput) throw new Error('toolOutput is undefined');\n toolCompleted(toolOutput);\n }\n };\n\n // wait, not cancelling all tool calling tasks\n tasks.push(tracableToolExecution(toolExecution));\n }\n\n await Promise.allSettled(tasks);\n if (toolOutput.output.length > 0) {\n logger.debug(\n {\n speech_id: speechHandle.id,\n },\n 'tools execution completed',\n );\n }\n };\n\n return [Task.from(executeToolsTask, controller, 'performToolExecutions'), toolOutput];\n}\n\ntype Aborted<T> =\n | {\n result: T;\n isAborted: false;\n }\n | {\n result: undefined;\n isAborted: true;\n };\n\nasync function waitUntilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<Aborted<T>> {\n const abortFut = new Future<Aborted<T>>();\n\n const resolveAbort = () => {\n if (!abortFut.done) {\n abortFut.resolve({ result: undefined, isAborted: true });\n }\n };\n\n signal.addEventListener('abort', resolveAbort);\n\n promise\n .then((r) => {\n if (!abortFut.done) {\n abortFut.resolve({ result: r, isAborted: false });\n }\n })\n .catch((e) => {\n if (!abortFut.done) {\n abortFut.reject(e);\n }\n })\n .finally(() => {\n signal.removeEventListener('abort', resolveAbort);\n });\n\n return await abortFut.await;\n}\n\nexport function removeInstructions(chatCtx: ChatContext) {\n // loop in case there are items with the same id (shouldn't happen!)\n while (true) {\n const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n if (idx !== undefined) {\n chatCtx.items.splice(idx, 1);\n } else {\n break;\n }\n }\n}\n"],"mappings":"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","names":["controller","toolOutput"]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/generation.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { AudioResampler } from '@livekit/rtc-node';\nimport type { ReadableStream, ReadableStreamDefaultReader } from 'stream/web';\nimport { ZodObject } from 'zod';\nimport {\n type ChatContext,\n ChatMessage,\n FunctionCall,\n FunctionCallOutput,\n} from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport {\n type ToolChoice,\n type ToolContext,\n isAgentHandoff,\n isFunctionTool,\n isToolError,\n} from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { Future, Task, shortuuid, toError } from '../utils.js';\nimport { type Agent, type ModelSettings, asyncLocalStorage, isStopResponse } from './agent.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { AudioOutput, LLMNode, TTSNode, TextOutput } from './io.js';\nimport { RunContext } from './run_context.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\n/** @internal */\nexport class _LLMGenerationData {\n generatedText: string = '';\n generatedToolCalls: FunctionCall[];\n id: string;\n\n constructor(\n public readonly textStream: ReadableStream<string>,\n public readonly toolCallStream: ReadableStream<FunctionCall>,\n ) {\n this.id = shortuuid('item_');\n this.generatedToolCalls = [];\n }\n}\n\n// TODO(brian): remove this class in favor of ToolOutput\nexport class _ToolOutput {\n output: _JsOutput[];\n firstToolFut: Future;\n\n constructor() {\n this.output = [];\n this.firstToolFut = new Future();\n }\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _SanitizedOutput {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n replyRequired: boolean;\n agentTask?: Agent;\n\n constructor(\n toolCall: FunctionCall,\n toolCallOutput: FunctionCallOutput | undefined,\n replyRequired: boolean,\n agentTask: Agent | undefined,\n ) {\n this.toolCall = toolCall;\n this.toolCallOutput = toolCallOutput;\n this.replyRequired = replyRequired;\n this.agentTask = agentTask;\n }\n\n static create(params: {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n replyRequired?: boolean;\n agentTask?: Agent;\n }) {\n const { toolCall, toolCallOutput, replyRequired = true, agentTask } = params;\n return new _SanitizedOutput(toolCall, toolCallOutput, replyRequired, agentTask);\n }\n}\n\nfunction isValidToolOutput(toolOutput: unknown): boolean {\n const validTypes = ['string', 'number', 'boolean'];\n\n if (validTypes.includes(typeof toolOutput)) {\n return true;\n }\n\n if (toolOutput === undefined || toolOutput === null) {\n return true;\n }\n\n if (Array.isArray(toolOutput)) {\n return toolOutput.every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Set) {\n return Array.from(toolOutput).every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Map) {\n return Array.from(toolOutput.values()).every(isValidToolOutput);\n }\n\n if (toolOutput instanceof Object) {\n return Object.entries(toolOutput).every(\n ([key, value]) => validTypes.includes(typeof key) && isValidToolOutput(value),\n );\n }\n\n return false;\n}\n\nexport class ToolExecutionOutput {\n constructor(\n public readonly toolCall: FunctionCall,\n public readonly toolCallOutput: FunctionCallOutput | undefined,\n public readonly agentTask: Agent | undefined,\n public readonly rawOutput: unknown,\n public readonly rawException: Error | undefined,\n public readonly replyRequired: boolean,\n ) {}\n\n static create(params: {\n toolCall: FunctionCall;\n toolCallOutput?: FunctionCallOutput;\n agentTask?: Agent;\n rawOutput: unknown;\n rawException?: Error;\n replyRequired?: boolean;\n }) {\n const {\n toolCall,\n toolCallOutput,\n agentTask,\n rawOutput,\n rawException,\n replyRequired = true,\n } = params;\n return new ToolExecutionOutput(\n toolCall,\n toolCallOutput,\n agentTask,\n rawOutput,\n rawException,\n replyRequired,\n );\n }\n}\n\nexport interface ToolOutput {\n output: ToolExecutionOutput[];\n firstToolStartedFuture: Future<void>;\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _JsOutput {\n toolCall: FunctionCall;\n output: unknown;\n exception?: Error;\n\n #logger = log();\n\n constructor(toolCall: FunctionCall, output: unknown, exception: Error | undefined) {\n this.toolCall = toolCall;\n this.output = output;\n this.exception = exception;\n }\n\n static create(params: { toolCall: FunctionCall; output?: unknown; exception?: Error }) {\n const { toolCall, output = undefined, exception = undefined } = params;\n return new _JsOutput(toolCall, output, exception);\n }\n\n sanitize(): _SanitizedOutput {\n if (isToolError(this.exception)) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: this.exception.message,\n isError: true,\n }),\n });\n }\n\n if (isStopResponse(this.exception)) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n });\n }\n\n if (this.exception !== undefined) {\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: 'An internal error occurred while executing the tool.', // Don't send the actual error message, as it may contain sensitive information\n isError: true,\n }),\n });\n }\n\n let agentTask: Agent | undefined = undefined;\n let toolOutput: unknown = this.output;\n if (isAgentHandoff(this.output)) {\n agentTask = this.output.agent;\n toolOutput = this.output.returns;\n }\n\n if (!isValidToolOutput(toolOutput)) {\n this.#logger.error(\n {\n callId: this.toolCall.callId,\n function: this.toolCall.name,\n },\n `AI function ${this.toolCall.name} returned an invalid output`,\n );\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: undefined,\n });\n }\n\n return _SanitizedOutput.create({\n toolCall: FunctionCall.create({ ...this.toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: this.toolCall.name,\n callId: this.toolCall.callId,\n output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n isError: false,\n }),\n replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n agentTask,\n });\n }\n}\n\nexport function createToolOutput(params: {\n toolCall: FunctionCall;\n output?: unknown;\n exception?: Error;\n}): ToolExecutionOutput {\n const { toolCall, output, exception } = params;\n const logger = log();\n\n // support returning Exception instead of raising them (for devex purposes inside evals)\n let finalOutput = output;\n let finalException = exception;\n if (output instanceof Error) {\n finalException = output;\n finalOutput = undefined;\n }\n\n if (isToolError(finalException)) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: finalException.message,\n isError: true,\n }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n if (isStopResponse(finalException)) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n if (finalException !== undefined) {\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: 'An internal error occurred', // Don't send the actual error message, as it may contain sensitive information\n isError: true,\n }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n let agentTask: Agent | undefined = undefined;\n let toolOutput: unknown = finalOutput;\n if (isAgentHandoff(finalOutput)) {\n agentTask = finalOutput.agent;\n toolOutput = finalOutput.returns;\n }\n\n if (!isValidToolOutput(toolOutput)) {\n logger.error(\n {\n callId: toolCall.callId,\n output: finalOutput,\n },\n `AI function ${toolCall.name} returned an invalid output`,\n );\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n rawOutput: finalOutput,\n rawException: finalException,\n });\n }\n\n return ToolExecutionOutput.create({\n toolCall: FunctionCall.create({ ...toolCall }),\n toolCallOutput: FunctionCallOutput.create({\n name: toolCall.name,\n callId: toolCall.callId,\n output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n isError: false,\n }),\n replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n agentTask,\n rawOutput: finalOutput,\n rawException: finalException,\n });\n}\n\nconst INSTRUCTIONS_MESSAGE_ID = 'lk.agent_task.instructions';\n\n/**\n * Update the instruction message in the chat context or insert a new one if missing.\n *\n * This function looks for an existing instruction message in the chat context using the identifier\n * 'INSTRUCTIONS_MESSAGE_ID'.\n *\n * @param options - The options for updating the instructions.\n * @param options.chatCtx - The chat context to update.\n * @param options.instructions - The instructions to add.\n * @param options.addIfMissing - Whether to add the instructions if they are missing.\n */\nexport function updateInstructions(options: {\n chatCtx: ChatContext;\n instructions: string;\n addIfMissing: boolean;\n}) {\n const { chatCtx, instructions, addIfMissing } = options;\n\n const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n if (idx !== undefined) {\n if (chatCtx.items[idx]!.type === 'message') {\n // create a new instance to avoid mutating the original\n chatCtx.items[idx] = ChatMessage.create({\n id: INSTRUCTIONS_MESSAGE_ID,\n role: 'system',\n content: [instructions],\n createdAt: chatCtx.items[idx]!.createdAt,\n });\n } else {\n throw new Error('expected the instructions inside the chatCtx to be of type \"message\"');\n }\n } else if (addIfMissing) {\n // insert the instructions at the beginning of the chat context\n chatCtx.items.unshift(\n ChatMessage.create({\n id: INSTRUCTIONS_MESSAGE_ID,\n role: 'system',\n content: [instructions],\n }),\n );\n }\n}\n\nexport function performLLMInference(\n node: LLMNode,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n controller: AbortController,\n): [Task<void>, _LLMGenerationData] {\n const textStream = new IdentityTransform<string>();\n const toolCallStream = new IdentityTransform<FunctionCall>();\n\n const textWriter = textStream.writable.getWriter();\n const toolCallWriter = toolCallStream.writable.getWriter();\n const data = new _LLMGenerationData(textStream.readable, toolCallStream.readable);\n\n const inferenceTask = async (signal: AbortSignal) => {\n let llmStreamReader: ReadableStreamDefaultReader<string | ChatChunk> | null = null;\n let llmStream: ReadableStream<string | ChatChunk> | null = null;\n\n try {\n llmStream = await node(chatCtx, toolCtx, modelSettings);\n if (llmStream === null) {\n await textWriter.close();\n return;\n }\n\n // TODO(brian): add support for dynamic tools\n\n llmStreamReader = llmStream.getReader();\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: chunk } = await llmStreamReader.read();\n if (done) {\n break;\n }\n\n if (typeof chunk === 'string') {\n data.generatedText += chunk;\n await textWriter.write(chunk);\n // TODO(shubhra): better way to check??\n } else {\n if (chunk.delta === undefined) {\n continue;\n }\n\n if (chunk.delta.toolCalls) {\n for (const tool of chunk.delta.toolCalls) {\n if (tool.type !== 'function_call') continue;\n\n const toolCall = FunctionCall.create({\n callId: `${data.id}/fnc_${data.generatedToolCalls.length}`,\n name: tool.name,\n args: tool.args,\n });\n\n data.generatedToolCalls.push(toolCall);\n await toolCallWriter.write(toolCall);\n }\n }\n\n if (chunk.delta.content) {\n data.generatedText += chunk.delta.content;\n await textWriter.write(chunk.delta.content);\n }\n }\n\n // No need to check if chunk is of type other than ChatChunk or string like in\n // Python since chunk is defined in the type ChatChunk | string in TypeScript\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n // Abort signal was triggered, handle gracefully\n return;\n }\n throw error;\n } finally {\n llmStreamReader?.releaseLock();\n await llmStream?.cancel();\n await textWriter.close();\n await toolCallWriter.close();\n }\n };\n\n return [\n Task.from((controller) => inferenceTask(controller.signal), controller, 'performLLMInference'),\n data,\n ];\n}\n\nexport function performTTSInference(\n node: TTSNode,\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n controller: AbortController,\n): [Task<void>, ReadableStream<AudioFrame>] {\n const audioStream = new IdentityTransform<AudioFrame>();\n const outputWriter = audioStream.writable.getWriter();\n const audioOutputStream = audioStream.readable;\n\n const inferenceTask = async (signal: AbortSignal) => {\n let ttsStreamReader: ReadableStreamDefaultReader<AudioFrame> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n\n try {\n ttsStream = await node(text, modelSettings);\n if (ttsStream === null) {\n await outputWriter.close();\n return;\n }\n\n ttsStreamReader = ttsStream.getReader();\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: chunk } = await ttsStreamReader.read();\n if (done) {\n break;\n }\n await outputWriter.write(chunk);\n }\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n // Abort signal was triggered, handle gracefully\n return;\n }\n throw error;\n } finally {\n ttsStreamReader?.releaseLock();\n await ttsStream?.cancel();\n await outputWriter.close();\n }\n };\n\n return [\n Task.from((controller) => inferenceTask(controller.signal), controller, 'performTTSInference'),\n audioOutputStream,\n ];\n}\n\nexport interface _TextOut {\n text: string;\n firstTextFut: Future;\n}\n\nasync function forwardText(\n source: ReadableStream<string>,\n out: _TextOut,\n signal: AbortSignal,\n textOutput: TextOutput | null,\n): Promise<void> {\n const reader = source.getReader();\n try {\n while (true) {\n if (signal.aborted) {\n break;\n }\n const { done, value: delta } = await reader.read();\n if (done) break;\n out.text += delta;\n if (textOutput !== null) {\n await textOutput.captureText(delta);\n }\n if (!out.firstTextFut.done) {\n out.firstTextFut.resolve();\n }\n }\n } finally {\n if (textOutput !== null) {\n textOutput.flush();\n }\n reader?.releaseLock();\n }\n}\n\nexport function performTextForwarding(\n source: ReadableStream<string>,\n controller: AbortController,\n textOutput: TextOutput | null,\n): [Task<void>, _TextOut] {\n const out = {\n text: '',\n firstTextFut: new Future(),\n };\n return [\n Task.from(\n (controller) => forwardText(source, out, controller.signal, textOutput),\n controller,\n 'performTextForwarding',\n ),\n out,\n ];\n}\n\nexport interface _AudioOut {\n audio: Array<AudioFrame>;\n firstFrameFut: Future;\n}\n\nasync function forwardAudio(\n ttsStream: ReadableStream<AudioFrame>,\n audioOuput: AudioOutput,\n out: _AudioOut,\n signal?: AbortSignal,\n): Promise<void> {\n const reader = ttsStream.getReader();\n let resampler: AudioResampler | null = null;\n\n try {\n while (true) {\n if (signal?.aborted) {\n break;\n }\n\n const { done, value: frame } = await reader.read();\n if (done) break;\n\n out.audio.push(frame);\n\n if (\n !out.firstFrameFut.done &&\n audioOuput.sampleRate &&\n audioOuput.sampleRate !== frame.sampleRate &&\n !resampler\n ) {\n resampler = new AudioResampler(frame.sampleRate, audioOuput.sampleRate, 1);\n }\n\n if (resampler) {\n for (const f of resampler.push(frame)) {\n await audioOuput.captureFrame(f);\n }\n } else {\n await audioOuput.captureFrame(frame);\n }\n\n // set the first frame future if not already set\n // (after completing the first frame)\n if (!out.firstFrameFut.done) {\n out.firstFrameFut.resolve();\n }\n }\n } finally {\n reader?.releaseLock();\n if (resampler) {\n for (const f of resampler.flush()) {\n await audioOuput.captureFrame(f);\n }\n }\n audioOuput.flush();\n }\n}\n\nexport function performAudioForwarding(\n ttsStream: ReadableStream<AudioFrame>,\n audioOutput: AudioOutput,\n controller: AbortController,\n): [Task<void>, _AudioOut] {\n const out = {\n audio: [],\n firstFrameFut: new Future(),\n };\n return [\n Task.from(\n (controller) => forwardAudio(ttsStream, audioOutput, out, controller.signal),\n controller,\n 'performAudioForwarding',\n ),\n out,\n ];\n}\n\nexport function performToolExecutions({\n session,\n speechHandle,\n toolCtx,\n toolChoice,\n toolCallStream,\n onToolExecutionStarted = () => {},\n onToolExecutionCompleted = () => {},\n controller,\n}: {\n session: AgentSession;\n speechHandle: SpeechHandle;\n toolCtx: ToolContext;\n toolChoice?: ToolChoice;\n toolCallStream: ReadableStream<FunctionCall>;\n onToolExecutionStarted?: (toolCall: FunctionCall) => void;\n onToolExecutionCompleted?: (toolExecutionOutput: ToolExecutionOutput) => void;\n controller: AbortController;\n}): [Task<void>, ToolOutput] {\n const logger = log();\n const toolOutput: ToolOutput = {\n output: [],\n firstToolStartedFuture: new Future(),\n };\n\n const toolCompleted = (out: ToolExecutionOutput) => {\n onToolExecutionCompleted(out);\n toolOutput.output.push(out);\n };\n\n const executeToolsTask = async (controller: AbortController) => {\n const signal = controller.signal;\n const reader = toolCallStream.getReader();\n\n const tasks: Promise<any>[] = [];\n while (!signal.aborted) {\n const { done, value: toolCall } = await reader.read();\n if (signal.aborted) break;\n if (done) break;\n\n if (toolChoice === 'none') {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n \"received a tool call with toolChoice set to 'none', ignoring\",\n );\n continue;\n }\n\n // TODO(brian): assert other toolChoice values\n\n const tool = toolCtx[toolCall.name];\n if (!tool) {\n logger.warn(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n `unknown AI function ${toolCall.name}`,\n );\n continue;\n }\n\n if (!isFunctionTool(tool)) {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n },\n `unknown tool type: ${typeof tool}`,\n );\n continue;\n }\n\n let parsedArgs: object | undefined;\n\n // Ensure valid arguments\n try {\n const jsonArgs = JSON.parse(toolCall.args);\n\n if (tool.parameters instanceof ZodObject) {\n parsedArgs = tool.parameters.parse(jsonArgs);\n } else {\n parsedArgs = jsonArgs;\n }\n } catch (rawError) {\n const error = toError(rawError);\n logger.error(\n {\n function: toolCall.name,\n arguments: toolCall.args,\n speech_id: speechHandle.id,\n error: error.message,\n },\n `tried to call AI function ${toolCall.name} with invalid arguments`,\n );\n toolCompleted(\n createToolOutput({\n toolCall,\n exception: error,\n }),\n );\n continue;\n }\n\n if (!toolOutput.firstToolStartedFuture.done) {\n toolOutput.firstToolStartedFuture.resolve();\n }\n\n onToolExecutionStarted(toolCall);\n\n logger.info(\n {\n function: toolCall.name,\n arguments: parsedArgs,\n speech_id: speechHandle.id,\n },\n 'Executing LLM tool call',\n );\n\n const toolExecution = asyncLocalStorage.run({ functionCall: toolCall }, async () => {\n return await tool.execute(parsedArgs, {\n ctx: new RunContext(session, speechHandle, toolCall),\n toolCallId: toolCall.callId,\n abortSignal: signal,\n });\n });\n\n const tracableToolExecution = async (toolExecTask: Promise<unknown>) => {\n // TODO(brian): add tracing\n\n // await for task to complete, if task is aborted, set exception\n let toolOutput: ToolExecutionOutput | undefined;\n try {\n const { result, isAborted } = await waitUntilAborted(toolExecTask, signal);\n toolOutput = createToolOutput({\n toolCall,\n exception: isAborted ? new Error('tool call was aborted') : undefined,\n output: isAborted ? undefined : result,\n });\n } catch (rawError) {\n logger.error(\n {\n function: toolCall.name,\n speech_id: speechHandle.id,\n error: toError(rawError).message,\n },\n 'exception occurred while executing tool',\n );\n toolOutput = createToolOutput({\n toolCall,\n exception: toError(rawError),\n });\n } finally {\n if (!toolOutput) throw new Error('toolOutput is undefined');\n toolCompleted(toolOutput);\n }\n };\n\n // wait, not cancelling all tool calling tasks\n tasks.push(tracableToolExecution(toolExecution));\n }\n\n await Promise.allSettled(tasks);\n if (toolOutput.output.length > 0) {\n logger.debug(\n {\n speech_id: speechHandle.id,\n },\n 'tools execution completed',\n );\n }\n };\n\n return [Task.from(executeToolsTask, controller, 'performToolExecutions'), toolOutput];\n}\n\ntype Aborted<T> =\n | {\n result: T;\n isAborted: false;\n }\n | {\n result: undefined;\n isAborted: true;\n };\n\nasync function waitUntilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<Aborted<T>> {\n const abortFut = new Future<Aborted<T>>();\n\n const resolveAbort = () => {\n if (!abortFut.done) {\n abortFut.resolve({ result: undefined, isAborted: true });\n }\n };\n\n signal.addEventListener('abort', resolveAbort);\n\n promise\n .then((r) => {\n if (!abortFut.done) {\n abortFut.resolve({ result: r, isAborted: false });\n }\n })\n .catch((e) => {\n if (!abortFut.done) {\n abortFut.reject(e);\n }\n })\n .finally(() => {\n signal.removeEventListener('abort', resolveAbort);\n });\n\n return await abortFut.await;\n}\n\nexport function removeInstructions(chatCtx: ChatContext) {\n // loop in case there are items with the same id (shouldn't happen!)\n while (true) {\n const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n if (idx !== undefined) {\n chatCtx.items.splice(idx, 1);\n } else {\n break;\n }\n }\n}\n"],"mappings":"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","names":["controller","toolOutput"]}
|
|
@@ -59,6 +59,15 @@ class ParticipantAudioInputStream extends import_io.AudioInput {
|
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
const participantValue = participant instanceof import_rtc_node.RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
|
|
62
|
+
const trackPublicationsArray = Array.from((participantValue == null ? void 0 : participantValue.trackPublications.values()) ?? []);
|
|
63
|
+
this.logger.info(
|
|
64
|
+
{
|
|
65
|
+
participantValue: participantValue == null ? void 0 : participantValue.identity,
|
|
66
|
+
trackPublications: trackPublicationsArray,
|
|
67
|
+
lengthOfTrackPublications: trackPublicationsArray.length
|
|
68
|
+
},
|
|
69
|
+
"participantValue.trackPublications"
|
|
70
|
+
);
|
|
62
71
|
if (participantValue) {
|
|
63
72
|
for (const publication of participantValue.trackPublications.values()) {
|
|
64
73
|
if (publication.track && publication.source === import_rtc_node.TrackSource.SOURCE_MICROPHONE) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n AudioFrame,\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // Convert Map iterator to array for Pino serialization\n const trackPublicationsArray = Array.from(participantValue?.trackPublications.values() ?? []);\n\n this.logger.info(\n {\n participantValue: participantValue?.identity,\n trackPublications: trackPublicationsArray,\n lengthOfTrackPublications: trackPublicationsArray.length,\n },\n 'participantValue.trackPublications',\n );\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"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","names":["publication"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,wBAAwB,EAC7B,iBAAiB,EAGjB,KAAK,IAAI,EAGV,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,2BAA4B,SAAQ,UAAU;IACzD,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,MAAM,CAAS;gBACX,EACV,IAAI,EACJ,UAAU,EACV,WAAW,EACX,iBAAiB,GAClB,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;KAC9C;IAWD,cAAc,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IA2C7D,OAAO,CAAC,kBAAkB,CAqBxB;IAEF,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,iBAAiB,CAsBvB;IAEF,OAAO,CAAC,YAAY;IASd,KAAK;CAMZ"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AudioFrame,
|
|
2
3
|
AudioStream,
|
|
3
4
|
RemoteParticipant,
|
|
4
5
|
RoomEvent,
|
|
@@ -41,6 +42,15 @@ class ParticipantAudioInputStream extends AudioInput {
|
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
44
|
const participantValue = participant instanceof RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
|
|
45
|
+
const trackPublicationsArray = Array.from((participantValue == null ? void 0 : participantValue.trackPublications.values()) ?? []);
|
|
46
|
+
this.logger.info(
|
|
47
|
+
{
|
|
48
|
+
participantValue: participantValue == null ? void 0 : participantValue.identity,
|
|
49
|
+
trackPublications: trackPublicationsArray,
|
|
50
|
+
lengthOfTrackPublications: trackPublicationsArray.length
|
|
51
|
+
},
|
|
52
|
+
"participantValue.trackPublications"
|
|
53
|
+
);
|
|
44
54
|
if (participantValue) {
|
|
45
55
|
for (const publication of participantValue.trackPublications.values()) {
|
|
46
56
|
if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n AudioFrame,\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // Convert Map iterator to array for Pino serialization\n const trackPublicationsArray = Array.from(participantValue?.trackPublications.values() ?? []);\n\n this.logger.info(\n {\n participantValue: participantValue?.identity,\n trackPublications: trackPublicationsArray,\n lengthOfTrackPublications: trackPublicationsArray.length,\n },\n 'participantValue.trackPublications',\n );\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n this.logger.debug({ participant: participant.identity }, 'onTrackSubscribed in _input');\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"AAGA;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EAIA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,WAAW;AACpB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAEpB,MAAM,oCAAoC,WAAW;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAA6C;AAAA,EAC7C,sBAAqC;AAAA,EACrC,SAAS,IAAI;AAAA,EACrB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,KAAK,GAAG,UAAU,iBAAiB,KAAK,iBAAiB;AAC9D,SAAK,KAAK,GAAG,UAAU,kBAAkB,KAAK,kBAAkB;AAAA,EAClE;AAAA,EAEA,eAAe,aAAgD;AAC7D,SAAK,OAAO,MAAM,EAAE,YAAY,GAAG,iCAAiC;AACpE,UAAM,sBACJ,uBAAuB,oBAAoB,YAAY,WAAW;AAEpE,QAAI,KAAK,wBAAwB,qBAAqB;AACpD;AAAA,IACF;AACA,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AAEjB,QAAI,CAAC,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,mBACJ,uBAAuB,oBACnB,cACA,KAAK,KAAK,mBAAmB,IAAI,mBAAmB;AAG1D,UAAM,yBAAyB,MAAM,MAAK,qDAAkB,kBAAkB,aAAY,CAAC,CAAC;AAE5F,SAAK,OAAO;AAAA,MACV;AAAA,QACE,kBAAkB,qDAAkB;AAAA,QACpC,mBAAmB;AAAA,QACnB,2BAA2B,uBAAuB;AAAA,MACpD;AAAA,MACA;AAAA,IACF;AAGA,QAAI,kBAAkB;AACpB,iBAAW,eAAe,iBAAiB,kBAAkB,OAAO,GAAG;AACrE,YAAI,YAAY,SAAS,YAAY,WAAW,YAAY,mBAAmB;AAC7E,eAAK,kBAAkB,YAAY,OAAO,aAAa,gBAAgB;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB,CAC3B,aACA,gBACG;AA9FP;AA+FI,UACE,UAAK,gBAAL,mBAAkB,SAAQ,YAAY,OACtC,YAAY,aAAa,KAAK,qBAC9B;AACA;AAAA,IACF;AACA,SAAK,YAAY;AAGjB,eAAWA,gBAAe,YAAY,kBAAkB,OAAO,GAAG;AAChE,UACEA,aAAY,SACZ,KAAK,kBAAkBA,aAAY,OAAOA,cAAa,WAAW,GAClE;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI,KAAK,eAAe,aAAa;AACnC,WAAK,eAAe,aAAa;AAAA,IACnC;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,oBAAoB,CAC1B,OACA,aACA,gBACY;AACZ,SAAK,OAAO,MAAM,EAAE,aAAa,YAAY,SAAS,GAAG,6BAA6B;AACtF,QACE,KAAK,wBAAwB,YAAY,YACzC,YAAY,WAAW,YAAY,qBAClC,KAAK,eAAe,KAAK,YAAY,QAAQ,YAAY,KAC1D;AACA,aAAO;AAAA,IACT;AACA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,MAClB,eAAe;AAAA,QACb,QAAQ,KAAK,aAAa,KAAK;AAAA,QAC/B,YAAY,KAAK;AAAA,MACnB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,OAAgD;AACnE,WAAO,IAAI,YAAY,OAAO;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA;AAAA,IAE1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,KAAK,IAAI,UAAU,iBAAiB,KAAK,iBAAiB;AAC/D,SAAK,KAAK,IAAI,UAAU,kBAAkB,KAAK,kBAAkB;AACjE,SAAK,YAAY;AACjB,SAAK,eAAe,OAAO,OAAO;AAAA,EACpC;AACF;","names":["publication"]}
|
|
@@ -241,7 +241,7 @@ class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionO
|
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
class ParalellTextOutput extends import_io.TextOutput {
|
|
244
|
-
|
|
244
|
+
/** @internal */
|
|
245
245
|
_sinks;
|
|
246
246
|
constructor(sinks, nextInChain) {
|
|
247
247
|
super(nextInChain);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_output.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RemoteParticipant } from '@livekit/rtc-node';\nimport {\n type AudioFrame,\n AudioSource,\n LocalAudioTrack,\n type LocalTrackPublication,\n type Participant,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n type TextStreamWriter,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport {\n ATTRIBUTE_TRANSCRIPTION_FINAL,\n ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID,\n ATTRIBUTE_TRANSCRIPTION_TRACK_ID,\n TOPIC_TRANSCRIPTION,\n} from '../../constants.js';\nimport { log } from '../../log.js';\nimport { Future, Task, shortuuid } from '../../utils.js';\nimport { AudioOutput, TextOutput } from '../io.js';\nimport { findMicrophoneTrackId } from '../transcription/index.js';\n\nabstract class BaseParticipantTranscriptionOutput extends TextOutput {\n protected room: Room;\n protected isDeltaStream: boolean;\n protected participantIdentity: string | null = null;\n protected trackId?: string;\n protected capturing: boolean = false;\n protected latestText: string = '';\n protected currentId: string = this.generateCurrentId();\n protected logger = log();\n\n constructor(room: Room, isDeltaStream: boolean, participant: Participant | string | null) {\n super();\n this.room = room;\n this.isDeltaStream = isDeltaStream;\n\n this.room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n this.room.on(RoomEvent.LocalTrackPublished, this.onLocalTrackPublished);\n\n this.setParticipant(participant);\n }\n\n setParticipant(participant: Participant | string | null) {\n if (typeof participant === 'string' || participant === null) {\n this.participantIdentity = participant;\n } else {\n this.participantIdentity = participant.identity;\n }\n\n if (!this.participantIdentity) {\n return;\n }\n\n try {\n this.trackId = findMicrophoneTrackId(this.room, this.participantIdentity);\n } catch (error) {\n // track id is optional for TextStream when audio is not published\n }\n\n this.flush();\n this.resetState();\n }\n\n protected onTrackPublished = (track: RemoteTrackPublication, participant: RemoteParticipant) => {\n if (\n !this.participantIdentity ||\n participant.identity !== this.participantIdentity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected onLocalTrackPublished = (track: LocalTrackPublication) => {\n if (\n !this.participantIdentity ||\n this.participantIdentity !== this.room.localParticipant?.identity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected generateCurrentId(): string {\n return shortuuid('SG_');\n }\n\n protected resetState() {\n this.currentId = this.generateCurrentId();\n this.capturing = false;\n this.latestText = '';\n }\n\n async captureText(text: string) {\n if (!this.participantIdentity) {\n return;\n }\n\n this.latestText = text;\n await this.handleCaptureText(text);\n }\n\n flush() {\n if (!this.participantIdentity || !this.capturing) {\n return;\n }\n\n this.capturing = false;\n this.handleFlush();\n }\n\n protected abstract handleCaptureText(text: string): Promise<void>;\n protected abstract handleFlush(): void;\n}\n\nexport class ParticipantTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private writer: TextStreamWriter | null = null;\n private flushTask: Task<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (this.flushTask && !this.flushTask.done) {\n await this.flushTask.result;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n // reuse the existing writer\n if (this.writer === null) {\n this.writer = await this.createTextWriter();\n }\n await this.writer.write(text);\n } else {\n const tmpWriter = await this.createTextWriter();\n await tmpWriter.write(text);\n await tmpWriter.close();\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected handleFlush() {\n const currWriter = this.writer;\n this.writer = null;\n this.flushTask = Task.from((controller) => this.flushTaskImpl(currWriter, controller.signal));\n }\n\n private async createTextWriter(attributes?: Record<string, string>): Promise<TextStreamWriter> {\n if (!this.participantIdentity) {\n throw new Error('participantIdentity not found');\n }\n\n if (!this.room.localParticipant) {\n throw new Error('localParticipant not found');\n }\n\n if (!attributes) {\n attributes = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'false',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n }\n attributes[ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID] = this.currentId;\n\n return await this.room.localParticipant.streamText({\n topic: TOPIC_TRANSCRIPTION,\n senderIdentity: this.participantIdentity,\n attributes,\n });\n }\n\n private async flushTaskImpl(writer: TextStreamWriter | null, signal: AbortSignal): Promise<void> {\n const attributes: Record<string, string> = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'true',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n\n const abortPromise = new Promise<void>((resolve) => {\n signal.addEventListener('abort', () => resolve());\n });\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n if (writer) {\n await Promise.race([writer.close(), abortPromise]);\n }\n } else {\n const tmpWriter = await Promise.race([this.createTextWriter(attributes), abortPromise]);\n if (signal.aborted || !tmpWriter) {\n return;\n }\n await Promise.race([tmpWriter.write(this.latestText), abortPromise]);\n if (signal.aborted) {\n return;\n }\n await Promise.race([tmpWriter.close(), abortPromise]);\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n}\n\nexport class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private pushedText: string = '';\n private flushTask: Promise<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (!this.trackId) {\n return;\n }\n\n if (this.flushTask) {\n await this.flushTask;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n if (this.isDeltaStream) {\n this.pushedText += text;\n } else {\n this.pushedText = text;\n }\n\n await this.publishTranscription(this.currentId, this.pushedText, false);\n }\n\n protected handleFlush() {\n if (!this.trackId) {\n return;\n }\n\n this.flushTask = this.publishTranscription(this.currentId, this.pushedText, true);\n this.resetState();\n }\n\n async publishTranscription(id: string, text: string, final: boolean, signal?: AbortSignal) {\n if (!this.participantIdentity || !this.trackId) {\n return;\n }\n\n try {\n if (this.room.isConnected) {\n if (signal?.aborted) {\n return;\n }\n\n await this.room.localParticipant?.publishTranscription({\n participantIdentity: this.participantIdentity,\n trackSid: this.trackId,\n segments: [{ id, text, final, startTime: BigInt(0), endTime: BigInt(0), language: '' }],\n });\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected resetState() {\n super.resetState();\n this.pushedText = '';\n }\n}\n\nexport class ParalellTextOutput extends TextOutput {\n /* @internal */\n _sinks: TextOutput[];\n\n constructor(sinks: TextOutput[], nextInChain?: TextOutput) {\n super(nextInChain);\n this._sinks = sinks;\n }\n\n async captureText(text: string) {\n await Promise.all(this._sinks.map((sink) => sink.captureText(text)));\n }\n\n flush() {\n for (const sink of this._sinks) {\n sink.flush();\n }\n }\n}\n\nexport interface AudioOutputOptions {\n sampleRate: number;\n numChannels: number;\n trackPublishOptions: TrackPublishOptions;\n queueSizeMs?: number;\n}\nexport class ParticipantAudioOutput extends AudioOutput {\n private room: Room;\n private options: AudioOutputOptions;\n private audioSource: AudioSource;\n private publication?: LocalTrackPublication;\n private flushTask?: Task<void>;\n private pushedDurationMs: number = 0;\n private startedFuture: Future<void> = new Future();\n private interruptedFuture: Future<void> = new Future();\n\n constructor(room: Room, options: AudioOutputOptions) {\n super(options.sampleRate);\n this.room = room;\n this.options = options;\n this.audioSource = new AudioSource(options.sampleRate, options.numChannels);\n }\n\n get subscribed(): boolean {\n return this.startedFuture.done;\n }\n\n async start(signal: AbortSignal): Promise<void> {\n await this.publishTrack(signal);\n }\n\n async captureFrame(frame: AudioFrame): Promise<void> {\n await this.startedFuture.await;\n\n super.captureFrame(frame);\n\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n this.pushedDurationMs += frame.samplesPerChannel / frame.sampleRate;\n await this.audioSource.captureFrame(frame);\n }\n\n private async waitForPlayoutTask(abortController: AbortController): Promise<void> {\n const abortFuture = new Future<boolean>();\n\n const resolveAbort = () => {\n if (!abortFuture.done) abortFuture.resolve(true);\n };\n\n abortController.signal.addEventListener('abort', resolveAbort);\n\n this.audioSource.waitForPlayout().finally(() => {\n abortController.signal.removeEventListener('abort', resolveAbort);\n if (!abortFuture.done) abortFuture.resolve(false);\n });\n\n const interrupted = await Promise.race([\n abortFuture.await,\n this.interruptedFuture.await.then(() => true),\n ]);\n\n let pushedDuration = this.pushedDurationMs;\n\n if (interrupted) {\n // Calculate actual played duration accounting for queued audio\n pushedDuration = Math.max(this.pushedDurationMs - this.audioSource.queuedDuration, 0);\n this.audioSource.clearQueue();\n }\n\n this.pushedDurationMs = 0;\n this.interruptedFuture = new Future();\n this.onPlaybackFinished({\n playbackPosition: pushedDuration,\n interrupted,\n });\n }\n\n /**\n * Flush any buffered audio, marking the current playback/segment as complete\n */\n flush(): void {\n super.flush();\n\n if (!this.pushedDurationMs) {\n return;\n }\n\n if (this.flushTask && !this.flushTask.done) {\n this.logger.error('flush called while playback is in progress');\n this.flushTask.cancel();\n }\n\n this.flushTask = Task.from((controller) => this.waitForPlayoutTask(controller));\n }\n\n clearBuffer(): void {\n if (!this.pushedDurationMs) {\n return;\n }\n\n this.interruptedFuture.resolve();\n }\n\n private async publishTrack(signal: AbortSignal) {\n const track = LocalAudioTrack.createAudioTrack('roomio_audio', this.audioSource);\n this.publication = await this.room.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n if (signal.aborted) {\n return;\n }\n\n await this.publication?.waitForSubscription();\n\n if (!this.startedFuture.done) {\n this.startedFuture.resolve();\n }\n }\n\n async close() {\n // TODO(AJS-106): add republish track\n await this.audioSource.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_output.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RemoteParticipant } from '@livekit/rtc-node';\nimport {\n type AudioFrame,\n AudioSource,\n LocalAudioTrack,\n type LocalTrackPublication,\n type Participant,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n type TextStreamWriter,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport {\n ATTRIBUTE_TRANSCRIPTION_FINAL,\n ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID,\n ATTRIBUTE_TRANSCRIPTION_TRACK_ID,\n TOPIC_TRANSCRIPTION,\n} from '../../constants.js';\nimport { log } from '../../log.js';\nimport { Future, Task, shortuuid } from '../../utils.js';\nimport { AudioOutput, TextOutput } from '../io.js';\nimport { findMicrophoneTrackId } from '../transcription/index.js';\n\nabstract class BaseParticipantTranscriptionOutput extends TextOutput {\n protected room: Room;\n protected isDeltaStream: boolean;\n protected participantIdentity: string | null = null;\n protected trackId?: string;\n protected capturing: boolean = false;\n protected latestText: string = '';\n protected currentId: string = this.generateCurrentId();\n protected logger = log();\n\n constructor(room: Room, isDeltaStream: boolean, participant: Participant | string | null) {\n super();\n this.room = room;\n this.isDeltaStream = isDeltaStream;\n\n this.room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n this.room.on(RoomEvent.LocalTrackPublished, this.onLocalTrackPublished);\n\n this.setParticipant(participant);\n }\n\n setParticipant(participant: Participant | string | null) {\n if (typeof participant === 'string' || participant === null) {\n this.participantIdentity = participant;\n } else {\n this.participantIdentity = participant.identity;\n }\n\n if (!this.participantIdentity) {\n return;\n }\n\n try {\n this.trackId = findMicrophoneTrackId(this.room, this.participantIdentity);\n } catch (error) {\n // track id is optional for TextStream when audio is not published\n }\n\n this.flush();\n this.resetState();\n }\n\n protected onTrackPublished = (track: RemoteTrackPublication, participant: RemoteParticipant) => {\n if (\n !this.participantIdentity ||\n participant.identity !== this.participantIdentity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected onLocalTrackPublished = (track: LocalTrackPublication) => {\n if (\n !this.participantIdentity ||\n this.participantIdentity !== this.room.localParticipant?.identity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected generateCurrentId(): string {\n return shortuuid('SG_');\n }\n\n protected resetState() {\n this.currentId = this.generateCurrentId();\n this.capturing = false;\n this.latestText = '';\n }\n\n async captureText(text: string) {\n if (!this.participantIdentity) {\n return;\n }\n\n this.latestText = text;\n await this.handleCaptureText(text);\n }\n\n flush() {\n if (!this.participantIdentity || !this.capturing) {\n return;\n }\n\n this.capturing = false;\n this.handleFlush();\n }\n\n protected abstract handleCaptureText(text: string): Promise<void>;\n protected abstract handleFlush(): void;\n}\n\nexport class ParticipantTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private writer: TextStreamWriter | null = null;\n private flushTask: Task<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (this.flushTask && !this.flushTask.done) {\n await this.flushTask.result;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n // reuse the existing writer\n if (this.writer === null) {\n this.writer = await this.createTextWriter();\n }\n await this.writer.write(text);\n } else {\n const tmpWriter = await this.createTextWriter();\n await tmpWriter.write(text);\n await tmpWriter.close();\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected handleFlush() {\n const currWriter = this.writer;\n this.writer = null;\n this.flushTask = Task.from((controller) => this.flushTaskImpl(currWriter, controller.signal));\n }\n\n private async createTextWriter(attributes?: Record<string, string>): Promise<TextStreamWriter> {\n if (!this.participantIdentity) {\n throw new Error('participantIdentity not found');\n }\n\n if (!this.room.localParticipant) {\n throw new Error('localParticipant not found');\n }\n\n if (!attributes) {\n attributes = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'false',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n }\n attributes[ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID] = this.currentId;\n\n return await this.room.localParticipant.streamText({\n topic: TOPIC_TRANSCRIPTION,\n senderIdentity: this.participantIdentity,\n attributes,\n });\n }\n\n private async flushTaskImpl(writer: TextStreamWriter | null, signal: AbortSignal): Promise<void> {\n const attributes: Record<string, string> = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'true',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n\n const abortPromise = new Promise<void>((resolve) => {\n signal.addEventListener('abort', () => resolve());\n });\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n if (writer) {\n await Promise.race([writer.close(), abortPromise]);\n }\n } else {\n const tmpWriter = await Promise.race([this.createTextWriter(attributes), abortPromise]);\n if (signal.aborted || !tmpWriter) {\n return;\n }\n await Promise.race([tmpWriter.write(this.latestText), abortPromise]);\n if (signal.aborted) {\n return;\n }\n await Promise.race([tmpWriter.close(), abortPromise]);\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n}\n\nexport class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private pushedText: string = '';\n private flushTask: Promise<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (!this.trackId) {\n return;\n }\n\n if (this.flushTask) {\n await this.flushTask;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n if (this.isDeltaStream) {\n this.pushedText += text;\n } else {\n this.pushedText = text;\n }\n\n await this.publishTranscription(this.currentId, this.pushedText, false);\n }\n\n protected handleFlush() {\n if (!this.trackId) {\n return;\n }\n\n this.flushTask = this.publishTranscription(this.currentId, this.pushedText, true);\n this.resetState();\n }\n\n async publishTranscription(id: string, text: string, final: boolean, signal?: AbortSignal) {\n if (!this.participantIdentity || !this.trackId) {\n return;\n }\n\n try {\n if (this.room.isConnected) {\n if (signal?.aborted) {\n return;\n }\n\n await this.room.localParticipant?.publishTranscription({\n participantIdentity: this.participantIdentity,\n trackSid: this.trackId,\n segments: [{ id, text, final, startTime: BigInt(0), endTime: BigInt(0), language: '' }],\n });\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected resetState() {\n super.resetState();\n this.pushedText = '';\n }\n}\n\nexport class ParalellTextOutput extends TextOutput {\n /** @internal */\n _sinks: TextOutput[];\n\n constructor(sinks: TextOutput[], nextInChain?: TextOutput) {\n super(nextInChain);\n this._sinks = sinks;\n }\n\n async captureText(text: string) {\n await Promise.all(this._sinks.map((sink) => sink.captureText(text)));\n }\n\n flush() {\n for (const sink of this._sinks) {\n sink.flush();\n }\n }\n}\n\nexport interface AudioOutputOptions {\n sampleRate: number;\n numChannels: number;\n trackPublishOptions: TrackPublishOptions;\n queueSizeMs?: number;\n}\nexport class ParticipantAudioOutput extends AudioOutput {\n private room: Room;\n private options: AudioOutputOptions;\n private audioSource: AudioSource;\n private publication?: LocalTrackPublication;\n private flushTask?: Task<void>;\n private pushedDurationMs: number = 0;\n private startedFuture: Future<void> = new Future();\n private interruptedFuture: Future<void> = new Future();\n\n constructor(room: Room, options: AudioOutputOptions) {\n super(options.sampleRate);\n this.room = room;\n this.options = options;\n this.audioSource = new AudioSource(options.sampleRate, options.numChannels);\n }\n\n get subscribed(): boolean {\n return this.startedFuture.done;\n }\n\n async start(signal: AbortSignal): Promise<void> {\n await this.publishTrack(signal);\n }\n\n async captureFrame(frame: AudioFrame): Promise<void> {\n await this.startedFuture.await;\n\n super.captureFrame(frame);\n\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n this.pushedDurationMs += frame.samplesPerChannel / frame.sampleRate;\n await this.audioSource.captureFrame(frame);\n }\n\n private async waitForPlayoutTask(abortController: AbortController): Promise<void> {\n const abortFuture = new Future<boolean>();\n\n const resolveAbort = () => {\n if (!abortFuture.done) abortFuture.resolve(true);\n };\n\n abortController.signal.addEventListener('abort', resolveAbort);\n\n this.audioSource.waitForPlayout().finally(() => {\n abortController.signal.removeEventListener('abort', resolveAbort);\n if (!abortFuture.done) abortFuture.resolve(false);\n });\n\n const interrupted = await Promise.race([\n abortFuture.await,\n this.interruptedFuture.await.then(() => true),\n ]);\n\n let pushedDuration = this.pushedDurationMs;\n\n if (interrupted) {\n // Calculate actual played duration accounting for queued audio\n pushedDuration = Math.max(this.pushedDurationMs - this.audioSource.queuedDuration, 0);\n this.audioSource.clearQueue();\n }\n\n this.pushedDurationMs = 0;\n this.interruptedFuture = new Future();\n this.onPlaybackFinished({\n playbackPosition: pushedDuration,\n interrupted,\n });\n }\n\n /**\n * Flush any buffered audio, marking the current playback/segment as complete\n */\n flush(): void {\n super.flush();\n\n if (!this.pushedDurationMs) {\n return;\n }\n\n if (this.flushTask && !this.flushTask.done) {\n this.logger.error('flush called while playback is in progress');\n this.flushTask.cancel();\n }\n\n this.flushTask = Task.from((controller) => this.waitForPlayoutTask(controller));\n }\n\n clearBuffer(): void {\n if (!this.pushedDurationMs) {\n return;\n }\n\n this.interruptedFuture.resolve();\n }\n\n private async publishTrack(signal: AbortSignal) {\n const track = LocalAudioTrack.createAudioTrack('roomio_audio', this.audioSource);\n this.publication = await this.room.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n if (signal.aborted) {\n return;\n }\n\n await this.publication?.waitForSubscription();\n\n if (!this.startedFuture.done) {\n this.startedFuture.resolve();\n }\n }\n\n async close() {\n // TODO(AJS-106): add republish track\n await this.audioSource.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -38,6 +38,7 @@ export declare class ParticipantLegacyTranscriptionOutput extends BaseParticipan
|
|
|
38
38
|
protected resetState(): void;
|
|
39
39
|
}
|
|
40
40
|
export declare class ParalellTextOutput extends TextOutput {
|
|
41
|
+
/** @internal */
|
|
41
42
|
_sinks: TextOutput[];
|
|
42
43
|
constructor(sinks: TextOutput[], nextInChain?: TextOutput);
|
|
43
44
|
captureText(text: string): Promise<void>;
|
|
@@ -38,6 +38,7 @@ export declare class ParticipantLegacyTranscriptionOutput extends BaseParticipan
|
|
|
38
38
|
protected resetState(): void;
|
|
39
39
|
}
|
|
40
40
|
export declare class ParalellTextOutput extends TextOutput {
|
|
41
|
+
/** @internal */
|
|
41
42
|
_sinks: TextOutput[];
|
|
42
43
|
constructor(sinks: TextOutput[], nextInChain?: TextOutput);
|
|
43
44
|
captureText(text: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_output.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_output.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EACL,KAAK,UAAU,EAGf,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,IAAI,EAGT,mBAAmB,EAEpB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGnD,uBAAe,kCAAmC,SAAQ,UAAU;IAClE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;IACrB,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACpD,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,SAAS,EAAE,OAAO,CAAS;IACrC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAM;IAClC,SAAS,CAAC,SAAS,EAAE,MAAM,CAA4B;IACvD,SAAS,CAAC,MAAM,wBAAS;gBAEb,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAWxF,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAqBvD,SAAS,CAAC,gBAAgB,UAAW,sBAAsB,eAAe,iBAAiB,UAUzF;IAEF,SAAS,CAAC,qBAAqB,UAAW,qBAAqB,UAU7D;IAEF,SAAS,CAAC,iBAAiB,IAAI,MAAM;IAIrC,SAAS,CAAC,UAAU;IAMd,WAAW,CAAC,IAAI,EAAE,MAAM;IAS9B,KAAK;IASL,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,IAAI;CACvC;AAED,qBAAa,8BAA+B,SAAQ,kCAAkC;IACpF,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,SAAS,CAA2B;cAE5B,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B9D,SAAS,CAAC,WAAW;YAMP,gBAAgB;YA0BhB,aAAa;CAkC5B;AAED,qBAAa,oCAAqC,SAAQ,kCAAkC;IAC1F,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,SAAS,CAA8B;cAE/B,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB9D,SAAS,CAAC,WAAW;IASf,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;IAsBzF,SAAS,CAAC,UAAU;CAIrB;AAED,qBAAa,kBAAmB,SAAQ,UAAU;
|
|
1
|
+
{"version":3,"file":"_output.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_output.ts"],"names":[],"mappings":"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"}
|
|
@@ -226,7 +226,7 @@ class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionO
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
class ParalellTextOutput extends TextOutput {
|
|
229
|
-
|
|
229
|
+
/** @internal */
|
|
230
230
|
_sinks;
|
|
231
231
|
constructor(sinks, nextInChain) {
|
|
232
232
|
super(nextInChain);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_output.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RemoteParticipant } from '@livekit/rtc-node';\nimport {\n type AudioFrame,\n AudioSource,\n LocalAudioTrack,\n type LocalTrackPublication,\n type Participant,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n type TextStreamWriter,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport {\n ATTRIBUTE_TRANSCRIPTION_FINAL,\n ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID,\n ATTRIBUTE_TRANSCRIPTION_TRACK_ID,\n TOPIC_TRANSCRIPTION,\n} from '../../constants.js';\nimport { log } from '../../log.js';\nimport { Future, Task, shortuuid } from '../../utils.js';\nimport { AudioOutput, TextOutput } from '../io.js';\nimport { findMicrophoneTrackId } from '../transcription/index.js';\n\nabstract class BaseParticipantTranscriptionOutput extends TextOutput {\n protected room: Room;\n protected isDeltaStream: boolean;\n protected participantIdentity: string | null = null;\n protected trackId?: string;\n protected capturing: boolean = false;\n protected latestText: string = '';\n protected currentId: string = this.generateCurrentId();\n protected logger = log();\n\n constructor(room: Room, isDeltaStream: boolean, participant: Participant | string | null) {\n super();\n this.room = room;\n this.isDeltaStream = isDeltaStream;\n\n this.room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n this.room.on(RoomEvent.LocalTrackPublished, this.onLocalTrackPublished);\n\n this.setParticipant(participant);\n }\n\n setParticipant(participant: Participant | string | null) {\n if (typeof participant === 'string' || participant === null) {\n this.participantIdentity = participant;\n } else {\n this.participantIdentity = participant.identity;\n }\n\n if (!this.participantIdentity) {\n return;\n }\n\n try {\n this.trackId = findMicrophoneTrackId(this.room, this.participantIdentity);\n } catch (error) {\n // track id is optional for TextStream when audio is not published\n }\n\n this.flush();\n this.resetState();\n }\n\n protected onTrackPublished = (track: RemoteTrackPublication, participant: RemoteParticipant) => {\n if (\n !this.participantIdentity ||\n participant.identity !== this.participantIdentity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected onLocalTrackPublished = (track: LocalTrackPublication) => {\n if (\n !this.participantIdentity ||\n this.participantIdentity !== this.room.localParticipant?.identity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected generateCurrentId(): string {\n return shortuuid('SG_');\n }\n\n protected resetState() {\n this.currentId = this.generateCurrentId();\n this.capturing = false;\n this.latestText = '';\n }\n\n async captureText(text: string) {\n if (!this.participantIdentity) {\n return;\n }\n\n this.latestText = text;\n await this.handleCaptureText(text);\n }\n\n flush() {\n if (!this.participantIdentity || !this.capturing) {\n return;\n }\n\n this.capturing = false;\n this.handleFlush();\n }\n\n protected abstract handleCaptureText(text: string): Promise<void>;\n protected abstract handleFlush(): void;\n}\n\nexport class ParticipantTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private writer: TextStreamWriter | null = null;\n private flushTask: Task<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (this.flushTask && !this.flushTask.done) {\n await this.flushTask.result;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n // reuse the existing writer\n if (this.writer === null) {\n this.writer = await this.createTextWriter();\n }\n await this.writer.write(text);\n } else {\n const tmpWriter = await this.createTextWriter();\n await tmpWriter.write(text);\n await tmpWriter.close();\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected handleFlush() {\n const currWriter = this.writer;\n this.writer = null;\n this.flushTask = Task.from((controller) => this.flushTaskImpl(currWriter, controller.signal));\n }\n\n private async createTextWriter(attributes?: Record<string, string>): Promise<TextStreamWriter> {\n if (!this.participantIdentity) {\n throw new Error('participantIdentity not found');\n }\n\n if (!this.room.localParticipant) {\n throw new Error('localParticipant not found');\n }\n\n if (!attributes) {\n attributes = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'false',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n }\n attributes[ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID] = this.currentId;\n\n return await this.room.localParticipant.streamText({\n topic: TOPIC_TRANSCRIPTION,\n senderIdentity: this.participantIdentity,\n attributes,\n });\n }\n\n private async flushTaskImpl(writer: TextStreamWriter | null, signal: AbortSignal): Promise<void> {\n const attributes: Record<string, string> = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'true',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n\n const abortPromise = new Promise<void>((resolve) => {\n signal.addEventListener('abort', () => resolve());\n });\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n if (writer) {\n await Promise.race([writer.close(), abortPromise]);\n }\n } else {\n const tmpWriter = await Promise.race([this.createTextWriter(attributes), abortPromise]);\n if (signal.aborted || !tmpWriter) {\n return;\n }\n await Promise.race([tmpWriter.write(this.latestText), abortPromise]);\n if (signal.aborted) {\n return;\n }\n await Promise.race([tmpWriter.close(), abortPromise]);\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n}\n\nexport class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private pushedText: string = '';\n private flushTask: Promise<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (!this.trackId) {\n return;\n }\n\n if (this.flushTask) {\n await this.flushTask;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n if (this.isDeltaStream) {\n this.pushedText += text;\n } else {\n this.pushedText = text;\n }\n\n await this.publishTranscription(this.currentId, this.pushedText, false);\n }\n\n protected handleFlush() {\n if (!this.trackId) {\n return;\n }\n\n this.flushTask = this.publishTranscription(this.currentId, this.pushedText, true);\n this.resetState();\n }\n\n async publishTranscription(id: string, text: string, final: boolean, signal?: AbortSignal) {\n if (!this.participantIdentity || !this.trackId) {\n return;\n }\n\n try {\n if (this.room.isConnected) {\n if (signal?.aborted) {\n return;\n }\n\n await this.room.localParticipant?.publishTranscription({\n participantIdentity: this.participantIdentity,\n trackSid: this.trackId,\n segments: [{ id, text, final, startTime: BigInt(0), endTime: BigInt(0), language: '' }],\n });\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected resetState() {\n super.resetState();\n this.pushedText = '';\n }\n}\n\nexport class ParalellTextOutput extends TextOutput {\n /* @internal */\n _sinks: TextOutput[];\n\n constructor(sinks: TextOutput[], nextInChain?: TextOutput) {\n super(nextInChain);\n this._sinks = sinks;\n }\n\n async captureText(text: string) {\n await Promise.all(this._sinks.map((sink) => sink.captureText(text)));\n }\n\n flush() {\n for (const sink of this._sinks) {\n sink.flush();\n }\n }\n}\n\nexport interface AudioOutputOptions {\n sampleRate: number;\n numChannels: number;\n trackPublishOptions: TrackPublishOptions;\n queueSizeMs?: number;\n}\nexport class ParticipantAudioOutput extends AudioOutput {\n private room: Room;\n private options: AudioOutputOptions;\n private audioSource: AudioSource;\n private publication?: LocalTrackPublication;\n private flushTask?: Task<void>;\n private pushedDurationMs: number = 0;\n private startedFuture: Future<void> = new Future();\n private interruptedFuture: Future<void> = new Future();\n\n constructor(room: Room, options: AudioOutputOptions) {\n super(options.sampleRate);\n this.room = room;\n this.options = options;\n this.audioSource = new AudioSource(options.sampleRate, options.numChannels);\n }\n\n get subscribed(): boolean {\n return this.startedFuture.done;\n }\n\n async start(signal: AbortSignal): Promise<void> {\n await this.publishTrack(signal);\n }\n\n async captureFrame(frame: AudioFrame): Promise<void> {\n await this.startedFuture.await;\n\n super.captureFrame(frame);\n\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n this.pushedDurationMs += frame.samplesPerChannel / frame.sampleRate;\n await this.audioSource.captureFrame(frame);\n }\n\n private async waitForPlayoutTask(abortController: AbortController): Promise<void> {\n const abortFuture = new Future<boolean>();\n\n const resolveAbort = () => {\n if (!abortFuture.done) abortFuture.resolve(true);\n };\n\n abortController.signal.addEventListener('abort', resolveAbort);\n\n this.audioSource.waitForPlayout().finally(() => {\n abortController.signal.removeEventListener('abort', resolveAbort);\n if (!abortFuture.done) abortFuture.resolve(false);\n });\n\n const interrupted = await Promise.race([\n abortFuture.await,\n this.interruptedFuture.await.then(() => true),\n ]);\n\n let pushedDuration = this.pushedDurationMs;\n\n if (interrupted) {\n // Calculate actual played duration accounting for queued audio\n pushedDuration = Math.max(this.pushedDurationMs - this.audioSource.queuedDuration, 0);\n this.audioSource.clearQueue();\n }\n\n this.pushedDurationMs = 0;\n this.interruptedFuture = new Future();\n this.onPlaybackFinished({\n playbackPosition: pushedDuration,\n interrupted,\n });\n }\n\n /**\n * Flush any buffered audio, marking the current playback/segment as complete\n */\n flush(): void {\n super.flush();\n\n if (!this.pushedDurationMs) {\n return;\n }\n\n if (this.flushTask && !this.flushTask.done) {\n this.logger.error('flush called while playback is in progress');\n this.flushTask.cancel();\n }\n\n this.flushTask = Task.from((controller) => this.waitForPlayoutTask(controller));\n }\n\n clearBuffer(): void {\n if (!this.pushedDurationMs) {\n return;\n }\n\n this.interruptedFuture.resolve();\n }\n\n private async publishTrack(signal: AbortSignal) {\n const track = LocalAudioTrack.createAudioTrack('roomio_audio', this.audioSource);\n this.publication = await this.room.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n if (signal.aborted) {\n return;\n }\n\n await this.publication?.waitForSubscription();\n\n if (!this.startedFuture.done) {\n this.startedFuture.resolve();\n }\n }\n\n async close() {\n // TODO(AJS-106): add republish track\n await this.audioSource.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_output.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RemoteParticipant } from '@livekit/rtc-node';\nimport {\n type AudioFrame,\n AudioSource,\n LocalAudioTrack,\n type LocalTrackPublication,\n type Participant,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n type TextStreamWriter,\n TrackPublishOptions,\n TrackSource,\n} from '@livekit/rtc-node';\nimport {\n ATTRIBUTE_TRANSCRIPTION_FINAL,\n ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID,\n ATTRIBUTE_TRANSCRIPTION_TRACK_ID,\n TOPIC_TRANSCRIPTION,\n} from '../../constants.js';\nimport { log } from '../../log.js';\nimport { Future, Task, shortuuid } from '../../utils.js';\nimport { AudioOutput, TextOutput } from '../io.js';\nimport { findMicrophoneTrackId } from '../transcription/index.js';\n\nabstract class BaseParticipantTranscriptionOutput extends TextOutput {\n protected room: Room;\n protected isDeltaStream: boolean;\n protected participantIdentity: string | null = null;\n protected trackId?: string;\n protected capturing: boolean = false;\n protected latestText: string = '';\n protected currentId: string = this.generateCurrentId();\n protected logger = log();\n\n constructor(room: Room, isDeltaStream: boolean, participant: Participant | string | null) {\n super();\n this.room = room;\n this.isDeltaStream = isDeltaStream;\n\n this.room.on(RoomEvent.TrackPublished, this.onTrackPublished);\n this.room.on(RoomEvent.LocalTrackPublished, this.onLocalTrackPublished);\n\n this.setParticipant(participant);\n }\n\n setParticipant(participant: Participant | string | null) {\n if (typeof participant === 'string' || participant === null) {\n this.participantIdentity = participant;\n } else {\n this.participantIdentity = participant.identity;\n }\n\n if (!this.participantIdentity) {\n return;\n }\n\n try {\n this.trackId = findMicrophoneTrackId(this.room, this.participantIdentity);\n } catch (error) {\n // track id is optional for TextStream when audio is not published\n }\n\n this.flush();\n this.resetState();\n }\n\n protected onTrackPublished = (track: RemoteTrackPublication, participant: RemoteParticipant) => {\n if (\n !this.participantIdentity ||\n participant.identity !== this.participantIdentity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected onLocalTrackPublished = (track: LocalTrackPublication) => {\n if (\n !this.participantIdentity ||\n this.participantIdentity !== this.room.localParticipant?.identity ||\n track.source !== TrackSource.SOURCE_MICROPHONE\n ) {\n return;\n }\n\n this.trackId = track.sid;\n };\n\n protected generateCurrentId(): string {\n return shortuuid('SG_');\n }\n\n protected resetState() {\n this.currentId = this.generateCurrentId();\n this.capturing = false;\n this.latestText = '';\n }\n\n async captureText(text: string) {\n if (!this.participantIdentity) {\n return;\n }\n\n this.latestText = text;\n await this.handleCaptureText(text);\n }\n\n flush() {\n if (!this.participantIdentity || !this.capturing) {\n return;\n }\n\n this.capturing = false;\n this.handleFlush();\n }\n\n protected abstract handleCaptureText(text: string): Promise<void>;\n protected abstract handleFlush(): void;\n}\n\nexport class ParticipantTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private writer: TextStreamWriter | null = null;\n private flushTask: Task<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (this.flushTask && !this.flushTask.done) {\n await this.flushTask.result;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n // reuse the existing writer\n if (this.writer === null) {\n this.writer = await this.createTextWriter();\n }\n await this.writer.write(text);\n } else {\n const tmpWriter = await this.createTextWriter();\n await tmpWriter.write(text);\n await tmpWriter.close();\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected handleFlush() {\n const currWriter = this.writer;\n this.writer = null;\n this.flushTask = Task.from((controller) => this.flushTaskImpl(currWriter, controller.signal));\n }\n\n private async createTextWriter(attributes?: Record<string, string>): Promise<TextStreamWriter> {\n if (!this.participantIdentity) {\n throw new Error('participantIdentity not found');\n }\n\n if (!this.room.localParticipant) {\n throw new Error('localParticipant not found');\n }\n\n if (!attributes) {\n attributes = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'false',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n }\n attributes[ATTRIBUTE_TRANSCRIPTION_SEGMENT_ID] = this.currentId;\n\n return await this.room.localParticipant.streamText({\n topic: TOPIC_TRANSCRIPTION,\n senderIdentity: this.participantIdentity,\n attributes,\n });\n }\n\n private async flushTaskImpl(writer: TextStreamWriter | null, signal: AbortSignal): Promise<void> {\n const attributes: Record<string, string> = {\n [ATTRIBUTE_TRANSCRIPTION_FINAL]: 'true',\n };\n if (this.trackId) {\n attributes[ATTRIBUTE_TRANSCRIPTION_TRACK_ID] = this.trackId;\n }\n\n const abortPromise = new Promise<void>((resolve) => {\n signal.addEventListener('abort', () => resolve());\n });\n\n try {\n if (this.room.isConnected) {\n if (this.isDeltaStream) {\n if (writer) {\n await Promise.race([writer.close(), abortPromise]);\n }\n } else {\n const tmpWriter = await Promise.race([this.createTextWriter(attributes), abortPromise]);\n if (signal.aborted || !tmpWriter) {\n return;\n }\n await Promise.race([tmpWriter.write(this.latestText), abortPromise]);\n if (signal.aborted) {\n return;\n }\n await Promise.race([tmpWriter.close(), abortPromise]);\n }\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n}\n\nexport class ParticipantLegacyTranscriptionOutput extends BaseParticipantTranscriptionOutput {\n private pushedText: string = '';\n private flushTask: Promise<void> | null = null;\n\n protected async handleCaptureText(text: string): Promise<void> {\n if (!this.trackId) {\n return;\n }\n\n if (this.flushTask) {\n await this.flushTask;\n }\n\n if (!this.capturing) {\n this.resetState();\n this.capturing = true;\n }\n\n if (this.isDeltaStream) {\n this.pushedText += text;\n } else {\n this.pushedText = text;\n }\n\n await this.publishTranscription(this.currentId, this.pushedText, false);\n }\n\n protected handleFlush() {\n if (!this.trackId) {\n return;\n }\n\n this.flushTask = this.publishTranscription(this.currentId, this.pushedText, true);\n this.resetState();\n }\n\n async publishTranscription(id: string, text: string, final: boolean, signal?: AbortSignal) {\n if (!this.participantIdentity || !this.trackId) {\n return;\n }\n\n try {\n if (this.room.isConnected) {\n if (signal?.aborted) {\n return;\n }\n\n await this.room.localParticipant?.publishTranscription({\n participantIdentity: this.participantIdentity,\n trackSid: this.trackId,\n segments: [{ id, text, final, startTime: BigInt(0), endTime: BigInt(0), language: '' }],\n });\n }\n } catch (error) {\n this.logger.error(error, 'failed to publish transcription');\n }\n }\n\n protected resetState() {\n super.resetState();\n this.pushedText = '';\n }\n}\n\nexport class ParalellTextOutput extends TextOutput {\n /** @internal */\n _sinks: TextOutput[];\n\n constructor(sinks: TextOutput[], nextInChain?: TextOutput) {\n super(nextInChain);\n this._sinks = sinks;\n }\n\n async captureText(text: string) {\n await Promise.all(this._sinks.map((sink) => sink.captureText(text)));\n }\n\n flush() {\n for (const sink of this._sinks) {\n sink.flush();\n }\n }\n}\n\nexport interface AudioOutputOptions {\n sampleRate: number;\n numChannels: number;\n trackPublishOptions: TrackPublishOptions;\n queueSizeMs?: number;\n}\nexport class ParticipantAudioOutput extends AudioOutput {\n private room: Room;\n private options: AudioOutputOptions;\n private audioSource: AudioSource;\n private publication?: LocalTrackPublication;\n private flushTask?: Task<void>;\n private pushedDurationMs: number = 0;\n private startedFuture: Future<void> = new Future();\n private interruptedFuture: Future<void> = new Future();\n\n constructor(room: Room, options: AudioOutputOptions) {\n super(options.sampleRate);\n this.room = room;\n this.options = options;\n this.audioSource = new AudioSource(options.sampleRate, options.numChannels);\n }\n\n get subscribed(): boolean {\n return this.startedFuture.done;\n }\n\n async start(signal: AbortSignal): Promise<void> {\n await this.publishTrack(signal);\n }\n\n async captureFrame(frame: AudioFrame): Promise<void> {\n await this.startedFuture.await;\n\n super.captureFrame(frame);\n\n // TODO(AJS-102): use frame.durationMs once available in rtc-node\n this.pushedDurationMs += frame.samplesPerChannel / frame.sampleRate;\n await this.audioSource.captureFrame(frame);\n }\n\n private async waitForPlayoutTask(abortController: AbortController): Promise<void> {\n const abortFuture = new Future<boolean>();\n\n const resolveAbort = () => {\n if (!abortFuture.done) abortFuture.resolve(true);\n };\n\n abortController.signal.addEventListener('abort', resolveAbort);\n\n this.audioSource.waitForPlayout().finally(() => {\n abortController.signal.removeEventListener('abort', resolveAbort);\n if (!abortFuture.done) abortFuture.resolve(false);\n });\n\n const interrupted = await Promise.race([\n abortFuture.await,\n this.interruptedFuture.await.then(() => true),\n ]);\n\n let pushedDuration = this.pushedDurationMs;\n\n if (interrupted) {\n // Calculate actual played duration accounting for queued audio\n pushedDuration = Math.max(this.pushedDurationMs - this.audioSource.queuedDuration, 0);\n this.audioSource.clearQueue();\n }\n\n this.pushedDurationMs = 0;\n this.interruptedFuture = new Future();\n this.onPlaybackFinished({\n playbackPosition: pushedDuration,\n interrupted,\n });\n }\n\n /**\n * Flush any buffered audio, marking the current playback/segment as complete\n */\n flush(): void {\n super.flush();\n\n if (!this.pushedDurationMs) {\n return;\n }\n\n if (this.flushTask && !this.flushTask.done) {\n this.logger.error('flush called while playback is in progress');\n this.flushTask.cancel();\n }\n\n this.flushTask = Task.from((controller) => this.waitForPlayoutTask(controller));\n }\n\n clearBuffer(): void {\n if (!this.pushedDurationMs) {\n return;\n }\n\n this.interruptedFuture.resolve();\n }\n\n private async publishTrack(signal: AbortSignal) {\n const track = LocalAudioTrack.createAudioTrack('roomio_audio', this.audioSource);\n this.publication = await this.room.localParticipant?.publishTrack(\n track,\n new TrackPublishOptions({ source: TrackSource.SOURCE_MICROPHONE }),\n );\n\n if (signal.aborted) {\n return;\n }\n\n await this.publication?.waitForSubscription();\n\n if (!this.startedFuture.done) {\n this.startedFuture.resolve();\n }\n }\n\n async close() {\n // TODO(AJS-106): add republish track\n await this.audioSource.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -245,7 +245,7 @@ class RoomIO {
|
|
|
245
245
|
}
|
|
246
246
|
return this.transcriptionSynchronizer.textOutput;
|
|
247
247
|
}
|
|
248
|
-
|
|
248
|
+
/** Switch to a different participant */
|
|
249
249
|
setParticipant(participantIdentity) {
|
|
250
250
|
var _a;
|
|
251
251
|
this.logger.debug({ participantIdentity }, "setting participant");
|