noobs 0.0.33 → 0.0.63

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.
@@ -6,6 +6,12 @@
6
6
  #include "obs_interface.h"
7
7
  #include <vector>
8
8
  #include <thread>
9
+ #include <iostream>
10
+ #include <map>
11
+ #include <string>
12
+ #include <graphics/matrix4.h>
13
+ #include <graphics/vec4.h>
14
+ #include <util/platform.h>
9
15
 
10
16
  std::vector<std::string> ObsInterface::get_available_video_encoders()
11
17
  {
@@ -158,7 +164,14 @@ void ObsInterface::init_obs(const std::string& pluginPath, const std::string& da
158
164
  }
159
165
 
160
166
  obs_add_data_path(dp.c_str()); // This is deprecated in libobs but it works for now.
161
- std::vector<std::string> modules = { "obs-x264.dll", "obs-ffmpeg.dll", "win-capture.dll" };
167
+
168
+ std::vector<std::string> modules = {
169
+ "obs-x264.dll",
170
+ "obs-ffmpeg.dll",
171
+ "win-capture.dll", // Required for basically all forms of capture on Windows.
172
+ "image-source.dll", // Required for image sources.
173
+ "win-wasapi.dll" // Required for WASAPI audio input.
174
+ };
162
175
 
163
176
  for (const auto& module : modules) {
164
177
  std::string path = pluginPath + "/" + module;
@@ -178,33 +191,46 @@ void ObsInterface::init_obs(const std::string& pluginPath, const std::string& da
178
191
  blog(LOG_INFO, "Exit init_obs");
179
192
  }
180
193
 
181
- void ObsInterface::configure_output(const std::string& recordingPath) {
194
+ void ObsInterface::create_output(const std::string& recordingPath, bool buffering) {
182
195
  blog(LOG_INFO, "Create output");
183
196
 
184
- if (output && obs_output_active(output)) {
185
- blog(LOG_ERROR, "Tried to recreate active output");
186
- throw std::runtime_error("Failed to create output!");
187
- }
188
-
189
197
  if (output) {
190
198
  blog(LOG_DEBUG, "Releasing output");
191
199
  obs_output_release(output);
192
200
  }
193
201
 
194
- output = obs_output_create("replay_buffer", "recording_output", NULL, NULL);
202
+ if (buffering) {
203
+ blog(LOG_INFO, "Creating replay buffer output");
204
+ output = obs_output_create("replay_buffer", "recording_output", NULL, NULL);
205
+ } else {
206
+ blog(LOG_INFO, "Creating file output");
207
+ output = obs_output_create("ffmpeg_muxer", "recording_output", NULL, NULL);
208
+ }
195
209
 
196
210
  if (!output) {
197
211
  blog(LOG_ERROR, "Failed to create output!");
198
212
  throw std::runtime_error("Failed to create output!");
199
213
  }
200
-
201
- blog(LOG_INFO, "Set output settings");
214
+
202
215
  obs_data_t *settings = obs_data_create();
203
- obs_data_set_int(settings, "max_time_sec", 60);
204
- obs_data_set_int(settings, "max_size_mb", 1024);
205
- obs_data_set_string(settings, "directory", recordingPath.c_str());
206
- obs_data_set_string(settings, "format", "%CCYY-%MM-%DD %hh-%mm-%ss");
207
- obs_data_set_string(settings, "extension", "mp4");
216
+
217
+ if (buffering) {
218
+ blog(LOG_INFO, "Set replay_buffer settings");
219
+ obs_data_set_int(settings, "max_time_sec", 60);
220
+ obs_data_set_int(settings, "max_size_mb", 1024);
221
+ obs_data_set_string(settings, "directory", recordingPath.c_str());
222
+ obs_data_set_string(settings, "format", "%CCYY-%MM-%DD %hh-%mm-%ss");
223
+ obs_data_set_string(settings, "extension", "mp4");
224
+ } else {
225
+ blog(LOG_INFO, "Set ffmpeg_muxer settings");
226
+ obs_data_set_string(settings, "extension", "mp4");
227
+ // Apparently need to specify the exact path for ffmpeg_muxer.
228
+ // TODO add something to auto generate this ?
229
+ obs_data_set_string(settings, "path", (recordingPath + "/noobs.mp4").c_str());
230
+ recording_path = recordingPath + "/noobs.mp4";
231
+ }
232
+
233
+ // Apply and release the settings.
208
234
  obs_output_update(output, settings);
209
235
  obs_data_release(settings);
210
236
 
@@ -212,6 +238,33 @@ void ObsInterface::configure_output(const std::string& recordingPath) {
212
238
  create_signal_handlers(output);
213
239
  }
214
240
 
241
+ void ObsInterface::setRecordingDir(const std::string& recordingPath) {
242
+ blog(LOG_INFO, "Set recording directory");
243
+ // TODO make this work for file output also.
244
+
245
+ if (!output) {
246
+ blog(LOG_ERROR, "No output to update recording directory");
247
+ throw std::runtime_error("Output not initialized");
248
+ }
249
+
250
+ // check its not active
251
+ if (obs_output_active(output)) {
252
+ blog(LOG_ERROR, "Output is active, cannot update recording path");
253
+ throw std::runtime_error("Output is active, cannot update recording path");
254
+ }
255
+
256
+ obs_data_t *settings = obs_output_get_settings(output);
257
+
258
+ if (!settings) {
259
+ blog(LOG_ERROR, "Failed to get output settings");
260
+ throw std::runtime_error("Failed to get output settings");
261
+ }
262
+
263
+ obs_data_set_string(settings, "directory", recordingPath.c_str());
264
+ obs_output_update(output, settings);
265
+ obs_data_release(settings);
266
+ }
267
+
215
268
  void ObsInterface::configure_video_encoder() {
216
269
  blog(LOG_INFO, "Create video encoder");
217
270
 
@@ -278,15 +331,8 @@ void ObsInterface::configure_audio_encoder() {
278
331
  obs_encoder_set_audio(audio_encoder, obs_get_audio());
279
332
  }
280
333
 
281
- void ObsInterface::configure_scene() {
282
- blog(LOG_INFO, "Configure scene");
283
-
284
- if (scene) {
285
- blog(LOG_DEBUG, "Releasing scene");
286
- obs_scene_release(scene);
287
- scene = nullptr;
288
- }
289
-
334
+ void ObsInterface::create_scene() {
335
+ blog(LOG_INFO, "Create scene");
290
336
  scene = obs_scene_create("WCR Scene");
291
337
 
292
338
  if (!scene) {
@@ -302,24 +348,85 @@ void ObsInterface::configure_scene() {
302
348
  }
303
349
 
304
350
  obs_set_output_source(0, scene_source); // 0 = video track
305
- obs_scene_add(scene, video_source);
306
351
  }
307
352
 
308
- void ObsInterface::configure_video_source() {
309
- blog(LOG_INFO, "Create monitor capture source");
353
+ void ObsInterface::createSource(std::string name, std::string type) {
354
+ blog(LOG_INFO, "Create source: %s of type %s", name.c_str(), type.c_str());
355
+
356
+ obs_source_t *source = obs_source_create(
357
+ type.c_str(),
358
+ name.c_str(),
359
+ NULL, // No settings.
360
+ NULL // No hotkey data.
361
+ );
362
+
363
+ if (!source) {
364
+ blog(LOG_ERROR, "Failed to create source: %s", name.c_str());
365
+ throw std::runtime_error("Failed to create source!");
366
+ }
367
+ }
368
+
369
+ void ObsInterface::deleteSource(std::string name) {
370
+ blog(LOG_INFO, "Delete source: %s", name.c_str());
371
+ obs_source_t *source = obs_get_source_by_name(name.c_str());
372
+
373
+ if (!source) {
374
+ blog(LOG_WARNING, "Source not found: %s", name.c_str());
375
+ return; // Source not found, nothing to delete.
376
+ }
377
+
378
+ obs_source_release(source);
379
+ blog(LOG_INFO, "Source deleted: %s", name.c_str());
380
+ }
381
+
382
+ obs_data_t* ObsInterface::getSourceSettings(std::string name) {
383
+ blog(LOG_INFO, "Get source settings for: %s", name.c_str());
384
+ obs_source_t *source = obs_get_source_by_name(name.c_str());
385
+
386
+ if (!source) {
387
+ blog(LOG_ERROR, "Source not found: %s", name.c_str());
388
+ throw std::runtime_error("Source not found!");
389
+ }
390
+
391
+ obs_data_t *settings = obs_source_get_settings(source);
392
+
393
+ if (!settings) {
394
+ blog(LOG_ERROR, "Failed to get settings for source: %s", name.c_str());
395
+ throw std::runtime_error("Failed to get source settings!");
396
+ }
397
+
398
+ return settings;
399
+ }
400
+
401
+ void ObsInterface::setSourceSettings(std::string name, obs_data_t* settings) {
402
+ blog(LOG_INFO, "Set source settings for: %s", name.c_str());
403
+ obs_source_t *source = obs_get_source_by_name(name.c_str());
310
404
 
311
- // Create settings for monitor capture
312
- obs_data_t *monitor_settings = obs_data_create();
313
- obs_data_set_int(monitor_settings, "monitor", 0); // Monitor 0
314
- obs_data_set_bool(monitor_settings, "capture_cursor", true);
405
+ if (!source) {
406
+ blog(LOG_ERROR, "Source not found: %s", name.c_str());
407
+ throw std::runtime_error("Source not found!");
408
+ }
409
+
410
+ obs_source_update(source, settings);
411
+ }
315
412
 
316
- video_source = obs_source_create("monitor_capture", "video_source", monitor_settings, NULL);
317
- obs_data_release(monitor_settings);
413
+ obs_properties_t* ObsInterface::getSourceProperties(std::string name) {
414
+ blog(LOG_INFO, "Get source properties for: %s", name.c_str());
415
+ obs_source_t *source = obs_get_source_by_name(name.c_str());
318
416
 
319
- if (!video_source) {
320
- blog(LOG_ERROR, "Failed to create video source!");
321
- throw std::runtime_error("Failed to create video source!");
417
+ if (!source) {
418
+ blog(LOG_ERROR, "Source not found: %s", name.c_str());
419
+ throw std::runtime_error("Source not found!");
322
420
  }
421
+
422
+ obs_properties_t *props = obs_source_properties(source);
423
+
424
+ if (!props) {
425
+ blog(LOG_ERROR, "Failed to get properties for source: %s", name.c_str());
426
+ throw std::runtime_error("Failed to get source properties!");
427
+ }
428
+
429
+ return props;
323
430
  }
324
431
 
325
432
  void call_jscb(Napi::Env env, Napi::Function cb, SignalData* sd) {
@@ -374,8 +481,76 @@ void ObsInterface::create_signal_handlers(obs_output_t *output) {
374
481
  signal_handler_connect(sh, "saved", output_signal_handler_saved, this);
375
482
  }
376
483
 
484
+ bool draw_box(obs_scene_t *scene, obs_sceneitem_t *item, void *p) {
485
+ // Get the item position and size
486
+ vec2 pos; vec2 scale;
487
+ obs_sceneitem_get_pos(item, &pos);
488
+ obs_sceneitem_get_scale(item, &scale);
489
+
490
+ // Calculate actual size with scaling
491
+ obs_source_t *src = obs_sceneitem_get_source(item);
492
+ float width = obs_source_get_width(src) * scale.x;
493
+ float height = obs_source_get_height(src) * scale.y;
494
+
495
+ // Draw rectangle around the source using the position and size
496
+ gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
497
+ gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
498
+ gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
499
+
500
+ vec4 col = {0.733f, 0.267f, 0.125f, 1.0f}; // #BB4420
501
+ gs_effect_set_vec4(color, &col);
502
+
503
+ gs_technique_begin(tech);
504
+ gs_technique_begin_pass(tech, 0);
505
+
506
+ gs_matrix_push();
507
+ gs_matrix_identity();
508
+
509
+ // Top border
510
+ gs_matrix_push();
511
+ gs_matrix_translate3f(pos.x, pos.y, 0.0f);
512
+ gs_draw_sprite(nullptr, 0, width, 2.0f);
513
+ gs_matrix_pop();
514
+
515
+ // Bottom border
516
+ gs_matrix_push();
517
+ gs_matrix_translate3f(pos.x, pos.y + height - 2.0f, 0.0f);
518
+ gs_draw_sprite(nullptr, 0, width, 2.0f);
519
+ gs_matrix_pop();
520
+
521
+ // Left border
522
+ gs_matrix_push();
523
+ gs_matrix_translate3f(pos.x, pos.y, 0.0f);
524
+ gs_draw_sprite(nullptr, 0, 2.0f, height);
525
+ gs_matrix_pop();
526
+
527
+ // Right border
528
+ gs_matrix_push();
529
+ gs_matrix_translate3f(pos.x + width - 2.0f, pos.y, 0.0f);
530
+ gs_draw_sprite(nullptr, 0, 2.0f, height);
531
+ gs_matrix_pop();
532
+
533
+ gs_matrix_pop();
534
+
535
+ gs_technique_end_pass(tech);
536
+ gs_technique_end(tech);
537
+
538
+ return true;
539
+ }
540
+
377
541
  void draw_callback(void* data, uint32_t cx, uint32_t cy) {
542
+ // Initially, draw the OBS scene texture
378
543
  obs_render_main_texture();
544
+
545
+ // This is some AI code that would draw a rectangle (and works).
546
+ // Set projection and viewport
547
+ gs_ortho(0.0f, float(cx), 0.0f, float(cy), -100.0f, 100.0f);
548
+ gs_set_viewport(0, 0, cx, cy);
549
+
550
+ // This was me trying to understand what OSN does.
551
+ obs_scene_t* scene = obs_get_scene_by_name("WCR Scene");
552
+ obs_scene_enum_items(scene, draw_box, NULL);
553
+ obs_scene_release(scene);
379
554
  }
380
555
 
381
556
  void ObsInterface::initPreview(HWND parent) {
@@ -470,7 +645,8 @@ ObsInterface::ObsInterface(
470
645
  const std::string& logPath,
471
646
  const std::string& dataPath,
472
647
  const std::string& recordingPath,
473
- Napi::ThreadSafeFunction cb
648
+ Napi::ThreadSafeFunction cb,
649
+ bool buffering
474
650
  ) {
475
651
  // Setup logs first so we have logs for the initialization.
476
652
  base_set_log_handler(log_handler, (void*)logPath.c_str());
@@ -483,11 +659,11 @@ ObsInterface::ObsInterface(
483
659
  jscb = cb;
484
660
 
485
661
  // Create the resources we rely on.
486
- configure_output(recordingPath);
662
+ create_output(recordingPath, buffering);
663
+ create_scene();
664
+
487
665
  configure_video_encoder();
488
666
  configure_audio_encoder();
489
- configure_video_source();
490
- configure_scene();
491
667
  }
492
668
 
493
669
  ObsInterface::~ObsInterface() {
@@ -557,26 +733,52 @@ void ObsInterface::startBuffering() {
557
733
 
558
734
  void ObsInterface::startRecording(int offset) {
559
735
  blog(LOG_INFO, "ObsInterface::startRecording enter");
560
- bool is_active = obs_output_active(output);
561
736
 
562
- if (!is_active) {
563
- blog(LOG_ERROR, "Buffer is not active");
564
- throw std::runtime_error("Buffer is not active");
565
- }
737
+ const char* type = obs_output_get_id(output);
566
738
 
567
- blog(LOG_INFO, "calling save proc handler");
568
- calldata cd;
569
- calldata_init(&cd);
570
- calldata_set_int(&cd, "offset_seconds", offset);
571
- proc_handler_t *ph = obs_output_get_proc_handler(output);
572
- bool success = proc_handler_call(ph, "convert", &cd);
573
- calldata_free(&cd);
739
+ if (strcmp(type, "replay_buffer") == 0) {
740
+ bool is_active = obs_output_active(output);
574
741
 
575
- if (!success) {
576
- throw std::runtime_error("Failed to call convert procedure handler");
742
+ if (!is_active) {
743
+ blog(LOG_WARNING, "Buffer is not active");
744
+ throw std::runtime_error("Buffer is not active");
745
+ }
746
+
747
+ blog(LOG_INFO, "calling save proc handler");
748
+ calldata cd;
749
+ calldata_init(&cd);
750
+ calldata_set_int(&cd, "offset_seconds", offset);
751
+ proc_handler_t *ph = obs_output_get_proc_handler(output);
752
+ bool success = proc_handler_call(ph, "convert", &cd);
753
+ calldata_free(&cd);
754
+
755
+ if (!success) {
756
+ throw std::runtime_error("Failed to call convert procedure handler");
757
+ }
758
+ } else if (strcmp(type, "ffmpeg_muxer") == 0) {
759
+ blog(LOG_INFO, "Starting ffmpeg_muxer output");
760
+
761
+ bool is_active = obs_output_active(output);
762
+
763
+ if (is_active) {
764
+ blog(LOG_WARNING, "Output already active");
765
+ return;
766
+ }
767
+
768
+ blog(LOG_WARNING, "Call start");
769
+ bool success = obs_output_start(output);
770
+
771
+ if (!success) {
772
+ const char *err = obs_output_get_last_error(output);
773
+ blog(LOG_ERROR, "Failed to start recording: %s", err ? err : "Unknown error");
774
+ throw std::runtime_error("Failed to start recording");
775
+ }
776
+ } else {
777
+ blog(LOG_ERROR, "Unknown output type: %s", type);
778
+ throw std::runtime_error("Unknown output type!");
577
779
  }
578
780
 
579
- blog(LOG_INFO, "ObsInterface::startRecording exit");
781
+ blog(LOG_INFO, "ObsInterface::startRecording exit");
580
782
  }
581
783
 
582
784
  void ObsInterface::stopRecording() {
@@ -597,10 +799,27 @@ std::string ObsInterface::getLastRecording() {
597
799
  calldata cd;
598
800
  calldata_init(&cd);
599
801
  proc_handler_t *ph = obs_output_get_proc_handler(output);
600
- bool success = proc_handler_call(ph, "get_last_replay", &cd);
802
+
803
+ const char* type = obs_output_get_id(output);
804
+
805
+ if (strcmp(type, "ffmpeg_muxer") == 0) {
806
+ blog(LOG_INFO, "Getting last recording path from ffmpeg_muxer");
807
+ return recording_path;
808
+ }
809
+
810
+ bool success;
811
+
812
+ if (strcmp(type, "replay_buffer") != 0) {
813
+ blog(LOG_ERROR, "Unknown output type: %s", type);
814
+ throw std::runtime_error("Unknown output type!");
815
+ }
816
+
817
+ success = proc_handler_call(ph, "get_last_replay", &cd);
601
818
 
602
819
  if (!success) {
603
- blog(LOG_ERROR, "Failed to call get_last_replay procedure handler");
820
+ blog(LOG_ERROR, "Failed to call procedure handler");
821
+ const char *err = obs_output_get_last_error(output);
822
+ blog(LOG_ERROR, "%s", err ? err : "Unknown error");
604
823
  calldata_free(&cd);
605
824
  return "";
606
825
  }
@@ -613,6 +832,43 @@ std::string ObsInterface::getLastRecording() {
613
832
  return path;
614
833
  }
615
834
 
835
+ void ObsInterface::addSourceToScene(std::string name) {
836
+ blog(LOG_INFO, "ObsInterface::addSourceToScene called for source: %s", name.c_str());
837
+
838
+ obs_source_t *src = obs_get_source_by_name(name.c_str());
839
+
840
+ if (!src) {
841
+ blog(LOG_WARNING, "Did not find source for video source: %s", name.c_str());
842
+ return;
843
+ }
844
+
845
+ // TODO refuse to add twice?
846
+
847
+ obs_sceneitem_t *item = obs_scene_add(scene, src);
848
+
849
+ if (!item) {
850
+ blog(LOG_ERROR, "Failed to add source to scene: %s", name.c_str());
851
+ obs_source_release(src);
852
+ return;
853
+ }
854
+
855
+ blog(LOG_INFO, "ObsInterface::addSourceToScene exited");
856
+ }
857
+
858
+ void ObsInterface::removeSourceFromScene(std::string name) {
859
+ blog(LOG_INFO, "ObsInterface::removeSourceFromScene called for source: %s", name.c_str());
860
+
861
+ obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
862
+
863
+ if (!item) {
864
+ blog(LOG_WARNING, "Did not find scene item for video source: %s", name.c_str());
865
+ return;
866
+ }
867
+
868
+ obs_sceneitem_remove(item);
869
+ blog(LOG_INFO, "ObsInterface::removeSourceFromScene exited");
870
+ }
871
+
616
872
  void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale)
617
873
  {
618
874
  blog(LOG_INFO, "ObsInterface::getSourcePos called");
@@ -621,12 +877,12 @@ void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* s
621
877
  obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
622
878
 
623
879
  if (!src) {
624
- blog(LOG_ERROR, "Did not find source for video ");
880
+ blog(LOG_WARNING, "Did not find source for video source: %s", name);
625
881
  return;
626
882
  }
627
883
 
628
884
  if (!item) {
629
- blog(LOG_ERROR, "Did not find scene item for video source");
885
+ blog(LOG_WARNING, "Did not find scene item for video source: %s", name);
630
886
  return;
631
887
  }
632
888
 
@@ -645,7 +901,7 @@ void ObsInterface::setSourcePos(std::string name, vec2* pos, vec2* scale) {
645
901
  obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
646
902
 
647
903
  if (!item) {
648
- blog(LOG_ERROR, "Did not find scene item for video source");
904
+ blog(LOG_WARNING, "Did not find scene item for video source: %s", name);
649
905
  return;
650
906
  }
651
907
 
@@ -10,26 +10,36 @@ struct SignalData {
10
10
  class ObsInterface {
11
11
  public:
12
12
  ObsInterface(
13
- const std::string& pluginPath, // where to look for plugins
14
- const std::string& logPath, // where to write logs to
15
- const std::string& dataPath, // where to look for effects
16
- const std::string& recordingPath, // where to save recordings
17
- Napi::ThreadSafeFunction cb // JavaScript callback
13
+ const std::string& pluginPath, // Where to look for plugins
14
+ const std::string& logPath, // Where to write logs to
15
+ const std::string& dataPath, // Where to look for effects
16
+ const std::string& recordingPath, // Where to save recordings
17
+ Napi::ThreadSafeFunction cb, // JavaScript callback
18
+ bool buffering // Whether to enable buffering the recording in memory
18
19
  );
19
20
 
20
21
  ~ObsInterface();
21
22
 
22
- void startBuffering();
23
- void startRecording(int offset);
24
- void stopRecording();
25
- std::string getLastRecording();
23
+ void startBuffering(); // Start buffering to memory.
24
+ void startRecording(int offset); // Convert the active buffered recording to a real one.
25
+ void stopRecording(); // Stop the recording.
26
+ std::string getLastRecording(); // Get the last recorded file path.
27
+ void setRecordingDir(const std::string& recordingPath); // Output must not be active when calling this.
26
28
 
29
+ void createSource(std::string name, std::string type); // Create a new source
30
+ void deleteSource(std::string name); // Release a source.
31
+ obs_data_t* getSourceSettings(std::string name); // Get the current settings.
32
+ void setSourceSettings(std::string name, obs_data_t* settings); // Set settings.
33
+ obs_properties_t* getSourceProperties(std::string name); // Get the settings schema.
34
+
35
+ void addSourceToScene(std::string name); // Add source to scene.
36
+ void removeSourceFromScene(std::string name); // Remove source from scene.
27
37
  void getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale); // Size is returned to allow clients to calculate scale.
28
38
  void setSourcePos(std::string name, vec2* pos, vec2* scale); // Size does not get set here because it's set by the source itself.
29
39
 
30
40
  void initPreview(HWND parent); // Must call this before showPreview to setup resources.
31
41
  void showPreview(int x, int y, int width, int height); // Also used for moving and resizing.
32
- void hidePreview();
42
+ void hidePreview(); // Hide the preview display.
33
43
 
34
44
  std::vector<std::string> get_available_video_encoders();
35
45
 
@@ -50,6 +60,7 @@ class ObsInterface {
50
60
  obs_display_t *display = nullptr;
51
61
  HWND preview_hwnd = nullptr; // window handle for scene preview
52
62
  Napi::ThreadSafeFunction jscb; // javascript callback
63
+ std::string recording_path = "";
53
64
 
54
65
  void init_obs(const std::string& pluginPath, const std::string& dataPath);
55
66
  void reset_video();
@@ -68,9 +79,9 @@ class ObsInterface {
68
79
  void list_input_types();
69
80
  void list_output_types();
70
81
 
71
- void configure_output(const std::string& recordingPath);
82
+ void create_scene();
83
+ void create_output(const std::string& recordingPath, bool buffering);
84
+
72
85
  void configure_video_encoder();
73
86
  void configure_audio_encoder();
74
- void configure_scene();
75
- void configure_video_source();
76
87
  };