@elizaos/plugin-streaming 2.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/api/stream-persistence.d.ts +68 -0
- package/dist/api/stream-persistence.js +181 -0
- package/dist/api/stream-persistence.js.map +1 -0
- package/dist/api/stream-route-state.d.ts +59 -0
- package/dist/api/stream-route-state.js +1 -0
- package/dist/api/stream-route-state.js.map +1 -0
- package/dist/api/stream-routes.d.ts +43 -0
- package/dist/api/stream-routes.js +609 -0
- package/dist/api/stream-routes.js.map +1 -0
- package/dist/api/streaming-text.d.ts +10 -0
- package/dist/api/streaming-text.js +88 -0
- package/dist/api/streaming-text.js.map +1 -0
- package/dist/api/streaming-types.d.ts +2 -0
- package/dist/api/streaming-types.js +1 -0
- package/dist/api/streaming-types.js.map +1 -0
- package/dist/api/tts-routes.d.ts +25 -0
- package/dist/api/tts-routes.js +158 -0
- package/dist/api/tts-routes.js.map +1 -0
- package/dist/core.d.ts +164 -0
- package/dist/core.js +495 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +147 -0
- package/dist/index.js.map +1 -0
- package/dist/services/stream-manager.d.ts +124 -0
- package/dist/services/stream-manager.js +531 -0
- package/dist/services/stream-manager.js.map +1 -0
- package/dist/services/tts-stream-bridge.d.ts +103 -0
- package/dist/services/tts-stream-bridge.js +327 -0
- package/dist/services/tts-stream-bridge.js.map +1 -0
- package/package.json +106 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getHeadlessCaptureConfig,
|
|
3
|
+
parseDestinationQuery,
|
|
4
|
+
readOverlayLayout,
|
|
5
|
+
readStreamSettings,
|
|
6
|
+
safeDestId,
|
|
7
|
+
seedOverlayDefaults,
|
|
8
|
+
validateStreamSettings,
|
|
9
|
+
writeOverlayLayout,
|
|
10
|
+
writeStreamSettings
|
|
11
|
+
} from "./api/stream-persistence.js";
|
|
12
|
+
import {
|
|
13
|
+
detectCaptureMode,
|
|
14
|
+
ensureXvfb,
|
|
15
|
+
getActiveDestination,
|
|
16
|
+
handleStreamRoute
|
|
17
|
+
} from "./api/stream-routes.js";
|
|
18
|
+
import {
|
|
19
|
+
mergeStreamingText,
|
|
20
|
+
resolveStreamingUpdate
|
|
21
|
+
} from "./api/streaming-text.js";
|
|
22
|
+
import { handleTtsRoutes } from "./api/tts-routes.js";
|
|
23
|
+
export * from "./core.js";
|
|
24
|
+
import {
|
|
25
|
+
streamManager
|
|
26
|
+
} from "./services/stream-manager.js";
|
|
27
|
+
import {
|
|
28
|
+
buildPresetLayout,
|
|
29
|
+
buildStreamOpAction,
|
|
30
|
+
createStreamingPlugin,
|
|
31
|
+
streamStatusProvider
|
|
32
|
+
} from "./core.js";
|
|
33
|
+
const TWITCH_CFG = {
|
|
34
|
+
platformId: "twitch",
|
|
35
|
+
platformName: "Twitch",
|
|
36
|
+
streamKeyEnvVar: "TWITCH_STREAM_KEY",
|
|
37
|
+
defaultRtmpUrl: "rtmp://live.twitch.tv/app",
|
|
38
|
+
cloudRelay: true,
|
|
39
|
+
defaultOverlayLayout: buildPresetLayout("Twitch", [
|
|
40
|
+
"viewer-count",
|
|
41
|
+
"action-ticker",
|
|
42
|
+
"branding"
|
|
43
|
+
])
|
|
44
|
+
};
|
|
45
|
+
const YOUTUBE_CFG = {
|
|
46
|
+
platformId: "youtube",
|
|
47
|
+
platformName: "YouTube",
|
|
48
|
+
pluginName: "youtube",
|
|
49
|
+
streamKeyEnvVar: "YOUTUBE_STREAM_KEY",
|
|
50
|
+
defaultRtmpUrl: "rtmp://a.rtmp.youtube.com/live2",
|
|
51
|
+
rtmpUrlEnvVar: "YOUTUBE_RTMP_URL",
|
|
52
|
+
cloudRelay: true,
|
|
53
|
+
defaultOverlayLayout: buildPresetLayout("YouTube", [
|
|
54
|
+
"viewer-count",
|
|
55
|
+
"thought-bubble",
|
|
56
|
+
"branding"
|
|
57
|
+
])
|
|
58
|
+
};
|
|
59
|
+
const X_CFG = {
|
|
60
|
+
platformId: "x",
|
|
61
|
+
platformName: "X (Twitter)",
|
|
62
|
+
streamKeyEnvVar: "X_STREAM_KEY",
|
|
63
|
+
defaultRtmpUrl: "",
|
|
64
|
+
rtmpUrlEnvVar: "X_RTMP_URL",
|
|
65
|
+
cloudRelay: true,
|
|
66
|
+
defaultOverlayLayout: buildPresetLayout("X", [
|
|
67
|
+
"thought-bubble",
|
|
68
|
+
"action-ticker",
|
|
69
|
+
"branding"
|
|
70
|
+
])
|
|
71
|
+
};
|
|
72
|
+
const PUMPFUN_CFG = {
|
|
73
|
+
platformId: "pumpfun",
|
|
74
|
+
platformName: "pump.fun",
|
|
75
|
+
streamKeyEnvVar: "PUMPFUN_STREAM_KEY",
|
|
76
|
+
defaultRtmpUrl: "",
|
|
77
|
+
rtmpUrlEnvVar: "PUMPFUN_RTMP_URL",
|
|
78
|
+
cloudRelay: true,
|
|
79
|
+
defaultOverlayLayout: buildPresetLayout("pump.fun", [
|
|
80
|
+
"viewer-count",
|
|
81
|
+
"action-ticker",
|
|
82
|
+
"branding"
|
|
83
|
+
])
|
|
84
|
+
};
|
|
85
|
+
const twitchBundle = createStreamingPlugin(TWITCH_CFG);
|
|
86
|
+
const youtubeBundle = createStreamingPlugin(YOUTUBE_CFG);
|
|
87
|
+
const xBundle = createStreamingPlugin(X_CFG);
|
|
88
|
+
const pumpfunBundle = createStreamingPlugin(PUMPFUN_CFG);
|
|
89
|
+
function createTwitchDestination(runtime, config) {
|
|
90
|
+
return twitchBundle.createDestination(runtime, config);
|
|
91
|
+
}
|
|
92
|
+
function createYoutubeDestination(runtime, config) {
|
|
93
|
+
return youtubeBundle.createDestination(runtime, config);
|
|
94
|
+
}
|
|
95
|
+
function createXStreamDestination(runtime, config) {
|
|
96
|
+
return xBundle.createDestination(runtime, config);
|
|
97
|
+
}
|
|
98
|
+
function createPumpfunDestination(runtime, config) {
|
|
99
|
+
return pumpfunBundle.createDestination(runtime, config);
|
|
100
|
+
}
|
|
101
|
+
const streamingPlugin = {
|
|
102
|
+
name: "streaming",
|
|
103
|
+
description: "RTMP live streaming: Twitch, YouTube, X (Twitter), pump.fun, custom ingest URLs, and named RTMP sources.",
|
|
104
|
+
get config() {
|
|
105
|
+
const out = {};
|
|
106
|
+
for (const cfg of [TWITCH_CFG, YOUTUBE_CFG, X_CFG, PUMPFUN_CFG]) {
|
|
107
|
+
out[cfg.streamKeyEnvVar] = process.env[cfg.streamKeyEnvVar] ?? null;
|
|
108
|
+
if (cfg.rtmpUrlEnvVar) {
|
|
109
|
+
out[cfg.rtmpUrlEnvVar] = process.env[cfg.rtmpUrlEnvVar] ?? null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
out.CUSTOM_RTMP_URL = process.env.CUSTOM_RTMP_URL ?? null;
|
|
113
|
+
out.CUSTOM_RTMP_KEY = process.env.CUSTOM_RTMP_KEY ?? null;
|
|
114
|
+
return out;
|
|
115
|
+
},
|
|
116
|
+
actions: [buildStreamOpAction()],
|
|
117
|
+
providers: [streamStatusProvider],
|
|
118
|
+
async init() {
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var index_default = streamingPlugin;
|
|
122
|
+
export {
|
|
123
|
+
createPumpfunDestination,
|
|
124
|
+
createTwitchDestination,
|
|
125
|
+
createXStreamDestination,
|
|
126
|
+
createYoutubeDestination,
|
|
127
|
+
index_default as default,
|
|
128
|
+
detectCaptureMode,
|
|
129
|
+
ensureXvfb,
|
|
130
|
+
getActiveDestination,
|
|
131
|
+
getHeadlessCaptureConfig,
|
|
132
|
+
handleStreamRoute,
|
|
133
|
+
handleTtsRoutes,
|
|
134
|
+
mergeStreamingText,
|
|
135
|
+
parseDestinationQuery,
|
|
136
|
+
readOverlayLayout,
|
|
137
|
+
readStreamSettings,
|
|
138
|
+
resolveStreamingUpdate,
|
|
139
|
+
safeDestId,
|
|
140
|
+
seedOverlayDefaults,
|
|
141
|
+
streamManager,
|
|
142
|
+
streamingPlugin,
|
|
143
|
+
validateStreamSettings,
|
|
144
|
+
writeOverlayLayout,
|
|
145
|
+
writeStreamSettings
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @elizaos/plugin-streaming — RTMP destinations (Twitch, YouTube, X, pump.fun, custom/named ingest).\n */\n\nexport {\n getHeadlessCaptureConfig,\n parseDestinationQuery,\n readOverlayLayout,\n readStreamSettings,\n type StreamVisualSettings,\n type StreamVoiceSettings,\n safeDestId,\n seedOverlayDefaults,\n validateStreamSettings,\n writeOverlayLayout,\n writeStreamSettings,\n} from \"./api/stream-persistence.js\";\nexport type { StreamRouteState } from \"./api/stream-route-state.js\";\nexport {\n detectCaptureMode,\n ensureXvfb,\n getActiveDestination,\n handleStreamRoute,\n} from \"./api/stream-routes.js\";\nexport {\n mergeStreamingText,\n resolveStreamingUpdate,\n type StreamingUpdate,\n type StreamingUpdateKind,\n} from \"./api/streaming-text.js\";\nexport { handleTtsRoutes, type TtsRouteContext } from \"./api/tts-routes.js\";\nexport * from \"./core.js\";\nexport {\n type AudioSource,\n type StreamConfig,\n streamManager,\n} from \"./services/stream-manager.js\";\n\nimport type { IAgentRuntime, Plugin } from \"@elizaos/core\";\nimport {\n buildPresetLayout,\n buildStreamOpAction,\n createStreamingPlugin,\n type StreamingDestination,\n type StreamingPluginConfig,\n streamStatusProvider,\n} from \"./core.js\";\n\nconst TWITCH_CFG: StreamingPluginConfig = {\n platformId: \"twitch\",\n platformName: \"Twitch\",\n streamKeyEnvVar: \"TWITCH_STREAM_KEY\",\n defaultRtmpUrl: \"rtmp://live.twitch.tv/app\",\n cloudRelay: true,\n defaultOverlayLayout: buildPresetLayout(\"Twitch\", [\n \"viewer-count\",\n \"action-ticker\",\n \"branding\",\n ]),\n};\n\nconst YOUTUBE_CFG: StreamingPluginConfig = {\n platformId: \"youtube\",\n platformName: \"YouTube\",\n pluginName: \"youtube\",\n streamKeyEnvVar: \"YOUTUBE_STREAM_KEY\",\n defaultRtmpUrl: \"rtmp://a.rtmp.youtube.com/live2\",\n rtmpUrlEnvVar: \"YOUTUBE_RTMP_URL\",\n cloudRelay: true,\n defaultOverlayLayout: buildPresetLayout(\"YouTube\", [\n \"viewer-count\",\n \"thought-bubble\",\n \"branding\",\n ]),\n};\n\nconst X_CFG: StreamingPluginConfig = {\n platformId: \"x\",\n platformName: \"X (Twitter)\",\n streamKeyEnvVar: \"X_STREAM_KEY\",\n defaultRtmpUrl: \"\",\n rtmpUrlEnvVar: \"X_RTMP_URL\",\n cloudRelay: true,\n defaultOverlayLayout: buildPresetLayout(\"X\", [\n \"thought-bubble\",\n \"action-ticker\",\n \"branding\",\n ]),\n};\n\nconst PUMPFUN_CFG: StreamingPluginConfig = {\n platformId: \"pumpfun\",\n platformName: \"pump.fun\",\n streamKeyEnvVar: \"PUMPFUN_STREAM_KEY\",\n defaultRtmpUrl: \"\",\n rtmpUrlEnvVar: \"PUMPFUN_RTMP_URL\",\n cloudRelay: true,\n defaultOverlayLayout: buildPresetLayout(\"pump.fun\", [\n \"viewer-count\",\n \"action-ticker\",\n \"branding\",\n ]),\n};\n\nconst twitchBundle = createStreamingPlugin(TWITCH_CFG);\nconst youtubeBundle = createStreamingPlugin(YOUTUBE_CFG);\nconst xBundle = createStreamingPlugin(X_CFG);\nconst pumpfunBundle = createStreamingPlugin(PUMPFUN_CFG);\n\nexport function createTwitchDestination(\n runtime?: IAgentRuntime,\n config?: { streamKey?: string },\n): StreamingDestination {\n return twitchBundle.createDestination(runtime, config);\n}\n\nexport function createYoutubeDestination(\n runtime?: IAgentRuntime,\n config?: { streamKey?: string; rtmpUrl?: string },\n): StreamingDestination {\n return youtubeBundle.createDestination(runtime, config);\n}\n\nexport function createXStreamDestination(\n runtime?: IAgentRuntime,\n config?: { streamKey?: string; rtmpUrl?: string },\n): StreamingDestination {\n return xBundle.createDestination(runtime, config);\n}\n\nexport function createPumpfunDestination(\n runtime?: IAgentRuntime,\n config?: { streamKey?: string; rtmpUrl?: string },\n): StreamingDestination {\n return pumpfunBundle.createDestination(runtime, config);\n}\n\nexport const streamingPlugin: Plugin = {\n name: \"streaming\",\n description:\n \"RTMP live streaming: Twitch, YouTube, X (Twitter), pump.fun, custom ingest URLs, and named RTMP sources.\",\n\n get config() {\n const out: Record<string, string | null> = {};\n for (const cfg of [TWITCH_CFG, YOUTUBE_CFG, X_CFG, PUMPFUN_CFG]) {\n out[cfg.streamKeyEnvVar] = process.env[cfg.streamKeyEnvVar] ?? null;\n if (cfg.rtmpUrlEnvVar) {\n out[cfg.rtmpUrlEnvVar] = process.env[cfg.rtmpUrlEnvVar] ?? null;\n }\n }\n out.CUSTOM_RTMP_URL = process.env.CUSTOM_RTMP_URL ?? null;\n out.CUSTOM_RTMP_KEY = process.env.CUSTOM_RTMP_KEY ?? null;\n return out;\n },\n\n actions: [buildStreamOpAction()],\n providers: [streamStatusProvider],\n\n async init() {},\n};\n\nexport default streamingPlugin;\n"],"mappings":"AAIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,uBAA6C;AACtD,cAAc;AACd;AAAA,EAGE;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,OACK;AAEP,MAAM,aAAoC;AAAA,EACxC,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,sBAAsB,kBAAkB,UAAU;AAAA,IAChD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,MAAM,cAAqC;AAAA,EACzC,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,sBAAsB,kBAAkB,WAAW;AAAA,IACjD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,MAAM,QAA+B;AAAA,EACnC,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,sBAAsB,kBAAkB,KAAK;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,MAAM,cAAqC;AAAA,EACzC,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,sBAAsB,kBAAkB,YAAY;AAAA,IAClD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,MAAM,eAAe,sBAAsB,UAAU;AACrD,MAAM,gBAAgB,sBAAsB,WAAW;AACvD,MAAM,UAAU,sBAAsB,KAAK;AAC3C,MAAM,gBAAgB,sBAAsB,WAAW;AAEhD,SAAS,wBACd,SACA,QACsB;AACtB,SAAO,aAAa,kBAAkB,SAAS,MAAM;AACvD;AAEO,SAAS,yBACd,SACA,QACsB;AACtB,SAAO,cAAc,kBAAkB,SAAS,MAAM;AACxD;AAEO,SAAS,yBACd,SACA,QACsB;AACtB,SAAO,QAAQ,kBAAkB,SAAS,MAAM;AAClD;AAEO,SAAS,yBACd,SACA,QACsB;AACtB,SAAO,cAAc,kBAAkB,SAAS,MAAM;AACxD;AAEO,MAAM,kBAA0B;AAAA,EACrC,MAAM;AAAA,EACN,aACE;AAAA,EAEF,IAAI,SAAS;AACX,UAAM,MAAqC,CAAC;AAC5C,eAAW,OAAO,CAAC,YAAY,aAAa,OAAO,WAAW,GAAG;AAC/D,UAAI,IAAI,eAAe,IAAI,QAAQ,IAAI,IAAI,eAAe,KAAK;AAC/D,UAAI,IAAI,eAAe;AACrB,YAAI,IAAI,aAAa,IAAI,QAAQ,IAAI,IAAI,aAAa,KAAK;AAAA,MAC7D;AAAA,IACF;AACA,QAAI,kBAAkB,QAAQ,IAAI,mBAAmB;AACrD,QAAI,kBAAkB,QAAQ,IAAI,mBAAmB;AACrD,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,CAAC,oBAAoB,CAAC;AAAA,EAC/B,WAAW,CAAC,oBAAoB;AAAA,EAEhC,MAAM,OAAO;AAAA,EAAC;AAChB;AAEA,IAAO,gBAAQ;","names":[]}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ITtsStreamBridge } from './tts-stream-bridge.js';
|
|
2
|
+
import 'node:stream';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Stream Manager — cross-platform RTMP streaming via FFmpeg.
|
|
6
|
+
*
|
|
7
|
+
* Supports multiple input modes:
|
|
8
|
+
* - "pipe": Receives JPEG frames via writeFrame() → FFmpeg stdin (image2pipe).
|
|
9
|
+
* Used for streaming desktop window contents captured by the host bridge.
|
|
10
|
+
* - "avfoundation" / "screen": macOS native screen capture.
|
|
11
|
+
* - "x11grab": Linux virtual display capture (Xvfb). Used for GPU-backed game streams.
|
|
12
|
+
* - "file": Reads a continuously-updated JPEG file (browser-capture).
|
|
13
|
+
* - "testsrc": Solid color test pattern (default fallback).
|
|
14
|
+
*
|
|
15
|
+
* Audio support:
|
|
16
|
+
* - "silent": Synthetic silent audio (anullsrc) — default.
|
|
17
|
+
* - "system": System/desktop audio capture.
|
|
18
|
+
* - "microphone": Microphone input.
|
|
19
|
+
* - File path: Play an audio file as stream audio.
|
|
20
|
+
*
|
|
21
|
+
* Volume control:
|
|
22
|
+
* - setVolume(0-100), mute(), unmute() — restarts FFmpeg to apply.
|
|
23
|
+
*
|
|
24
|
+
* Usage:
|
|
25
|
+
* import { streamManager } from "./services/stream-manager";
|
|
26
|
+
* await streamManager.start({ rtmpUrl, rtmpKey, inputMode: "pipe" });
|
|
27
|
+
* streamManager.writeFrame(jpegBuffer); // called from frame capture
|
|
28
|
+
* streamManager.setVolume(50); // adjust volume mid-stream
|
|
29
|
+
* await streamManager.stop();
|
|
30
|
+
*
|
|
31
|
+
* @module services/stream-manager
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type AudioSource = "silent" | "system" | "microphone" | "tts";
|
|
35
|
+
interface StreamConfig {
|
|
36
|
+
rtmpUrl: string;
|
|
37
|
+
rtmpKey: string;
|
|
38
|
+
/** FFmpeg video input source. Defaults to "testsrc" (test pattern). */
|
|
39
|
+
inputMode?: "testsrc" | "avfoundation" | "screen" | "pipe" | "file" | "x11grab";
|
|
40
|
+
/** avfoundation video device index (default "3" = Capture screen 0 on macOS) */
|
|
41
|
+
videoDevice?: string;
|
|
42
|
+
/** Path to JPEG frame file (for "file" input mode) */
|
|
43
|
+
frameFile?: string;
|
|
44
|
+
/** Resolution (default "1280x720") */
|
|
45
|
+
resolution?: string;
|
|
46
|
+
/** Video bitrate (default "2500k") */
|
|
47
|
+
bitrate?: string;
|
|
48
|
+
/** Frame rate (default 15) */
|
|
49
|
+
framerate?: number;
|
|
50
|
+
/** X11 display for x11grab mode (e.g., ":99"). Default ":99". */
|
|
51
|
+
display?: string;
|
|
52
|
+
/** Audio source. Default "silent" (anullsrc). Can also be an absolute file path. */
|
|
53
|
+
audioSource?: AudioSource | string;
|
|
54
|
+
/** Audio device identifier (platform-specific). For macOS avfoundation: device index. For Linux: pulse/alsa device name. */
|
|
55
|
+
audioDevice?: string;
|
|
56
|
+
/** Volume level 0–100. Default 80. Applied as FFmpeg audio filter. */
|
|
57
|
+
volume?: number;
|
|
58
|
+
/** Whether audio is muted. Default false. Overrides volume to 0 when true. */
|
|
59
|
+
muted?: boolean;
|
|
60
|
+
}
|
|
61
|
+
declare class StreamManager {
|
|
62
|
+
private ffmpeg;
|
|
63
|
+
private _running;
|
|
64
|
+
private startedAt;
|
|
65
|
+
private _frameCount;
|
|
66
|
+
/** Current stream config — stored for restart on volume/audio changes. */
|
|
67
|
+
private _config;
|
|
68
|
+
/** Current volume level (0–100). */
|
|
69
|
+
private _volume;
|
|
70
|
+
/** Whether audio is muted. */
|
|
71
|
+
private _muted;
|
|
72
|
+
/** Auto-restart state. */
|
|
73
|
+
private _restartAttempts;
|
|
74
|
+
private _maxRestartAttempts;
|
|
75
|
+
private _restartDecayTimer;
|
|
76
|
+
private _intentionalStop;
|
|
77
|
+
/** Pending auto-restart timer — cleared in stop() to prevent races. */
|
|
78
|
+
private _restartTimer;
|
|
79
|
+
/** Guard: prevents concurrent start() calls from orphaning FFmpeg. */
|
|
80
|
+
private _starting;
|
|
81
|
+
isRunning(): boolean;
|
|
82
|
+
getUptime(): number;
|
|
83
|
+
getHealth(): {
|
|
84
|
+
running: boolean;
|
|
85
|
+
ffmpegAlive: boolean;
|
|
86
|
+
uptime: number;
|
|
87
|
+
frameCount: number;
|
|
88
|
+
volume: number;
|
|
89
|
+
muted: boolean;
|
|
90
|
+
audioSource: string;
|
|
91
|
+
inputMode: "pipe" | "testsrc" | "avfoundation" | "screen" | "file" | "x11grab" | null;
|
|
92
|
+
};
|
|
93
|
+
getVolume(): number;
|
|
94
|
+
isMuted(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Set volume (0–100). Restarts FFmpeg if currently streaming to apply the change.
|
|
97
|
+
*/
|
|
98
|
+
setVolume(level: number): Promise<void>;
|
|
99
|
+
/** Mute audio. Restarts FFmpeg if currently streaming. */
|
|
100
|
+
mute(): Promise<void>;
|
|
101
|
+
/** Unmute audio. Restarts FFmpeg if currently streaming. */
|
|
102
|
+
unmute(): Promise<void>;
|
|
103
|
+
/** Restart the stream with updated config (preserves uptime tracking). */
|
|
104
|
+
private restart;
|
|
105
|
+
/**
|
|
106
|
+
* Write a JPEG frame to FFmpeg's stdin (only works in "pipe" mode).
|
|
107
|
+
* Returns true if the frame was accepted.
|
|
108
|
+
*/
|
|
109
|
+
writeFrame(jpegData: Buffer): boolean;
|
|
110
|
+
start(config: StreamConfig): Promise<void>;
|
|
111
|
+
private _startInner;
|
|
112
|
+
stop(): Promise<{
|
|
113
|
+
uptime: number;
|
|
114
|
+
}>;
|
|
115
|
+
/** Attempt to restart FFmpeg after unexpected exit with exponential backoff. */
|
|
116
|
+
private autoRestart;
|
|
117
|
+
private buildVideoInputArgs;
|
|
118
|
+
private buildAudioInputArgs;
|
|
119
|
+
/** Get the TTS stream bridge for external speak triggers. */
|
|
120
|
+
getTtsBridge(): ITtsStreamBridge;
|
|
121
|
+
}
|
|
122
|
+
declare const streamManager: StreamManager;
|
|
123
|
+
|
|
124
|
+
export { type AudioSource, type StreamConfig, streamManager };
|