noobs 0.0.145 → 0.0.147

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/noobs.node CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noobs",
3
- "version": "0.0.145",
3
+ "version": "0.0.147",
4
4
  "description": "A native Node.js addon with libobs bindings for Warcraft Recorder.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -10,14 +10,20 @@
10
10
 
11
11
  void call_jscb(Napi::Env env, Napi::Function cb, SignalData* sd) {
12
12
  Napi::Object obj = Napi::Object::New(env);
13
+
13
14
  obj.Set("type", Napi::String::New(env, sd->type));
14
15
  obj.Set("id", Napi::String::New(env, sd->id));
15
16
  obj.Set("code", Napi::Number::New(env, sd->code));
17
+
16
18
 
17
19
  if (sd->value.has_value()) {
18
20
  obj.Set("value", Napi::Number::New(env, sd->value.value()));
19
21
  }
20
22
 
23
+ if (sd->error.has_value()) {
24
+ obj.Set("error", Napi::String::New(env, sd->error.value()));
25
+ }
26
+
21
27
  cb.Call({ obj });
22
28
  delete sd;
23
29
  }
@@ -55,6 +61,22 @@ void ObsInterface::list_output_types()
55
61
  }
56
62
  }
57
63
 
64
+ bool log_adapter(void *param, const char *node, uint32_t idx)
65
+ {
66
+ blog(LOG_INFO, " - %d: %s", idx, node);
67
+ return true;
68
+ }
69
+
70
+ void list_adapters()
71
+ {
72
+ // Pretty sure OBS logs all this stuff anyway but do it ourselves for good measure.
73
+ obs_enter_graphics();
74
+ uint32_t count = gs_get_adapter_count();
75
+ blog(LOG_INFO, "Adapter count: %d", count);
76
+ gs_enum_adapters(log_adapter, NULL);
77
+ obs_leave_graphics();
78
+ }
79
+
58
80
  void ObsInterface::load_module(const char* module, const char* data, bool allowFail) {
59
81
  blog(LOG_INFO, "Loading module: %s", module);
60
82
  blog(LOG_INFO, "Data path: %s", data);
@@ -145,7 +167,7 @@ bool ObsInterface::reset_audio() {
145
167
  }
146
168
 
147
169
  void ObsInterface::init_obs(const std::string& distPath) {
148
- blog(LOG_INFO, "Enter init_obs");
170
+ blog(LOG_INFO, "Initializing OBS");
149
171
  auto success = obs_startup("en-US", NULL, NULL);
150
172
 
151
173
  if (!success) {
@@ -218,10 +240,12 @@ void ObsInterface::init_obs(const std::string& distPath) {
218
240
  list_encoders();
219
241
  list_source_types();
220
242
  list_output_types();
243
+ list_adapters();
221
244
 
222
- blog(LOG_INFO, "Exit init_obs");
245
+ blog(LOG_INFO, "Initializing complete");
223
246
  }
224
247
 
248
+
225
249
  void ObsInterface::create_output() {
226
250
  blog(LOG_INFO, "Create outputs");
227
251
 
@@ -571,11 +595,25 @@ obs_properties_t* ObsInterface::getSourceProperties(std::string name) {
571
595
 
572
596
  void ObsInterface::output_signal_handler(void *data, calldata_t *cd) {
573
597
  long long code = calldata_int(cd, "code");
598
+ const char *err = calldata_string(cd, "last_error");
599
+
600
+ std::optional<std::string> error;
601
+
602
+ if (err) {
603
+ error = std::string(err);
604
+ }
574
605
 
575
606
  SignalContext* ctx = static_cast<SignalContext*>(data);
576
607
  ObsInterface* self = ctx->self;
577
608
 
578
- SignalData* sd = new SignalData{ "output", ctx->id.c_str(), code };
609
+ SignalData* sd = new SignalData{
610
+ "output",
611
+ ctx->id.c_str(),
612
+ code,
613
+ std::nullopt, // No value, that's only used for volmeters.
614
+ error,
615
+ };
616
+
579
617
  self->jscb.NonBlockingCall(sd, call_jscb);
580
618
  }
581
619
 
@@ -896,7 +934,7 @@ ObsInterface::ObsInterface(
896
934
  }
897
935
 
898
936
  ObsInterface::~ObsInterface() {
899
- blog(LOG_DEBUG, "Destroying ObsInterface");
937
+ blog(LOG_DEBUG, "Shutting down");
900
938
 
901
939
  for (auto& kv : volmeters) {
902
940
  obs_volmeter_t* volmeter = kv.second;
@@ -969,6 +1007,8 @@ ObsInterface::~ObsInterface() {
969
1007
  blog(LOG_DEBUG, "Releasing JavaScript callback");
970
1008
  jscb.Release();
971
1009
  }
1010
+
1011
+ blog(LOG_DEBUG, "Shutdown complete");
972
1012
  }
973
1013
 
974
1014
  void ObsInterface::setBuffering(bool value) {
@@ -18,6 +18,7 @@ struct SignalData {
18
18
  std::string id;
19
19
  long long code;
20
20
  std::optional<float> value;
21
+ std::optional<std::string> error;
21
22
  };
22
23
 
23
24
  struct SignalContext {
package/src/utils.cpp CHANGED
@@ -7,77 +7,56 @@
7
7
  #include "utils.h"
8
8
 
9
9
  void log_handler(int lvl, const char *msg, va_list args, void *p) {
10
- // Use the passed log path parameter
11
- static std::string log_filename;
12
- static bool filename_initialized = false;
13
-
14
- if (!filename_initialized) {
10
+ static std::ofstream logFile;
11
+ static bool initialized = false;
12
+
13
+ if (!initialized) {
14
+ // Build log filename
15
+ auto now = std::chrono::system_clock::now();
16
+ auto t = std::chrono::system_clock::to_time_t(now);
17
+ std::stringstream filename;
18
+ filename << "OBS-" << std::put_time(std::localtime(&t), "%Y-%m-%d") << ".log";
19
+
20
+ std::string log_dir = static_cast<const char*>(p);
21
+ if (!log_dir.empty() && log_dir.back() != '\\' && log_dir.back() != '/')
22
+ log_dir += '\\';
23
+
24
+ logFile.open(log_dir + filename.str(), std::ios::app);
25
+ initialized = true;
26
+ }
27
+
28
+ if (!logFile.is_open()) return;
29
+
30
+ // Timestamp
15
31
  auto now = std::chrono::system_clock::now();
16
- auto time_t = std::chrono::system_clock::to_time_t(now);
17
-
18
- std::stringstream filename_stream;
19
- filename_stream << "OBS-" << std::put_time(std::localtime(&time_t), "%Y-%m-%d") << ".log";
20
-
21
- // Use the provided directory path and append the filename
22
- std::string log_dir = static_cast<const char*>(p);
32
+ auto t = std::chrono::system_clock::to_time_t(now);
33
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
34
+ now.time_since_epoch()) % 1000;
35
+
36
+ std::stringstream timestamp;
37
+ timestamp << "[" << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S")
38
+ << "." << std::setfill('0') << std::setw(3) << ms.count() << "] ";
23
39
 
24
- // Ensure the directory path ends with a separator
25
- if (!log_dir.empty() && log_dir.back() != '\\' && log_dir.back() != '/') {
26
- log_dir += "\\";
40
+ // Log level
41
+ const char* level_str = "UNKNOWN";
42
+ switch (lvl) {
43
+ case LOG_ERROR: level_str = "ERROR"; break;
44
+ case LOG_WARNING: level_str = "WARN"; break;
45
+ case LOG_INFO: level_str = "INFO"; break;
46
+ case LOG_DEBUG: level_str = "DEBUG"; break;
27
47
  }
48
+ timestamp << "[" << level_str << "] ";
28
49
 
29
- log_filename = log_dir + filename_stream.str();
30
- filename_initialized = true;
31
- }
32
-
33
- // Get current timestamp
34
- auto now = std::chrono::system_clock::now();
35
- auto time_t = std::chrono::system_clock::to_time_t(now);
36
- auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
37
- now.time_since_epoch()) % 1000;
38
-
39
- // Convert log level to string
40
- const char* level_str;
41
- switch (lvl) {
42
- case LOG_ERROR: level_str = "ERROR"; break;
43
- case LOG_WARNING: level_str = "WARN"; break;
44
- case LOG_INFO: level_str = "INFO"; break;
45
- case LOG_DEBUG: level_str = "DEBUG"; break;
46
- default: level_str = "UNKNOWN"; break;
47
- }
48
-
49
- // Format the log message
50
- char buffer[4096];
51
- vsnprintf(buffer, sizeof(buffer), msg, args);
52
-
53
- // Create timestamp string
54
- std::stringstream timestamp;
55
- timestamp << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
56
- timestamp << "." << std::setfill('0') << std::setw(3) << ms.count();
57
-
58
- std::string timestamp_str = "[" + timestamp.str() + "] [" + level_str + "] ";
59
-
60
- // Split the message by newlines and add timestamp to each line
61
- std::string message(buffer);
62
- std::istringstream iss(message);
63
- std::string line;
64
- std::string formatted_output;
65
-
66
- while (std::getline(iss, line)) {
67
- formatted_output += timestamp_str + line + "\n";
68
- }
69
-
70
- // Remove the last newline if it exists
71
- if (!formatted_output.empty() && formatted_output.back() == '\n') {
72
- formatted_output.pop_back();
73
- }
74
-
75
- // Write to log file
76
- std::ofstream logFile(log_filename, std::ios::app);
77
- if (logFile.is_open()) {
78
- logFile << formatted_output << std::endl;
79
- logFile.close();
80
- }
50
+ // Format message
51
+ char buffer[4096];
52
+ vsnprintf(buffer, sizeof(buffer), msg, args);
53
+
54
+ // Prepend timestamp and flush per line
55
+ std::istringstream iss(buffer);
56
+ std::string line;
57
+ while (std::getline(iss, line)) {
58
+ logFile << timestamp.str() << line << std::endl; // std::endl flushes
59
+ }
81
60
  }
82
61
 
83
62
  Napi::Object data_to_napi(Napi::Env env, obs_data_t* data) {