tjbot-ce 3.0.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 +202 -0
- package/README.md +382 -0
- package/dist/camera/camera.d.ts +62 -0
- package/dist/camera/camera.d.ts.map +1 -0
- package/dist/camera/camera.js +155 -0
- package/dist/camera/camera.js.map +1 -0
- package/dist/camera/index.d.ts +18 -0
- package/dist/camera/index.d.ts.map +1 -0
- package/dist/camera/index.js +18 -0
- package/dist/camera/index.js.map +1 -0
- package/dist/config/config-types.d.ts +75 -0
- package/dist/config/config-types.d.ts.map +1 -0
- package/dist/config/config-types.generated.d.ts +495 -0
- package/dist/config/config-types.generated.d.ts.map +1 -0
- package/dist/config/config-types.generated.js +2 -0
- package/dist/config/config-types.generated.js.map +1 -0
- package/dist/config/config-types.js +175 -0
- package/dist/config/config-types.js.map +1 -0
- package/dist/config/index.d.ts +20 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/tjbot-config.d.ts +98 -0
- package/dist/config/tjbot-config.d.ts.map +1 -0
- package/dist/config/tjbot-config.js +309 -0
- package/dist/config/tjbot-config.js.map +1 -0
- package/dist/config/vendor/colors.yaml +61 -0
- package/dist/config/vendor/model-registry.yaml +275 -0
- package/dist/config/vendor/tjbot-config.schema.yaml +792 -0
- package/dist/config/vendor/tjbot.default.toml +452 -0
- package/dist/led/index.d.ts +20 -0
- package/dist/led/index.d.ts.map +1 -0
- package/dist/led/index.js +20 -0
- package/dist/led/index.js.map +1 -0
- package/dist/led/led-common-anode.d.ts +38 -0
- package/dist/led/led-common-anode.d.ts.map +1 -0
- package/dist/led/led-common-anode.js +79 -0
- package/dist/led/led-common-anode.js.map +1 -0
- package/dist/led/led-neopixel-spi.d.ts +60 -0
- package/dist/led/led-neopixel-spi.d.ts.map +1 -0
- package/dist/led/led-neopixel-spi.js +216 -0
- package/dist/led/led-neopixel-spi.js.map +1 -0
- package/dist/led/led-neopixel-ws281x.js +186 -0
- package/dist/led/led-neopixel.d.ts +57 -0
- package/dist/led/led-neopixel.d.ts.map +1 -0
- package/dist/led/led-neopixel.js +235 -0
- package/dist/led/led-neopixel.js.map +1 -0
- package/dist/microphone/index.d.ts +18 -0
- package/dist/microphone/index.d.ts.map +1 -0
- package/dist/microphone/index.js +18 -0
- package/dist/microphone/index.js.map +1 -0
- package/dist/microphone/microphone.d.ts +65 -0
- package/dist/microphone/microphone.d.ts.map +1 -0
- package/dist/microphone/microphone.js +179 -0
- package/dist/microphone/microphone.js.map +1 -0
- package/dist/rpi-drivers/index.d.ts +22 -0
- package/dist/rpi-drivers/index.d.ts.map +1 -0
- package/dist/rpi-drivers/index.js +22 -0
- package/dist/rpi-drivers/index.js.map +1 -0
- package/dist/rpi-drivers/rpi-detect.d.ts +24 -0
- package/dist/rpi-drivers/rpi-detect.d.ts.map +1 -0
- package/dist/rpi-drivers/rpi-detect.js +49 -0
- package/dist/rpi-drivers/rpi-detect.js.map +1 -0
- package/dist/rpi-drivers/rpi-driver.d.ts +116 -0
- package/dist/rpi-drivers/rpi-driver.d.ts.map +1 -0
- package/dist/rpi-drivers/rpi-driver.js +261 -0
- package/dist/rpi-drivers/rpi-driver.js.map +1 -0
- package/dist/rpi-drivers/rpi3-driver.d.ts +47 -0
- package/dist/rpi-drivers/rpi3-driver.d.ts.map +1 -0
- package/dist/rpi-drivers/rpi3-driver.js +145 -0
- package/dist/rpi-drivers/rpi3-driver.js.map +1 -0
- package/dist/rpi-drivers/rpi4-driver.d.ts +35 -0
- package/dist/rpi-drivers/rpi4-driver.d.ts.map +1 -0
- package/dist/rpi-drivers/rpi4-driver.js +101 -0
- package/dist/rpi-drivers/rpi4-driver.js.map +1 -0
- package/dist/rpi-drivers/rpi5-driver.d.ts +33 -0
- package/dist/rpi-drivers/rpi5-driver.d.ts.map +1 -0
- package/dist/rpi-drivers/rpi5-driver.js +78 -0
- package/dist/rpi-drivers/rpi5-driver.js.map +1 -0
- package/dist/servo/index.d.ts +19 -0
- package/dist/servo/index.d.ts.map +1 -0
- package/dist/servo/index.js +19 -0
- package/dist/servo/index.js.map +1 -0
- package/dist/servo/servo-constants.d.ts +33 -0
- package/dist/servo/servo-constants.d.ts.map +1 -0
- package/dist/servo/servo-constants.js +34 -0
- package/dist/servo/servo-constants.js.map +1 -0
- package/dist/servo/servo-lgpio.d.ts +82 -0
- package/dist/servo/servo-lgpio.d.ts.map +1 -0
- package/dist/servo/servo-lgpio.js +178 -0
- package/dist/servo/servo-lgpio.js.map +1 -0
- package/dist/speaker/audio-player.d.ts +30 -0
- package/dist/speaker/audio-player.d.ts.map +1 -0
- package/dist/speaker/audio-player.js +68 -0
- package/dist/speaker/audio-player.js.map +1 -0
- package/dist/speaker/index.d.ts +18 -0
- package/dist/speaker/index.d.ts.map +1 -0
- package/dist/speaker/index.js +18 -0
- package/dist/speaker/index.js.map +1 -0
- package/dist/speaker/speaker.d.ts +53 -0
- package/dist/speaker/speaker.d.ts.map +1 -0
- package/dist/speaker/speaker.js +125 -0
- package/dist/speaker/speaker.js.map +1 -0
- package/dist/stt/backends/azure-stt.d.ts +32 -0
- package/dist/stt/backends/azure-stt.d.ts.map +1 -0
- package/dist/stt/backends/azure-stt.js +227 -0
- package/dist/stt/backends/azure-stt.js.map +1 -0
- package/dist/stt/backends/google-cloud-stt.d.ts +31 -0
- package/dist/stt/backends/google-cloud-stt.d.ts.map +1 -0
- package/dist/stt/backends/google-cloud-stt.js +371 -0
- package/dist/stt/backends/google-cloud-stt.js.map +1 -0
- package/dist/stt/backends/ibm-watson-stt.d.ts +32 -0
- package/dist/stt/backends/ibm-watson-stt.d.ts.map +1 -0
- package/dist/stt/backends/ibm-watson-stt.js +190 -0
- package/dist/stt/backends/ibm-watson-stt.js.map +1 -0
- package/dist/stt/backends/sherpa-onnx-stt.d.ts +117 -0
- package/dist/stt/backends/sherpa-onnx-stt.d.ts.map +1 -0
- package/dist/stt/backends/sherpa-onnx-stt.js +694 -0
- package/dist/stt/backends/sherpa-onnx-stt.js.map +1 -0
- package/dist/stt/index.d.ts +20 -0
- package/dist/stt/index.d.ts.map +1 -0
- package/dist/stt/index.js +21 -0
- package/dist/stt/index.js.map +1 -0
- package/dist/stt/stt-engine.d.ts +68 -0
- package/dist/stt/stt-engine.d.ts.map +1 -0
- package/dist/stt/stt-engine.js +99 -0
- package/dist/stt/stt-engine.js.map +1 -0
- package/dist/stt/stt-utils.d.ts +36 -0
- package/dist/stt/stt-utils.d.ts.map +1 -0
- package/dist/stt/stt-utils.js +112 -0
- package/dist/stt/stt-utils.js.map +1 -0
- package/dist/stt/stt.d.ts +52 -0
- package/dist/stt/stt.d.ts.map +1 -0
- package/dist/stt/stt.js +100 -0
- package/dist/stt/stt.js.map +1 -0
- package/dist/tjbot.d.ts +317 -0
- package/dist/tjbot.d.ts.map +1 -0
- package/dist/tjbot.js +736 -0
- package/dist/tjbot.js.map +1 -0
- package/dist/tts/backends/azure-tts.d.ts +30 -0
- package/dist/tts/backends/azure-tts.d.ts.map +1 -0
- package/dist/tts/backends/azure-tts.js +92 -0
- package/dist/tts/backends/azure-tts.js.map +1 -0
- package/dist/tts/backends/google-cloud-tts.d.ts +38 -0
- package/dist/tts/backends/google-cloud-tts.d.ts.map +1 -0
- package/dist/tts/backends/google-cloud-tts.js +116 -0
- package/dist/tts/backends/google-cloud-tts.js.map +1 -0
- package/dist/tts/backends/ibm-watson-tts.d.ts +42 -0
- package/dist/tts/backends/ibm-watson-tts.d.ts.map +1 -0
- package/dist/tts/backends/ibm-watson-tts.js +99 -0
- package/dist/tts/backends/ibm-watson-tts.js.map +1 -0
- package/dist/tts/backends/sherpa-onnx-tts.d.ts +80 -0
- package/dist/tts/backends/sherpa-onnx-tts.d.ts.map +1 -0
- package/dist/tts/backends/sherpa-onnx-tts.js +237 -0
- package/dist/tts/backends/sherpa-onnx-tts.js.map +1 -0
- package/dist/tts/index.d.ts +19 -0
- package/dist/tts/index.d.ts.map +1 -0
- package/dist/tts/index.js +20 -0
- package/dist/tts/index.js.map +1 -0
- package/dist/tts/tts-engine.d.ts +67 -0
- package/dist/tts/tts-engine.d.ts.map +1 -0
- package/dist/tts/tts-engine.js +109 -0
- package/dist/tts/tts-engine.js.map +1 -0
- package/dist/tts/tts.d.ts +47 -0
- package/dist/tts/tts.d.ts.map +1 -0
- package/dist/tts/tts.js +101 -0
- package/dist/tts/tts.js.map +1 -0
- package/dist/utils/colors.d.ts +39 -0
- package/dist/utils/colors.d.ts.map +1 -0
- package/dist/utils/colors.js +155 -0
- package/dist/utils/colors.js.map +1 -0
- package/dist/utils/constants.d.ts +41 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +43 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/credentials.d.ts +43 -0
- package/dist/utils/credentials.d.ts.map +1 -0
- package/dist/utils/credentials.js +121 -0
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/errors.d.ts +26 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +32 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +25 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logging.d.ts +44 -0
- package/dist/utils/logging.d.ts.map +1 -0
- package/dist/utils/logging.js +113 -0
- package/dist/utils/logging.js.map +1 -0
- package/dist/utils/model-registry.d.ts +142 -0
- package/dist/utils/model-registry.d.ts.map +1 -0
- package/dist/utils/model-registry.js +391 -0
- package/dist/utils/model-registry.js.map +1 -0
- package/dist/utils/utils.d.ts +33 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +50 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/vision/backends/azure-vision.d.ts +33 -0
- package/dist/vision/backends/azure-vision.d.ts.map +1 -0
- package/dist/vision/backends/azure-vision.js +151 -0
- package/dist/vision/backends/azure-vision.js.map +1 -0
- package/dist/vision/backends/google-cloud-vision.d.ts +32 -0
- package/dist/vision/backends/google-cloud-vision.d.ts.map +1 -0
- package/dist/vision/backends/google-cloud-vision.js +193 -0
- package/dist/vision/backends/google-cloud-vision.js.map +1 -0
- package/dist/vision/backends/onnx.d.ts +116 -0
- package/dist/vision/backends/onnx.d.ts.map +1 -0
- package/dist/vision/backends/onnx.js +781 -0
- package/dist/vision/backends/onnx.js.map +1 -0
- package/dist/vision/index.d.ts +19 -0
- package/dist/vision/index.d.ts.map +1 -0
- package/dist/vision/index.js +20 -0
- package/dist/vision/index.js.map +1 -0
- package/dist/vision/vision-engine.d.ts +131 -0
- package/dist/vision/vision-engine.d.ts.map +1 -0
- package/dist/vision/vision-engine.js +97 -0
- package/dist/vision/vision-engine.js.map +1 -0
- package/dist/vision/vision.d.ts +48 -0
- package/dist/vision/vision.d.ts.map +1 -0
- package/dist/vision/vision.js +83 -0
- package/dist/vision/vision.js.map +1 -0
- package/package.json +124 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 IBM Corp. All Rights Reserved.
|
|
3
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { createRequire } from 'module';
|
|
18
|
+
import { getLogger } from '../utils/logging.js';
|
|
19
|
+
import { TJBotError } from '../utils/errors.js';
|
|
20
|
+
import { MAX_PULSE_MS, MID_PULSE_MS, MIN_PULSE_MS } from './servo-constants.js';
|
|
21
|
+
const logger = getLogger(import.meta.url);
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
// lgpio is published as CommonJS; createRequire avoids ESM namespace interop issues.
|
|
24
|
+
const lgpio = require('lgpio');
|
|
25
|
+
/**
|
|
26
|
+
* Servo controller using lgpio on Raspberry Pi GPIO character devices
|
|
27
|
+
*/
|
|
28
|
+
export class LGPIOServoController {
|
|
29
|
+
chipNumber;
|
|
30
|
+
pin;
|
|
31
|
+
freq;
|
|
32
|
+
chipHandle;
|
|
33
|
+
claimed = false;
|
|
34
|
+
currentPulseMs;
|
|
35
|
+
running;
|
|
36
|
+
autoStopTimer;
|
|
37
|
+
autoStopDelayMs;
|
|
38
|
+
/**
|
|
39
|
+
* Create a LGPIOServoController instance
|
|
40
|
+
* @param chipNumber GPIO chip number (usually 0)
|
|
41
|
+
* @param pin GPIO pin number (BCM)
|
|
42
|
+
* @param freq PWM frequency in Hz (default 50 for standard servos)
|
|
43
|
+
*/
|
|
44
|
+
constructor(chipNumber, pin, freq = 50, autoStopDelayMs = 2000) {
|
|
45
|
+
this.chipNumber = chipNumber;
|
|
46
|
+
this.pin = pin;
|
|
47
|
+
this.freq = freq;
|
|
48
|
+
this.currentPulseMs = MID_PULSE_MS;
|
|
49
|
+
this.running = false;
|
|
50
|
+
this.autoStopDelayMs = autoStopDelayMs;
|
|
51
|
+
logger.debug(`LGPIOServoController initialized with config:
|
|
52
|
+
chip: ${chipNumber}
|
|
53
|
+
pin: ${pin}
|
|
54
|
+
frequency: ${freq} Hz`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set the servo to a specific position.
|
|
58
|
+
* @param position Servo position in microseconds (500-2500 for standard servos)
|
|
59
|
+
*/
|
|
60
|
+
setPosition(position) {
|
|
61
|
+
const pulseMs = position / 1000;
|
|
62
|
+
logger.verbose(`setting servo position to ${position} μs (${pulseMs} ms)`);
|
|
63
|
+
this.setPulseWidth(pulseMs);
|
|
64
|
+
}
|
|
65
|
+
ensureStarted() {
|
|
66
|
+
if (this.running)
|
|
67
|
+
return;
|
|
68
|
+
logger.debug('starting LGPIOServoController');
|
|
69
|
+
const handle = lgpio.gpiochipOpen(this.chipNumber);
|
|
70
|
+
lgpio.gpioClaimOutput(handle, this.pin);
|
|
71
|
+
this.chipHandle = handle;
|
|
72
|
+
this.claimed = true;
|
|
73
|
+
this.running = true;
|
|
74
|
+
}
|
|
75
|
+
setServoPulse(pulseMs) {
|
|
76
|
+
if (this.chipHandle === undefined) {
|
|
77
|
+
throw new TJBotError('Servo GPIO is not initialized');
|
|
78
|
+
}
|
|
79
|
+
logger.debug(`setting servo pulse: ${pulseMs.toFixed(2)} ms`);
|
|
80
|
+
const periodMs = 1000 / this.freq;
|
|
81
|
+
const dutyCycle = Math.max(0, Math.min(100, (pulseMs / periodMs) * 100));
|
|
82
|
+
// 0 cycles means continuous output until changed.
|
|
83
|
+
lgpio.txPwm(this.chipHandle, this.pin, this.freq, dutyCycle, 0, 0);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Start the servo controller worker
|
|
87
|
+
*/
|
|
88
|
+
start() {
|
|
89
|
+
try {
|
|
90
|
+
this.ensureStarted();
|
|
91
|
+
this.setServoPulse(this.currentPulseMs);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
logger.error('ServoController failed to start:', err);
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Stop the servo controller and clean up resources
|
|
100
|
+
*/
|
|
101
|
+
async stop() {
|
|
102
|
+
logger.debug('stopping LGPIOServoController');
|
|
103
|
+
this.running = false;
|
|
104
|
+
if (this.autoStopTimer) {
|
|
105
|
+
clearTimeout(this.autoStopTimer);
|
|
106
|
+
this.autoStopTimer = undefined;
|
|
107
|
+
}
|
|
108
|
+
if (this.claimed && this.chipHandle !== undefined) {
|
|
109
|
+
try {
|
|
110
|
+
lgpio.txPwm(this.chipHandle, this.pin, this.freq, 0, 0, 0);
|
|
111
|
+
lgpio.gpioWrite(this.chipHandle, this.pin, false);
|
|
112
|
+
lgpio.gpioFree(this.chipHandle, this.pin);
|
|
113
|
+
lgpio.gpiochipClose(this.chipHandle);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
logger.warn('ServoController cleanup warning:', err);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
this.claimed = false;
|
|
120
|
+
this.chipHandle = undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Set pulse width in milliseconds
|
|
126
|
+
* Valid range is 0.5-2.5ms for standard servos
|
|
127
|
+
* @param pulseMs Pulse width in milliseconds
|
|
128
|
+
*/
|
|
129
|
+
setPulseWidth(pulseMs) {
|
|
130
|
+
this.currentPulseMs = Math.max(MIN_PULSE_MS, Math.min(MAX_PULSE_MS, pulseMs));
|
|
131
|
+
this.ensureStarted();
|
|
132
|
+
this.setServoPulse(this.currentPulseMs);
|
|
133
|
+
// Reset auto-stop timer
|
|
134
|
+
if (this.autoStopTimer) {
|
|
135
|
+
clearTimeout(this.autoStopTimer);
|
|
136
|
+
}
|
|
137
|
+
this.autoStopTimer = setTimeout(() => {
|
|
138
|
+
logger.debug('ServoController auto-stopping after inactivity');
|
|
139
|
+
this.stop();
|
|
140
|
+
}, this.autoStopDelayMs);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set servo angle (0-180 degrees)
|
|
144
|
+
* 0° = 0.5ms pulse, 90° = 1.5ms pulse, 180° = 2.5ms pulse
|
|
145
|
+
* @param angle Angle in degrees (0-180)
|
|
146
|
+
*/
|
|
147
|
+
setAngle(angle) {
|
|
148
|
+
angle = Math.max(0, Math.min(180, angle));
|
|
149
|
+
const pulse = MIN_PULSE_MS + (angle / 180.0) * (MAX_PULSE_MS - MIN_PULSE_MS);
|
|
150
|
+
this.setPulseWidth(pulse);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get the current pulse width
|
|
154
|
+
*/
|
|
155
|
+
getPulseWidth() {
|
|
156
|
+
return this.currentPulseMs;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get the current angle (approximately)
|
|
160
|
+
*/
|
|
161
|
+
getAngle() {
|
|
162
|
+
return Math.round(((this.currentPulseMs - MIN_PULSE_MS) / (MAX_PULSE_MS - MIN_PULSE_MS)) * 180);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Check if the controller is running
|
|
166
|
+
*/
|
|
167
|
+
isRunning() {
|
|
168
|
+
return this.running;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Cleanup and stop the controller
|
|
172
|
+
*/
|
|
173
|
+
async cleanup() {
|
|
174
|
+
logger.debug('LGPIOServoController cleanup');
|
|
175
|
+
await this.stop();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=servo-lgpio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servo-lgpio.js","sourceRoot":"","sources":["../../src/servo/servo-lgpio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAiB,MAAM,sBAAsB,CAAC;AAE/F,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,qFAAqF;AACrF,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAc5B,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACrB,UAAU,CAAS;IACnB,GAAG,CAAS;IACZ,IAAI,CAAS;IACb,UAAU,CAAU;IACpB,OAAO,GAAG,KAAK,CAAC;IAChB,cAAc,CAAS;IACvB,OAAO,CAAU;IACjB,aAAa,CAAkB;IAC/B,eAAe,CAAS;IAEhC;;;;;OAKG;IACH,YAAY,UAAkB,EAAE,GAAW,EAAE,IAAI,GAAG,EAAE,EAAE,eAAe,GAAG,IAAI;QAC1E,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QAEvC,MAAM,CAAC,KAAK,CAAC;oBACD,UAAU;mBACX,GAAG;yBACG,IAAI,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,QAAuB;QAC/B,MAAM,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,6BAA6B,QAAQ,QAAQ,OAAO,MAAM,CAAC,CAAC;QAC3E,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAEO,aAAa,CAAC,OAAe;QACjC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,wBAAwB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAEzE,kDAAkD;QAClD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IAED;;OAEG;IACH,KAAK;QACD,IAAI,CAAC;YACD,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YACtD,MAAM,GAAG,CAAC;QACd,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACN,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAE9C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QACnC,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAChD,IAAI,CAAC;gBACD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3D,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAClD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1C,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;oBAAS,CAAC;gBACP,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;gBACrB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAChC,CAAC;QACL,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,OAAe;QACzB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QAC9E,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAExC,wBAAwB;QACxB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACjC,MAAM,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;YAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,KAAa;QAClB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,YAAY,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC;QAC7E,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,aAAa;QACT,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IACpG,CAAC;IAED;;OAEG;IACH,SAAS;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACT,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC7C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;CACJ"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from 'events';
|
|
17
|
+
/**
|
|
18
|
+
* Native audio player that uses aplay for audio playback on Raspbian/ALSA systems
|
|
19
|
+
* Provides the same API surface as sound-player package
|
|
20
|
+
*/
|
|
21
|
+
export declare class AudioPlayer extends EventEmitter {
|
|
22
|
+
private process;
|
|
23
|
+
/**
|
|
24
|
+
* Play an audio file using aplay
|
|
25
|
+
* @param audioPath Path to the audio file to play
|
|
26
|
+
* @param device Optional audio device to use (e.g., 'hw:0,0')
|
|
27
|
+
*/
|
|
28
|
+
play(audioPath: string, device?: string): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=audio-player.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-player.d.ts","sourceRoot":"","sources":["../../src/speaker/audio-player.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMtC;;;GAGG;AACH,qBAAa,WAAY,SAAQ,YAAY;IACzC,OAAO,CAAC,OAAO,CAA6B;IAE5C;;;;OAIG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;CA2CjD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from 'events';
|
|
17
|
+
import { spawn } from 'child_process';
|
|
18
|
+
import { getLogger } from '../utils/logging.js';
|
|
19
|
+
const logger = getLogger(import.meta.url);
|
|
20
|
+
/**
|
|
21
|
+
* Native audio player that uses aplay for audio playback on Raspbian/ALSA systems
|
|
22
|
+
* Provides the same API surface as sound-player package
|
|
23
|
+
*/
|
|
24
|
+
export class AudioPlayer extends EventEmitter {
|
|
25
|
+
process = null;
|
|
26
|
+
/**
|
|
27
|
+
* Play an audio file using aplay
|
|
28
|
+
* @param audioPath Path to the audio file to play
|
|
29
|
+
* @param device Optional audio device to use (e.g., 'hw:0,0')
|
|
30
|
+
*/
|
|
31
|
+
play(audioPath, device) {
|
|
32
|
+
const args = [audioPath];
|
|
33
|
+
// Add device parameter if specified
|
|
34
|
+
if (device && device !== '') {
|
|
35
|
+
args.unshift('-D', device);
|
|
36
|
+
}
|
|
37
|
+
// Log the command being executed
|
|
38
|
+
logger.verbose(`Playing audio with command: aplay ${args.join(' ')}`);
|
|
39
|
+
// Spawn aplay process
|
|
40
|
+
this.process = spawn('aplay', args, {
|
|
41
|
+
stdio: ['ignore', 'ignore', 'pipe'], // Only capture stderr for errors
|
|
42
|
+
});
|
|
43
|
+
let stderrOutput = '';
|
|
44
|
+
// Capture stderr for error reporting
|
|
45
|
+
if (this.process.stderr) {
|
|
46
|
+
this.process.stderr.on('data', (data) => {
|
|
47
|
+
stderrOutput += data.toString();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Handle process completion
|
|
51
|
+
this.process.on('close', (code) => {
|
|
52
|
+
this.process = null;
|
|
53
|
+
if (code === 0) {
|
|
54
|
+
this.emit('complete');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const error = new Error(`aplay exited with code ${code}: ${stderrOutput}`);
|
|
58
|
+
this.emit('error', error);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// Handle process errors (e.g., aplay not found)
|
|
62
|
+
this.process.on('error', (err) => {
|
|
63
|
+
this.process = null;
|
|
64
|
+
this.emit('error', err);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=audio-player.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-player.js","sourceRoot":"","sources":["../../src/speaker/audio-player.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,YAAY;IACjC,OAAO,GAAwB,IAAI,CAAC;IAE5C;;;;OAIG;IACH,IAAI,CAAC,SAAiB,EAAE,MAAe;QACnC,MAAM,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAEzB,oCAAoC;QACpC,IAAI,MAAM,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QAED,iCAAiC;QACjC,MAAM,CAAC,OAAO,CAAC,qCAAqC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEtE,sBAAsB;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YAChC,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,iCAAiC;SACzE,CAAC,CAAC;QAEH,IAAI,YAAY,GAAG,EAAE,CAAC;QAEtB,qCAAqC;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBACpC,YAAY,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,CAAC,CAAC,CAAC;QACP,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YAEpB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,0BAA0B,IAAI,KAAK,YAAY,EAAE,CAAC,CAAC;gBAC3E,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,gDAAgD;QAChD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 IBM Corp. All Rights Reserved.
|
|
3
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
export { SpeakerController } from './speaker.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/speaker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 IBM Corp. All Rights Reserved.
|
|
3
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
export { SpeakerController } from './speaker.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/speaker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 IBM Corp. All Rights Reserved.
|
|
3
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Speaker controller for TJBot
|
|
19
|
+
* Handles audio playback and text-to-speech synthesis
|
|
20
|
+
*/
|
|
21
|
+
export declare class SpeakerController {
|
|
22
|
+
private device;
|
|
23
|
+
private onPauseCallback?;
|
|
24
|
+
private onResumeCallback?;
|
|
25
|
+
constructor();
|
|
26
|
+
/**
|
|
27
|
+
* Auto-detect the first available audio playback device
|
|
28
|
+
* Prefers USB audio devices over HDMI devices
|
|
29
|
+
* @returns The device string (e.g., 'plughw:0,0') or empty string if none found
|
|
30
|
+
*/
|
|
31
|
+
private detectSpeakerDevice;
|
|
32
|
+
/**
|
|
33
|
+
* Initialize the speaker with configuration
|
|
34
|
+
* @param device Optional specific audio device to use (auto-detected if not specified)
|
|
35
|
+
*/
|
|
36
|
+
initialize(device?: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Set callbacks for pause/resume (typically to pause/resume microphone)
|
|
39
|
+
* @param onPause Callback when audio playback starts
|
|
40
|
+
* @param onResume Callback when audio playback ends
|
|
41
|
+
*/
|
|
42
|
+
setAudioLifecycleCallbacks(onPause?: () => void, onResume?: () => void): void;
|
|
43
|
+
/**
|
|
44
|
+
* Play audio from a file
|
|
45
|
+
* @param audioPath Path to the audio file to play
|
|
46
|
+
*/
|
|
47
|
+
playAudio(audioPath: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Clean up resources
|
|
50
|
+
*/
|
|
51
|
+
cleanup(): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=speaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speaker.d.ts","sourceRoot":"","sources":["../../src/speaker/speaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH;;;GAGG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAC,CAAa;IACrC,OAAO,CAAC,gBAAgB,CAAC,CAAa;;IAMtC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IA6B3B;;;OAGG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAYjC;;;;OAIG;IACH,0BAA0B,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI;IAK7E;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCjD;;OAEG;IACH,OAAO,IAAI,IAAI;CAGlB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 IBM Corp. All Rights Reserved.
|
|
3
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { AudioPlayer } from './audio-player.js';
|
|
18
|
+
import { once } from 'events';
|
|
19
|
+
import { execSync } from 'child_process';
|
|
20
|
+
import { getLogger } from '../utils/logging.js';
|
|
21
|
+
const logger = getLogger(import.meta.url);
|
|
22
|
+
/**
|
|
23
|
+
* Speaker controller for TJBot
|
|
24
|
+
* Handles audio playback and text-to-speech synthesis
|
|
25
|
+
*/
|
|
26
|
+
export class SpeakerController {
|
|
27
|
+
device;
|
|
28
|
+
onPauseCallback;
|
|
29
|
+
onResumeCallback;
|
|
30
|
+
constructor() {
|
|
31
|
+
this.device = '';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Auto-detect the first available audio playback device
|
|
35
|
+
* Prefers USB audio devices over HDMI devices
|
|
36
|
+
* @returns The device string (e.g., 'plughw:0,0') or empty string if none found
|
|
37
|
+
*/
|
|
38
|
+
detectSpeakerDevice() {
|
|
39
|
+
try {
|
|
40
|
+
// Run aplay -l to list playback devices
|
|
41
|
+
const output = execSync('aplay -l', { encoding: 'utf8' });
|
|
42
|
+
const lines = output.split('\n');
|
|
43
|
+
// Prefer USB audio devices over HDMI (which may not work without connected display)
|
|
44
|
+
const usbLine = lines.find((line) => line.includes('USB') && line.match(/card (\d+):.*device (\d+):/));
|
|
45
|
+
const targetLine = usbLine || lines.find((line) => line.match(/card (\d+):.*device (\d+):/));
|
|
46
|
+
if (targetLine) {
|
|
47
|
+
const match = targetLine.match(/card (\d+):.*device (\d+):/);
|
|
48
|
+
if (match) {
|
|
49
|
+
const card = match[1];
|
|
50
|
+
const device = match[2];
|
|
51
|
+
const deviceString = `plughw:${card},${device}`;
|
|
52
|
+
logger.verbose(`🔈 auto-detected speaker device: ${deviceString}`);
|
|
53
|
+
return deviceString;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
logger.warn('No audio playback devices found');
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
logger.error('Error detecting speaker device:', error);
|
|
61
|
+
return '';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Initialize the speaker with configuration
|
|
66
|
+
* @param device Optional specific audio device to use (auto-detected if not specified)
|
|
67
|
+
*/
|
|
68
|
+
initialize(device) {
|
|
69
|
+
// Auto-detect device if not specified
|
|
70
|
+
let selectedDevice = device || '';
|
|
71
|
+
if (!selectedDevice || selectedDevice === '') {
|
|
72
|
+
selectedDevice = this.detectSpeakerDevice();
|
|
73
|
+
}
|
|
74
|
+
this.device = selectedDevice;
|
|
75
|
+
logger.verbose(`Initialized speaker on device ${this.device}`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Set callbacks for pause/resume (typically to pause/resume microphone)
|
|
79
|
+
* @param onPause Callback when audio playback starts
|
|
80
|
+
* @param onResume Callback when audio playback ends
|
|
81
|
+
*/
|
|
82
|
+
setAudioLifecycleCallbacks(onPause, onResume) {
|
|
83
|
+
this.onPauseCallback = onPause;
|
|
84
|
+
this.onResumeCallback = onResume;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Play audio from a file
|
|
88
|
+
* @param audioPath Path to the audio file to play
|
|
89
|
+
*/
|
|
90
|
+
async playAudio(audioPath) {
|
|
91
|
+
// pause listening while we play a sound
|
|
92
|
+
if (this.onPauseCallback) {
|
|
93
|
+
this.onPauseCallback();
|
|
94
|
+
}
|
|
95
|
+
const player = new AudioPlayer();
|
|
96
|
+
if (this.device !== undefined && this.device !== '') {
|
|
97
|
+
logger.verbose(`Playing audio file ${audioPath} through user-defined audio device (${this.device})`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
logger.verbose(`Playing audio file ${audioPath} through default audio device`);
|
|
101
|
+
}
|
|
102
|
+
// Set up event handlers
|
|
103
|
+
player.on('complete', () => {
|
|
104
|
+
logger.debug('Audio playback finished');
|
|
105
|
+
// resume listening
|
|
106
|
+
if (this.onResumeCallback) {
|
|
107
|
+
this.onResumeCallback();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
player.on('error', (err) => {
|
|
111
|
+
logger.error('Error occurred while playing audio', err);
|
|
112
|
+
});
|
|
113
|
+
// play the audio
|
|
114
|
+
player.play(audioPath, this.device);
|
|
115
|
+
// wait for the audio to finish playing, either by completing playback or by throwing an error
|
|
116
|
+
await Promise.race([once(player, 'complete'), once(player, 'error')]);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Clean up resources
|
|
120
|
+
*/
|
|
121
|
+
cleanup() {
|
|
122
|
+
logger.debug('SpeakerController cleanup (no-op)');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=speaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speaker.js","sourceRoot":"","sources":["../../src/speaker/speaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IAClB,MAAM,CAAS;IACf,eAAe,CAAc;IAC7B,gBAAgB,CAAc;IAEtC;QACI,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACK,mBAAmB;QACvB,IAAI,CAAC;YACD,wCAAwC;YACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAEjC,oFAAoF;YACpF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvG,MAAM,UAAU,GAAG,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;YAE7F,IAAI,UAAU,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;gBAC7D,IAAI,KAAK,EAAE,CAAC;oBACR,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACtB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACxB,MAAM,YAAY,GAAG,UAAU,IAAI,IAAI,MAAM,EAAE,CAAC;oBAChD,MAAM,CAAC,OAAO,CAAC,oCAAoC,YAAY,EAAE,CAAC,CAAC;oBACnE,OAAO,YAAY,CAAC;gBACxB,CAAC;YACL,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YAC/C,OAAO,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;YACvD,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,MAAe;QACtB,sCAAsC;QACtC,IAAI,cAAc,GAAG,MAAM,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,cAAc,IAAI,cAAc,KAAK,EAAE,EAAE,CAAC;YAC3C,cAAc,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAChD,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC;QAE7B,MAAM,CAAC,OAAO,CAAC,iCAAiC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACH,0BAA0B,CAAC,OAAoB,EAAE,QAAqB;QAClE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,SAAiB;QAC7B,wCAAwC;QACxC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,eAAe,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAEjC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YAClD,MAAM,CAAC,OAAO,CAAC,sBAAsB,SAAS,uCAAuC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACzG,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,OAAO,CAAC,sBAAsB,SAAS,+BAA+B,CAAC,CAAC;QACnF,CAAC;QAED,wBAAwB;QACxB,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;YACvB,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAExC,mBAAmB;YACnB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxB,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC5B,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,iBAAiB;QACjB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpC,8FAA8F;QAC9F,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,OAAO;QACH,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACtD,CAAC;CACJ"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026-present TJBot Contributors. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { STTEngine, STTRequestOptions } from '../stt-engine.js';
|
|
17
|
+
/**
|
|
18
|
+
* Azure Cognitive Services Speech-to-Text Engine
|
|
19
|
+
*
|
|
20
|
+
* Cloud-based speech recognition using Microsoft Azure Speech Services.
|
|
21
|
+
* Requires Azure subscription key and region to be configured.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export declare class AzureSTTEngine extends STTEngine {
|
|
25
|
+
private microphoneRate;
|
|
26
|
+
private microphoneChannels;
|
|
27
|
+
private subscriptionKey?;
|
|
28
|
+
private region?;
|
|
29
|
+
initialize(microphoneRate: number, microphoneChannels: number): Promise<void>;
|
|
30
|
+
transcribe(micStream: NodeJS.ReadableStream, options: STTRequestOptions): Promise<string>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=azure-stt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-stt.d.ts","sourceRoot":"","sources":["../../../src/stt/backends/azure-stt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAKhE;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,SAAS;IACzC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IAElB,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B7E,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;CAwNlG"}
|