node-libcec 1.0.0

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.
@@ -0,0 +1,96 @@
1
+ #ifndef CEC_ADAPTER_H
2
+ #define CEC_ADAPTER_H
3
+
4
+ #include <napi.h>
5
+ #include <libcec/cec.h>
6
+ #include <memory>
7
+ #include <string>
8
+ #include <mutex>
9
+
10
+ using namespace CEC;
11
+
12
+ class CECCallbackHandler;
13
+
14
+ class CECAdapter : public Napi::ObjectWrap<CECAdapter> {
15
+ public:
16
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
17
+ CECAdapter(const Napi::CallbackInfo& info);
18
+ ~CECAdapter();
19
+
20
+ private:
21
+ // Adapter connection methods
22
+ Napi::Value Open(const Napi::CallbackInfo& info);
23
+ Napi::Value Close(const Napi::CallbackInfo& info);
24
+ Napi::Value PingAdapter(const Napi::CallbackInfo& info);
25
+ Napi::Value GetAdapterVendorId(const Napi::CallbackInfo& info);
26
+ Napi::Value GetAdapterProductId(const Napi::CallbackInfo& info);
27
+ Napi::Value GetLibInfo(const Napi::CallbackInfo& info);
28
+
29
+ // Device discovery
30
+ static Napi::Value DetectAdapters(const Napi::CallbackInfo& info);
31
+
32
+ // Device control methods
33
+ Napi::Value PowerOnDevices(const Napi::CallbackInfo& info);
34
+ Napi::Value StandbyDevices(const Napi::CallbackInfo& info);
35
+ Napi::Value SetActiveSource(const Napi::CallbackInfo& info);
36
+ Napi::Value SetInactiveView(const Napi::CallbackInfo& info);
37
+
38
+ // Command transmission
39
+ Napi::Value Transmit(const Napi::CallbackInfo& info);
40
+ Napi::Value SendKeypress(const Napi::CallbackInfo& info);
41
+ Napi::Value SendKeyRelease(const Napi::CallbackInfo& info);
42
+
43
+ // Device information queries
44
+ Napi::Value GetDeviceCecVersion(const Napi::CallbackInfo& info);
45
+ Napi::Value GetDeviceMenuLanguage(const Napi::CallbackInfo& info);
46
+ Napi::Value GetDeviceVendorId(const Napi::CallbackInfo& info);
47
+ Napi::Value GetDevicePowerStatus(const Napi::CallbackInfo& info);
48
+ Napi::Value GetDeviceOSDName(const Napi::CallbackInfo& info);
49
+ Napi::Value GetDevicePhysicalAddress(const Napi::CallbackInfo& info);
50
+
51
+ // Device status checks
52
+ Napi::Value PollDevice(const Napi::CallbackInfo& info);
53
+ Napi::Value GetActiveDevices(const Napi::CallbackInfo& info);
54
+ Napi::Value IsActiveDevice(const Napi::CallbackInfo& info);
55
+ Napi::Value IsActiveDeviceType(const Napi::CallbackInfo& info);
56
+ Napi::Value GetActiveSource(const Napi::CallbackInfo& info);
57
+ Napi::Value IsActiveSource(const Napi::CallbackInfo& info);
58
+ Napi::Value IsLibCECActiveSource(const Napi::CallbackInfo& info);
59
+
60
+ // Audio control
61
+ Napi::Value VolumeUp(const Napi::CallbackInfo& info);
62
+ Napi::Value VolumeDown(const Napi::CallbackInfo& info);
63
+ Napi::Value MuteAudio(const Napi::CallbackInfo& info);
64
+ Napi::Value AudioToggleMute(const Napi::CallbackInfo& info);
65
+ Napi::Value AudioStatus(const Napi::CallbackInfo& info);
66
+
67
+ // Display control
68
+ Napi::Value SetOSDString(const Napi::CallbackInfo& info);
69
+
70
+ // Address configuration
71
+ Napi::Value SetLogicalAddress(const Napi::CallbackInfo& info);
72
+ Napi::Value SetPhysicalAddress(const Napi::CallbackInfo& info);
73
+ Napi::Value SetHDMIPort(const Napi::CallbackInfo& info);
74
+ Napi::Value GetLogicalAddresses(const Napi::CallbackInfo& info);
75
+
76
+ // Configuration
77
+ Napi::Value GetCurrentConfiguration(const Napi::CallbackInfo& info);
78
+ Napi::Value SetConfiguration(const Napi::CallbackInfo& info);
79
+ Napi::Value RescanActiveDevices(const Napi::CallbackInfo& info);
80
+
81
+ // Event handling
82
+ Napi::Value SetCallbacks(const Napi::CallbackInfo& info);
83
+ Napi::Value DisableCallbacks(const Napi::CallbackInfo& info);
84
+
85
+ // Static initializer
86
+ static Napi::FunctionReference constructor;
87
+
88
+ // libcec adapter instance
89
+ ICECAdapter* adapter_;
90
+ libcec_configuration config_;
91
+ std::unique_ptr<CECCallbackHandler> callbackHandler_;
92
+ std::mutex mutex_;
93
+ bool isOpen_;
94
+ };
95
+
96
+ #endif // CEC_ADAPTER_H
@@ -0,0 +1,9 @@
1
+ #include <napi.h>
2
+ #include "cec_adapter.h"
3
+
4
+ Napi::Object Init(Napi::Env env, Napi::Object exports) {
5
+ CECAdapter::Init(env, exports);
6
+ return exports;
7
+ }
8
+
9
+ NODE_API_MODULE(cec, Init)
@@ -0,0 +1,313 @@
1
+ #include "cec_callbacks.h"
2
+ #include <cstring>
3
+
4
+ CECCallbackHandler::CECCallbackHandler(Napi::Env env) : callbacks_{} {
5
+ }
6
+
7
+ CECCallbackHandler::~CECCallbackHandler() {
8
+ ClearCallbacks();
9
+ }
10
+
11
+ void CECCallbackHandler::ClearCallbacks() {
12
+ std::lock_guard<std::mutex> lock(mutex_);
13
+
14
+ if (logMessageTsfn_) {
15
+ logMessageTsfn_.Release();
16
+ }
17
+ if (keyPressTsfn_) {
18
+ keyPressTsfn_.Release();
19
+ }
20
+ if (commandTsfn_) {
21
+ commandTsfn_.Release();
22
+ }
23
+ if (configChangedTsfn_) {
24
+ configChangedTsfn_.Release();
25
+ }
26
+ if (alertTsfn_) {
27
+ alertTsfn_.Release();
28
+ }
29
+ if (sourceActivatedTsfn_) {
30
+ sourceActivatedTsfn_.Release();
31
+ }
32
+
33
+ callbacks_ = {};
34
+ }
35
+
36
+ void CECCallbackHandler::SetLogMessageCallback(Napi::Function callback) {
37
+ std::lock_guard<std::mutex> lock(mutex_);
38
+
39
+ if (logMessageTsfn_) {
40
+ logMessageTsfn_.Release();
41
+ }
42
+
43
+ logMessageTsfn_ = Napi::ThreadSafeFunction::New(
44
+ callback.Env(),
45
+ callback,
46
+ "LogMessageCallback",
47
+ 0,
48
+ 1
49
+ );
50
+
51
+ callbacks_.logMessage = &CECCallbackHandler::LogMessageCallback;
52
+ }
53
+
54
+ void CECCallbackHandler::SetKeyPressCallback(Napi::Function callback) {
55
+ std::lock_guard<std::mutex> lock(mutex_);
56
+
57
+ if (keyPressTsfn_) {
58
+ keyPressTsfn_.Release();
59
+ }
60
+
61
+ keyPressTsfn_ = Napi::ThreadSafeFunction::New(
62
+ callback.Env(),
63
+ callback,
64
+ "KeyPressCallback",
65
+ 0,
66
+ 1
67
+ );
68
+
69
+ callbacks_.keyPress = &CECCallbackHandler::KeyPressCallback;
70
+ }
71
+
72
+ void CECCallbackHandler::SetCommandCallback(Napi::Function callback) {
73
+ std::lock_guard<std::mutex> lock(mutex_);
74
+
75
+ if (commandTsfn_) {
76
+ commandTsfn_.Release();
77
+ }
78
+
79
+ commandTsfn_ = Napi::ThreadSafeFunction::New(
80
+ callback.Env(),
81
+ callback,
82
+ "CommandCallback",
83
+ 0,
84
+ 1
85
+ );
86
+
87
+ callbacks_.commandReceived = &CECCallbackHandler::CommandReceivedCallback;
88
+ }
89
+
90
+ void CECCallbackHandler::SetConfigurationChangedCallback(Napi::Function callback) {
91
+ std::lock_guard<std::mutex> lock(mutex_);
92
+
93
+ if (configChangedTsfn_) {
94
+ configChangedTsfn_.Release();
95
+ }
96
+
97
+ configChangedTsfn_ = Napi::ThreadSafeFunction::New(
98
+ callback.Env(),
99
+ callback,
100
+ "ConfigurationChangedCallback",
101
+ 0,
102
+ 1
103
+ );
104
+
105
+ callbacks_.configurationChanged = &CECCallbackHandler::ConfigurationChangedCallback;
106
+ }
107
+
108
+ void CECCallbackHandler::SetAlertCallback(Napi::Function callback) {
109
+ std::lock_guard<std::mutex> lock(mutex_);
110
+
111
+ if (alertTsfn_) {
112
+ alertTsfn_.Release();
113
+ }
114
+
115
+ alertTsfn_ = Napi::ThreadSafeFunction::New(
116
+ callback.Env(),
117
+ callback,
118
+ "AlertCallback",
119
+ 0,
120
+ 1
121
+ );
122
+
123
+ callbacks_.alert = &CECCallbackHandler::AlertCallback;
124
+ }
125
+
126
+ void CECCallbackHandler::SetSourceActivatedCallback(Napi::Function callback) {
127
+ std::lock_guard<std::mutex> lock(mutex_);
128
+
129
+ if (sourceActivatedTsfn_) {
130
+ sourceActivatedTsfn_.Release();
131
+ }
132
+
133
+ sourceActivatedTsfn_ = Napi::ThreadSafeFunction::New(
134
+ callback.Env(),
135
+ callback,
136
+ "SourceActivatedCallback",
137
+ 0,
138
+ 1
139
+ );
140
+
141
+ callbacks_.sourceActivated = &CECCallbackHandler::SourceActivatedCallback;
142
+ }
143
+
144
+ // Log message data structure
145
+ struct LogMessageData {
146
+ std::string message;
147
+ int level;
148
+ int64_t time;
149
+ };
150
+
151
+ void CECCallbackHandler::LogMessageCallback(void* cbParam, const cec_log_message* message) {
152
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
153
+ if (!handler || !handler->logMessageTsfn_) return;
154
+
155
+ auto* data = new LogMessageData{
156
+ std::string(message->message),
157
+ static_cast<int>(message->level),
158
+ message->time
159
+ };
160
+
161
+ handler->logMessageTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, LogMessageData* data) {
162
+ Napi::Object obj = Napi::Object::New(env);
163
+ obj.Set("message", Napi::String::New(env, data->message));
164
+ obj.Set("level", Napi::Number::New(env, data->level));
165
+ obj.Set("time", Napi::Number::New(env, static_cast<double>(data->time)));
166
+ jsCallback.Call({obj});
167
+ delete data;
168
+ });
169
+ }
170
+
171
+ // Key press data structure
172
+ struct KeyPressData {
173
+ int keycode;
174
+ int duration;
175
+ };
176
+
177
+ void CECCallbackHandler::KeyPressCallback(void* cbParam, const cec_keypress* key) {
178
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
179
+ if (!handler || !handler->keyPressTsfn_) return;
180
+
181
+ auto* data = new KeyPressData{
182
+ static_cast<int>(key->keycode),
183
+ static_cast<int>(key->duration)
184
+ };
185
+
186
+ handler->keyPressTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, KeyPressData* data) {
187
+ Napi::Object obj = Napi::Object::New(env);
188
+ obj.Set("keycode", Napi::Number::New(env, data->keycode));
189
+ obj.Set("duration", Napi::Number::New(env, data->duration));
190
+ jsCallback.Call({obj});
191
+ delete data;
192
+ });
193
+ }
194
+
195
+ // Command data structure
196
+ struct CommandData {
197
+ int initiator;
198
+ int destination;
199
+ int opcode;
200
+ bool ack;
201
+ bool eom;
202
+ int opcodeSet;
203
+ std::vector<uint8_t> parameters;
204
+ };
205
+
206
+ void CECCallbackHandler::CommandReceivedCallback(void* cbParam, const cec_command* command) {
207
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
208
+ if (!handler || !handler->commandTsfn_) return;
209
+
210
+ auto* data = new CommandData{
211
+ static_cast<int>(command->initiator),
212
+ static_cast<int>(command->destination),
213
+ static_cast<int>(command->opcode),
214
+ command->ack != 0,
215
+ command->eom != 0,
216
+ command->opcode_set != 0,
217
+ std::vector<uint8_t>(command->parameters.data, command->parameters.data + command->parameters.size)
218
+ };
219
+
220
+ handler->commandTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, CommandData* data) {
221
+ Napi::Object obj = Napi::Object::New(env);
222
+ obj.Set("initiator", Napi::Number::New(env, data->initiator));
223
+ obj.Set("destination", Napi::Number::New(env, data->destination));
224
+ obj.Set("opcode", Napi::Number::New(env, data->opcode));
225
+ obj.Set("ack", Napi::Boolean::New(env, data->ack));
226
+ obj.Set("eom", Napi::Boolean::New(env, data->eom));
227
+ obj.Set("opcodeSet", Napi::Boolean::New(env, data->opcodeSet));
228
+
229
+ Napi::Array params = Napi::Array::New(env, data->parameters.size());
230
+ for (size_t i = 0; i < data->parameters.size(); i++) {
231
+ params.Set(static_cast<uint32_t>(i), Napi::Number::New(env, data->parameters[i]));
232
+ }
233
+ obj.Set("parameters", params);
234
+
235
+ jsCallback.Call({obj});
236
+ delete data;
237
+ });
238
+ }
239
+
240
+ // Configuration changed data structure
241
+ struct ConfigChangedData {
242
+ std::string deviceName;
243
+ uint16_t physicalAddress;
244
+ int baseDevice;
245
+ uint8_t hdmiPort;
246
+ };
247
+
248
+ void CECCallbackHandler::ConfigurationChangedCallback(void* cbParam, const libcec_configuration* config) {
249
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
250
+ if (!handler || !handler->configChangedTsfn_) return;
251
+
252
+ auto* data = new ConfigChangedData{
253
+ std::string(config->strDeviceName),
254
+ config->iPhysicalAddress,
255
+ static_cast<int>(config->baseDevice),
256
+ config->iHDMIPort
257
+ };
258
+
259
+ handler->configChangedTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, ConfigChangedData* data) {
260
+ Napi::Object obj = Napi::Object::New(env);
261
+ obj.Set("deviceName", Napi::String::New(env, data->deviceName));
262
+ obj.Set("physicalAddress", Napi::Number::New(env, data->physicalAddress));
263
+ obj.Set("baseDevice", Napi::Number::New(env, data->baseDevice));
264
+ obj.Set("hdmiPort", Napi::Number::New(env, data->hdmiPort));
265
+ jsCallback.Call({obj});
266
+ delete data;
267
+ });
268
+ }
269
+
270
+ // Alert data structure
271
+ struct AlertData {
272
+ int alertType;
273
+ };
274
+
275
+ void CECCallbackHandler::AlertCallback(void* cbParam, const libcec_alert type, const libcec_parameter param) {
276
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
277
+ if (!handler || !handler->alertTsfn_) return;
278
+
279
+ auto* data = new AlertData{
280
+ static_cast<int>(type)
281
+ };
282
+
283
+ handler->alertTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, AlertData* data) {
284
+ Napi::Object obj = Napi::Object::New(env);
285
+ obj.Set("type", Napi::Number::New(env, data->alertType));
286
+ jsCallback.Call({obj});
287
+ delete data;
288
+ });
289
+ }
290
+
291
+ // Source activated data structure
292
+ struct SourceActivatedData {
293
+ int logicalAddress;
294
+ bool activated;
295
+ };
296
+
297
+ void CECCallbackHandler::SourceActivatedCallback(void* cbParam, const cec_logical_address logicalAddress, const uint8_t activated) {
298
+ CECCallbackHandler* handler = static_cast<CECCallbackHandler*>(cbParam);
299
+ if (!handler || !handler->sourceActivatedTsfn_) return;
300
+
301
+ auto* data = new SourceActivatedData{
302
+ static_cast<int>(logicalAddress),
303
+ activated != 0
304
+ };
305
+
306
+ handler->sourceActivatedTsfn_.BlockingCall(data, [](Napi::Env env, Napi::Function jsCallback, SourceActivatedData* data) {
307
+ Napi::Object obj = Napi::Object::New(env);
308
+ obj.Set("logicalAddress", Napi::Number::New(env, data->logicalAddress));
309
+ obj.Set("activated", Napi::Boolean::New(env, data->activated));
310
+ jsCallback.Call({obj});
311
+ delete data;
312
+ });
313
+ }
@@ -0,0 +1,48 @@
1
+ #ifndef CEC_CALLBACKS_H
2
+ #define CEC_CALLBACKS_H
3
+
4
+ #include <napi.h>
5
+ #include <libcec/cec.h>
6
+ #include <memory>
7
+ #include <mutex>
8
+
9
+ using namespace CEC;
10
+
11
+ class CECCallbackHandler {
12
+ public:
13
+ CECCallbackHandler(Napi::Env env);
14
+ ~CECCallbackHandler();
15
+
16
+ void SetLogMessageCallback(Napi::Function callback);
17
+ void SetKeyPressCallback(Napi::Function callback);
18
+ void SetCommandCallback(Napi::Function callback);
19
+ void SetConfigurationChangedCallback(Napi::Function callback);
20
+ void SetAlertCallback(Napi::Function callback);
21
+ void SetSourceActivatedCallback(Napi::Function callback);
22
+
23
+ void ClearCallbacks();
24
+
25
+ ICECCallbacks* GetCallbacks() { return &callbacks_; }
26
+
27
+ // Static callback functions for libcec
28
+ static void LogMessageCallback(void* cbParam, const cec_log_message* message);
29
+ static void KeyPressCallback(void* cbParam, const cec_keypress* key);
30
+ static void CommandReceivedCallback(void* cbParam, const cec_command* command);
31
+ static void ConfigurationChangedCallback(void* cbParam, const libcec_configuration* config);
32
+ static void AlertCallback(void* cbParam, const libcec_alert type, const libcec_parameter param);
33
+ static void SourceActivatedCallback(void* cbParam, const cec_logical_address logicalAddress, const uint8_t activated);
34
+
35
+ private:
36
+ ICECCallbacks callbacks_;
37
+
38
+ Napi::ThreadSafeFunction logMessageTsfn_;
39
+ Napi::ThreadSafeFunction keyPressTsfn_;
40
+ Napi::ThreadSafeFunction commandTsfn_;
41
+ Napi::ThreadSafeFunction configChangedTsfn_;
42
+ Napi::ThreadSafeFunction alertTsfn_;
43
+ Napi::ThreadSafeFunction sourceActivatedTsfn_;
44
+
45
+ std::mutex mutex_;
46
+ };
47
+
48
+ #endif // CEC_CALLBACKS_H