noobs 0.0.115 → 0.0.131
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/data/obs-plugins/obs-filters/LUTs/black_and_white.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/grayscale.cube +32769 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/grayscale.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/invert.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/original.cube +33 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/original.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/posterize.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/red_isolated.png +0 -0
- package/dist/data/obs-plugins/obs-filters/LUTs/teal_lows_orange_highs.png +0 -0
- package/dist/data/obs-plugins/obs-filters/blend_add_filter.effect +54 -0
- package/dist/data/obs-plugins/obs-filters/blend_mul_filter.effect +54 -0
- package/dist/data/obs-plugins/obs-filters/blend_sub_filter.effect +54 -0
- package/dist/data/obs-plugins/obs-filters/chroma_key_filter.effect +99 -0
- package/dist/data/obs-plugins/obs-filters/chroma_key_filter_v2.effect +111 -0
- package/dist/data/obs-plugins/obs-filters/color.effect +95 -0
- package/dist/data/obs-plugins/obs-filters/color_correction_filter.effect +74 -0
- package/dist/data/obs-plugins/obs-filters/color_grade_filter.effect +177 -0
- package/dist/data/obs-plugins/obs-filters/color_key_filter.effect +65 -0
- package/dist/data/obs-plugins/obs-filters/color_key_filter_v2.effect +77 -0
- package/dist/data/obs-plugins/obs-filters/crop_filter.effect +95 -0
- package/dist/data/obs-plugins/obs-filters/hdr_tonemap_filter.effect +97 -0
- package/dist/data/obs-plugins/obs-filters/locale/af-ZA.ini +89 -0
- package/dist/data/obs-plugins/obs-filters/locale/ar-SA.ini +133 -0
- package/dist/data/obs-plugins/obs-filters/locale/az-AZ.ini +1 -0
- package/dist/data/obs-plugins/obs-filters/locale/ba-RU.ini +19 -0
- package/dist/data/obs-plugins/obs-filters/locale/be-BY.ini +134 -0
- package/dist/data/obs-plugins/obs-filters/locale/bg-BG.ini +71 -0
- package/dist/data/obs-plugins/obs-filters/locale/bn-BD.ini +106 -0
- package/dist/data/obs-plugins/obs-filters/locale/ca-ES.ini +128 -0
- package/dist/data/obs-plugins/obs-filters/locale/cs-CZ.ini +130 -0
- package/dist/data/obs-plugins/obs-filters/locale/da-DK.ini +119 -0
- package/dist/data/obs-plugins/obs-filters/locale/de-DE.ini +113 -0
- package/dist/data/obs-plugins/obs-filters/locale/el-GR.ini +128 -0
- package/dist/data/obs-plugins/obs-filters/locale/en-GB.ini +12 -0
- package/dist/data/obs-plugins/obs-filters/locale/en-US.ini +138 -0
- package/dist/data/obs-plugins/obs-filters/locale/eo-UY.ini +1 -0
- package/dist/data/obs-plugins/obs-filters/locale/es-ES.ini +129 -0
- package/dist/data/obs-plugins/obs-filters/locale/et-EE.ini +132 -0
- package/dist/data/obs-plugins/obs-filters/locale/eu-ES.ini +127 -0
- package/dist/data/obs-plugins/obs-filters/locale/fa-IR.ini +137 -0
- package/dist/data/obs-plugins/obs-filters/locale/fi-FI.ini +127 -0
- package/dist/data/obs-plugins/obs-filters/locale/fil-PH.ini +111 -0
- package/dist/data/obs-plugins/obs-filters/locale/fr-FR.ini +124 -0
- package/dist/data/obs-plugins/obs-filters/locale/gd-GB.ini +94 -0
- package/dist/data/obs-plugins/obs-filters/locale/gl-ES.ini +132 -0
- package/dist/data/obs-plugins/obs-filters/locale/he-IL.ini +135 -0
- package/dist/data/obs-plugins/obs-filters/locale/hi-IN.ini +134 -0
- package/dist/data/obs-plugins/obs-filters/locale/hr-HR.ini +80 -0
- package/dist/data/obs-plugins/obs-filters/locale/hu-HU.ini +131 -0
- package/dist/data/obs-plugins/obs-filters/locale/hy-AM.ini +130 -0
- package/dist/data/obs-plugins/obs-filters/locale/id-ID.ini +112 -0
- package/dist/data/obs-plugins/obs-filters/locale/it-IT.ini +130 -0
- package/dist/data/obs-plugins/obs-filters/locale/ja-JP.ini +134 -0
- package/dist/data/obs-plugins/obs-filters/locale/ka-GE.ini +133 -0
- package/dist/data/obs-plugins/obs-filters/locale/kaa.ini +41 -0
- package/dist/data/obs-plugins/obs-filters/locale/kab-KAB.ini +56 -0
- package/dist/data/obs-plugins/obs-filters/locale/kmr-TR.ini +126 -0
- package/dist/data/obs-plugins/obs-filters/locale/ko-KR.ini +134 -0
- package/dist/data/obs-plugins/obs-filters/locale/ms-MY.ini +131 -0
- package/dist/data/obs-plugins/obs-filters/locale/nb-NO.ini +115 -0
- package/dist/data/obs-plugins/obs-filters/locale/nl-NL.ini +111 -0
- package/dist/data/obs-plugins/obs-filters/locale/nn-NO.ini +19 -0
- package/dist/data/obs-plugins/obs-filters/locale/pl-PL.ini +127 -0
- package/dist/data/obs-plugins/obs-filters/locale/pt-BR.ini +128 -0
- package/dist/data/obs-plugins/obs-filters/locale/pt-PT.ini +130 -0
- package/dist/data/obs-plugins/obs-filters/locale/ro-RO.ini +125 -0
- package/dist/data/obs-plugins/obs-filters/locale/ru-RU.ini +135 -0
- package/dist/data/obs-plugins/obs-filters/locale/si-LK.ini +44 -0
- package/dist/data/obs-plugins/obs-filters/locale/sk-SK.ini +131 -0
- package/dist/data/obs-plugins/obs-filters/locale/sl-SI.ini +133 -0
- package/dist/data/obs-plugins/obs-filters/locale/sr-CS.ini +90 -0
- package/dist/data/obs-plugins/obs-filters/locale/sr-SP.ini +97 -0
- package/dist/data/obs-plugins/obs-filters/locale/sv-SE.ini +129 -0
- package/dist/data/obs-plugins/obs-filters/locale/szl-PL.ini +94 -0
- package/dist/data/obs-plugins/obs-filters/locale/ta-IN.ini +28 -0
- package/dist/data/obs-plugins/obs-filters/locale/th-TH.ini +132 -0
- package/dist/data/obs-plugins/obs-filters/locale/tl-PH.ini +64 -0
- package/dist/data/obs-plugins/obs-filters/locale/tr-TR.ini +129 -0
- package/dist/data/obs-plugins/obs-filters/locale/tt-RU.ini +27 -0
- package/dist/data/obs-plugins/obs-filters/locale/ug-CN.ini +133 -0
- package/dist/data/obs-plugins/obs-filters/locale/uk-UA.ini +135 -0
- package/dist/data/obs-plugins/obs-filters/locale/vi-VN.ini +131 -0
- package/dist/data/obs-plugins/obs-filters/locale/zh-CN.ini +138 -0
- package/dist/data/obs-plugins/obs-filters/locale/zh-TW.ini +136 -0
- package/dist/data/obs-plugins/obs-filters/luma_key_filter.effect +52 -0
- package/dist/data/obs-plugins/obs-filters/luma_key_filter_v2.effect +54 -0
- package/dist/data/obs-plugins/obs-filters/mask_alpha_filter.effect +54 -0
- package/dist/data/obs-plugins/obs-filters/mask_color_filter.effect +55 -0
- package/dist/data/obs-plugins/obs-filters/rtx_greenscreen.effect +183 -0
- package/dist/data/obs-plugins/obs-filters/sharpness.effect +76 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ar-SA.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/be-BY.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/bg-BG.ini +2 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ca-ES.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/cs-CZ.ini +55 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/da-DK.ini +54 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/de-DE.ini +55 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/en-GB.ini +9 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/en-US.ini +75 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/es-ES.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/et-EE.ini +36 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/fa-IR.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/fi-FI.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/fr-FR.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/gl-ES.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/he-IL.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/hi-IN.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/hu-HU.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/id-ID.ini +55 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/is-IS.ini +2 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/it-IT.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ja-JP.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ka-GE.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/kaa.ini +13 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/kmr-TR.ini +20 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ko-KR.ini +58 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ms-MY.ini +58 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/nb-NO.ini +24 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/nl-NL.ini +54 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/nn-NO.ini +1 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/pl-PL.ini +55 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/pt-BR.ini +58 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/pt-PT.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ru-RU.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/sk-SK.ini +56 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/sv-SE.ini +58 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/th-TH.ini +59 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/tr-TR.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/tt-RU.ini +2 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/ug-CN.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/uk-UA.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/vi-VN.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/zh-CN.ini +60 -0
- package/dist/data/obs-plugins/obs-nvenc/locale/zh-TW.ini +60 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/af-ZA.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ar-SA.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ba-RU.ini +2 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/be-BY.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/bg-BG.ini +7 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/bn-BD.ini +8 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ca-ES.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/cs-CZ.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/da-DK.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/de-DE.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/el-GR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/en-GB.ini +1 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/en-US.ini +21 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/es-ES.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/et-EE.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/eu-ES.ini +11 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/fa-IR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/fi-FI.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/fil-PH.ini +11 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/fr-FR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/gd-GB.ini +8 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/gl-ES.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/he-IL.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/hi-IN.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/hr-HR.ini +14 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/hu-HU.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/hy-AM.ini +13 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/id-ID.ini +18 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/is-IS.ini +1 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/it-IT.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ja-JP.ini +16 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ka-GE.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/kaa.ini +10 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/kab-KAB.ini +5 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/kmr-TR.ini +12 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ko-KR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ms-MY.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/nb-NO.ini +16 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/nl-NL.ini +18 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/nn-NO.ini +2 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/oc-FR.ini +1 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/pl-PL.ini +16 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/pt-BR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/pt-PT.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ro-RO.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ru-RU.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/si-LK.ini +8 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/sk-SK.ini +19 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/sl-SI.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/sr-CS.ini +6 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/sr-SP.ini +10 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/sv-SE.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ta-IN.ini +2 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/th-TH.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/tl-PH.ini +5 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/tr-TR.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/tt-RU.ini +3 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/ug-CN.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/uk-UA.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/vi-VN.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/zh-CN.ini +20 -0
- package/dist/data/obs-plugins/obs-qsv11/locale/zh-TW.ini +20 -0
- package/dist/noobs.node +0 -0
- package/dist/obs-plugins/image-source.dll +0 -0
- package/dist/obs-plugins/obs-filters.dll +0 -0
- package/dist/obs-plugins/obs-nvenc.dll +0 -0
- package/dist/obs-plugins/obs-qsv11.dll +0 -0
- package/dist/obs-plugins/obs-x264.dll +0 -0
- package/dist/obs-plugins/win-capture.dll +0 -0
- package/dist/obs-plugins/win-wasapi.dll +0 -0
- package/index.d.ts +5 -8
- package/package.json +1 -1
- package/src/main.cpp +34 -65
- package/src/obs_interface.cpp +322 -215
- package/src/obs_interface.h +29 -27
package/src/obs_interface.cpp
CHANGED
|
@@ -55,9 +55,10 @@ void ObsInterface::list_output_types()
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
void ObsInterface::load_module(const char* module, const char* data) {
|
|
58
|
+
void ObsInterface::load_module(const char* module, const char* data, bool allowFail) {
|
|
59
59
|
blog(LOG_INFO, "Loading module: %s", module);
|
|
60
60
|
blog(LOG_INFO, "Data path: %s", data);
|
|
61
|
+
blog(LOG_INFO, "Allow fail: %d", allowFail);
|
|
61
62
|
|
|
62
63
|
obs_module_t *ptr = NULL;
|
|
63
64
|
int success = obs_open_module(&ptr, module, data);
|
|
@@ -69,8 +70,12 @@ void ObsInterface::load_module(const char* module, const char* data) {
|
|
|
69
70
|
|
|
70
71
|
bool initmod = obs_init_module(ptr);
|
|
71
72
|
|
|
72
|
-
if (
|
|
73
|
-
blog(
|
|
73
|
+
if (initmod) {
|
|
74
|
+
blog(LOG_INFO, "Module initialized successfully!");
|
|
75
|
+
} else if (allowFail) {
|
|
76
|
+
blog(LOG_INFO, "Module initialization failed, but allowed to fail: %s", module);
|
|
77
|
+
} else {
|
|
78
|
+
blog(LOG_ERROR, "Failed to initialize module: %s", module);
|
|
74
79
|
throw std::runtime_error("Module initialization failed!");
|
|
75
80
|
}
|
|
76
81
|
}
|
|
@@ -189,17 +194,23 @@ void ObsInterface::init_obs(const std::string& distPath) {
|
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
std::vector<std::string> modules = {
|
|
192
|
-
"obs-x264",
|
|
193
|
-
"obs-ffmpeg",
|
|
197
|
+
"obs-x264", // Software encoder.
|
|
198
|
+
"obs-ffmpeg", // Contains AMF (AMD) encoder support.
|
|
194
199
|
"win-capture", // Required for basically all forms of capture on Windows.
|
|
195
200
|
"image-source", // Required for image sources.
|
|
196
|
-
"win-wasapi"
|
|
201
|
+
"win-wasapi", // Required for WASAPI audio input.
|
|
202
|
+
"obs-nvenc", // Required for NVENC video encoding.
|
|
203
|
+
"obs-qsv11", // Required for QSV video encoding.
|
|
204
|
+
"obs-filters" // Required for audio filters.
|
|
197
205
|
};
|
|
198
206
|
|
|
199
207
|
for (const auto& module : modules) {
|
|
200
208
|
std::string modulePath = pluginPath + module + ".dll";
|
|
201
209
|
std::string moduleDataPath = pluginDataPath + module;
|
|
202
|
-
|
|
210
|
+
|
|
211
|
+
// NVENC fails if there is no NVENC hardware support.
|
|
212
|
+
bool allowFail = module == "obs-nvenc";
|
|
213
|
+
load_module(modulePath.c_str(), moduleDataPath.c_str(), allowFail);
|
|
203
214
|
}
|
|
204
215
|
|
|
205
216
|
obs_post_load_modules();
|
|
@@ -214,168 +225,119 @@ void ObsInterface::init_obs(const std::string& distPath) {
|
|
|
214
225
|
void ObsInterface::create_output() {
|
|
215
226
|
blog(LOG_INFO, "Create outputs");
|
|
216
227
|
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
const char* type = buffering ? "replay_buffer" : "ffmpeg_muxer";
|
|
229
|
+
const char* name = buffering ? "Buffer Output" : "File Output";
|
|
219
230
|
|
|
220
|
-
if (
|
|
221
|
-
blog(
|
|
222
|
-
|
|
231
|
+
if (output) {
|
|
232
|
+
blog(LOG_DEBUG, "Releasing existing output");
|
|
233
|
+
obs_output_release(output);
|
|
223
234
|
}
|
|
224
235
|
|
|
225
|
-
blog(LOG_INFO, "Creating
|
|
226
|
-
|
|
236
|
+
blog(LOG_INFO, "Creating replay buffer output");
|
|
237
|
+
output = obs_output_create(type, name, NULL, NULL);
|
|
227
238
|
|
|
228
|
-
if (!
|
|
229
|
-
blog(LOG_ERROR, "Failed to create
|
|
230
|
-
throw std::runtime_error("Failed to create
|
|
239
|
+
if (!output) {
|
|
240
|
+
blog(LOG_ERROR, "Failed to create output!");
|
|
241
|
+
throw std::runtime_error("Failed to create output!");
|
|
231
242
|
}
|
|
232
243
|
|
|
233
|
-
obs_data_t *
|
|
234
|
-
blog(LOG_INFO, "Set replay_buffer settings");
|
|
235
|
-
obs_data_set_int(buffer_settings, "max_time_sec", 60);
|
|
236
|
-
obs_data_set_int(buffer_settings, "max_size_mb", 1024);
|
|
237
|
-
obs_data_set_string(buffer_settings, "directory", recording_path.c_str());
|
|
238
|
-
obs_data_set_string(buffer_settings, "format", "%CCYY-%MM-%DD %hh-%mm-%ss");
|
|
239
|
-
obs_data_set_string(buffer_settings, "extension", "mp4");
|
|
240
|
-
obs_output_update(buffer_output, buffer_settings);
|
|
241
|
-
obs_data_release(buffer_settings);
|
|
244
|
+
obs_data_t *settings = obs_data_create();
|
|
242
245
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
246
|
+
if (buffering) {
|
|
247
|
+
blog(LOG_INFO, "Set replay buffer settings");
|
|
248
|
+
obs_data_set_int(settings, "max_time_sec", 60);
|
|
249
|
+
obs_data_set_int(settings, "max_size_mb", 1024);
|
|
250
|
+
obs_data_set_string(settings, "directory", recording_path.c_str());
|
|
251
|
+
obs_data_set_string(settings, "format", "%CCYY-%MM-%DD %hh-%mm-%ss");
|
|
252
|
+
obs_data_set_string(settings, "extension", "mp4");
|
|
253
|
+
} else {
|
|
254
|
+
blog(LOG_INFO, "Set ffmpeg_muxer settings");
|
|
255
|
+
// Need to specify the exact path for ffmpeg_muxer. We will write this again at start recording.
|
|
256
|
+
std::string filename = recording_path + "\\" + get_current_date_time() + ".mp4";
|
|
257
|
+
obs_data_set_string(settings, "path", filename.c_str());
|
|
258
|
+
unbuffered_output_filename = filename;
|
|
259
|
+
}
|
|
253
260
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
connect_signal_handlers(
|
|
261
|
+
obs_output_update(output, settings);
|
|
262
|
+
obs_data_release(settings);
|
|
263
|
+
connect_signal_handlers(output);
|
|
257
264
|
}
|
|
258
265
|
|
|
259
266
|
void ObsInterface::setRecordingDir(const std::string& recordingPath) {
|
|
260
|
-
blog(LOG_INFO, "Set recording directory");
|
|
261
|
-
// TODO make this work for file output also.
|
|
262
|
-
|
|
263
|
-
obs_output_t *output = buffering ? buffer_output : file_output;
|
|
264
|
-
|
|
265
|
-
if (!output) {
|
|
266
|
-
blog(LOG_ERROR, "No output to update recording directory");
|
|
267
|
-
throw std::runtime_error("Output not initialized");
|
|
268
|
-
}
|
|
267
|
+
blog(LOG_INFO, "Set recording directory. Path: %s", recordingPath.c_str());
|
|
269
268
|
|
|
270
|
-
// check its not active
|
|
271
269
|
if (obs_output_active(output)) {
|
|
272
270
|
blog(LOG_ERROR, "Output is active, cannot update recording path");
|
|
273
271
|
throw std::runtime_error("Output is active, cannot update recording path");
|
|
274
272
|
}
|
|
275
273
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (!settings) {
|
|
279
|
-
blog(LOG_ERROR, "Failed to get output settings");
|
|
280
|
-
throw std::runtime_error("Failed to get output settings");
|
|
281
|
-
}
|
|
274
|
+
recording_path = recordingPath;
|
|
275
|
+
create_output();
|
|
282
276
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
obs_data_release(settings);
|
|
277
|
+
create_video_encoders();
|
|
278
|
+
create_audio_encoders();
|
|
286
279
|
}
|
|
287
280
|
|
|
288
281
|
void ObsInterface::create_video_encoders() {
|
|
289
282
|
blog(LOG_INFO, "Set video encoder: %s", video_encoder_id.c_str());
|
|
290
283
|
|
|
291
|
-
if (
|
|
284
|
+
if (video_encoder) {
|
|
292
285
|
blog(LOG_DEBUG, "Releasing file video encoder");
|
|
293
|
-
obs_encoder_release(
|
|
294
|
-
|
|
286
|
+
obs_encoder_release(video_encoder);
|
|
287
|
+
video_encoder = nullptr;
|
|
295
288
|
}
|
|
296
289
|
|
|
297
|
-
|
|
290
|
+
video_encoder = obs_video_encoder_create(
|
|
298
291
|
video_encoder_id.c_str(),
|
|
299
292
|
"noobs_file_encoder",
|
|
300
293
|
video_encoder_settings,
|
|
301
294
|
NULL
|
|
302
295
|
);
|
|
303
296
|
|
|
304
|
-
if (!
|
|
297
|
+
if (!video_encoder) {
|
|
305
298
|
blog(LOG_ERROR, "Failed to create video encoder!");
|
|
306
299
|
throw std::runtime_error("Failed to create video encoder!");
|
|
307
300
|
}
|
|
308
301
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
obs_encoder_release(buffer_video_encoder);
|
|
312
|
-
buffer_video_encoder = nullptr;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
buffer_video_encoder = obs_video_encoder_create(
|
|
316
|
-
video_encoder_id.c_str(),
|
|
317
|
-
"noobs_buffer_encoder",
|
|
318
|
-
video_encoder_settings,
|
|
319
|
-
NULL
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
if (!buffer_video_encoder) {
|
|
323
|
-
blog(LOG_ERROR, "Failed to create buffer video encoder!");
|
|
324
|
-
throw std::runtime_error("Failed to create buffer video encoder!");
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
obs_output_set_video_encoder(file_output, file_video_encoder);
|
|
328
|
-
obs_output_set_video_encoder(buffer_output, buffer_video_encoder);
|
|
329
|
-
|
|
330
|
-
obs_encoder_set_video(file_video_encoder, obs_get_video());
|
|
331
|
-
obs_encoder_set_video(buffer_video_encoder, obs_get_video());
|
|
302
|
+
obs_output_set_video_encoder(output, video_encoder);
|
|
303
|
+
obs_encoder_set_video(video_encoder, obs_get_video());
|
|
332
304
|
}
|
|
333
305
|
|
|
334
306
|
void ObsInterface::create_audio_encoders() {
|
|
335
307
|
blog(LOG_INFO, "Create audio encoder");
|
|
336
308
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// if (audio_encoder) {
|
|
343
|
-
// blog(LOG_DEBUG, "Releasing audio encoder");
|
|
344
|
-
// obs_encoder_release(audio_encoder);
|
|
345
|
-
// audio_encoder = nullptr;
|
|
346
|
-
// }
|
|
309
|
+
if (audio_encoder) {
|
|
310
|
+
blog(LOG_DEBUG, "Releasing audio encoder");
|
|
311
|
+
obs_encoder_release(audio_encoder);
|
|
312
|
+
audio_encoder = nullptr;
|
|
313
|
+
}
|
|
347
314
|
|
|
348
|
-
|
|
315
|
+
audio_encoder = obs_audio_encoder_create(
|
|
316
|
+
"ffmpeg_aac",
|
|
317
|
+
"aac_file",
|
|
318
|
+
NULL,
|
|
319
|
+
0,
|
|
320
|
+
NULL
|
|
321
|
+
);
|
|
349
322
|
|
|
350
|
-
if (!
|
|
323
|
+
if (!audio_encoder) {
|
|
351
324
|
blog(LOG_ERROR, "Failed to create audio encoder!");
|
|
352
325
|
throw std::runtime_error("Failed to create audio encoder!");
|
|
353
326
|
}
|
|
354
327
|
|
|
355
|
-
buffer_audio_encoder = obs_audio_encoder_create("ffmpeg_aac", "aac_buffer", NULL, 0, NULL);
|
|
356
|
-
|
|
357
|
-
if (!buffer_audio_encoder) {
|
|
358
|
-
blog(LOG_ERROR, "Failed to create buffer audio encoder!");
|
|
359
|
-
throw std::runtime_error("Failed to create buffer audio encoder!");
|
|
360
|
-
}
|
|
361
|
-
|
|
362
328
|
blog(LOG_INFO, "Set audio encoder settings");
|
|
363
329
|
obs_data_t *aenc_settings = obs_data_create();
|
|
364
330
|
obs_data_set_int(aenc_settings, "bitrate", 128);
|
|
365
|
-
obs_encoder_update(
|
|
366
|
-
obs_encoder_update(buffer_audio_encoder, aenc_settings);
|
|
331
|
+
obs_encoder_update(audio_encoder, aenc_settings);
|
|
367
332
|
obs_data_release(aenc_settings);
|
|
368
333
|
|
|
369
|
-
obs_output_set_audio_encoder(
|
|
370
|
-
obs_encoder_set_audio(
|
|
371
|
-
|
|
372
|
-
obs_output_set_audio_encoder(buffer_output, buffer_audio_encoder, 0);
|
|
373
|
-
obs_encoder_set_audio(buffer_audio_encoder, obs_get_audio());
|
|
334
|
+
obs_output_set_audio_encoder(output, audio_encoder, 0);
|
|
335
|
+
obs_encoder_set_audio(audio_encoder, obs_get_audio());
|
|
374
336
|
}
|
|
375
337
|
|
|
376
338
|
void ObsInterface::create_scene() {
|
|
377
339
|
blog(LOG_INFO, "Create scene");
|
|
378
|
-
scene = obs_scene_create("
|
|
340
|
+
scene = obs_scene_create("Base Scene");
|
|
379
341
|
|
|
380
342
|
if (!scene) {
|
|
381
343
|
blog(LOG_ERROR, "Failed to create scene!");
|
|
@@ -414,7 +376,7 @@ void ObsInterface::volmeter_callback(void *data,
|
|
|
414
376
|
self->jscb.NonBlockingCall(sd, call_jscb);
|
|
415
377
|
}
|
|
416
378
|
|
|
417
|
-
|
|
379
|
+
std::string ObsInterface::createSource(std::string name, std::string type) {
|
|
418
380
|
blog(LOG_INFO, "Create source: %s of type %s", name.c_str(), type.c_str());
|
|
419
381
|
|
|
420
382
|
obs_source_t *source = obs_source_create(
|
|
@@ -429,32 +391,60 @@ void ObsInterface::createSource(std::string name, std::string type) {
|
|
|
429
391
|
throw std::runtime_error("Failed to create source!");
|
|
430
392
|
}
|
|
431
393
|
|
|
432
|
-
if
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
} else if (type == AUDIO_INPUT) {
|
|
436
|
-
blog(LOG_INFO, "Setting input volume for source: %s to %d", name.c_str(), input_volume);
|
|
437
|
-
obs_source_set_volume(source, input_volume);
|
|
438
|
-
} else if (type == AUDIO_PROCESS) {
|
|
439
|
-
blog(LOG_INFO, "Setting process volume for source: %s to %d", name.c_str(), process_volume);
|
|
440
|
-
obs_source_set_volume(source, process_volume);
|
|
441
|
-
}
|
|
394
|
+
// The name might not match what we asked for if there is a duplicate.
|
|
395
|
+
// So pass it back to the client to avoid potential for a mismatch.
|
|
396
|
+
std::string real_name = obs_source_get_name(source);
|
|
442
397
|
|
|
443
398
|
if (type == AUDIO_OUTPUT || type == AUDIO_INPUT || type == AUDIO_PROCESS) {
|
|
444
|
-
blog(LOG_INFO, "Creating volmeter for source: %s",
|
|
399
|
+
blog(LOG_INFO, "Creating volmeter for source: %s", real_name.c_str());
|
|
445
400
|
|
|
446
401
|
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_CUBIC);
|
|
447
402
|
obs_volmeter_attach_source(volmeter, source);
|
|
448
403
|
|
|
449
|
-
SignalContext* ctx = new SignalContext{ this,
|
|
404
|
+
SignalContext* ctx = new SignalContext{ this, real_name };
|
|
450
405
|
obs_volmeter_add_callback(volmeter, volmeter_callback, ctx);
|
|
451
406
|
|
|
452
407
|
// Store the volmeter in the volmeters map.
|
|
453
|
-
volmeters[
|
|
408
|
+
volmeters[real_name] = volmeter;
|
|
409
|
+
volmeter_cb_ctx[real_name] = ctx; // Track this so we can free it later.
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (type == AUDIO_INPUT && force_mono) {
|
|
413
|
+
blog(LOG_INFO, "Setting force mono for new source: %s", real_name.c_str());
|
|
414
|
+
uint32_t flags = obs_source_get_flags(source);
|
|
415
|
+
obs_source_set_flags(source, flags | OBS_SOURCE_FLAG_FORCE_MONO);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (type == AUDIO_INPUT && audio_suppression) {
|
|
419
|
+
blog(LOG_INFO, "Setting up filter for new source: %s", real_name.c_str());
|
|
420
|
+
std::string filter_name = "Filter for " + real_name;
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
obs_source_t *filter = obs_source_create(
|
|
424
|
+
"noise_suppress_filter_v2",
|
|
425
|
+
filter_name.c_str(),
|
|
426
|
+
nullptr, // Defaults are sensible.
|
|
427
|
+
nullptr
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
if (!filter) {
|
|
431
|
+
blog(LOG_ERROR, "Failed to create filter for source: %s", real_name.c_str());
|
|
432
|
+
throw std::runtime_error("Failed to create filter!");
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
filters[real_name] = filter;
|
|
436
|
+
obs_source_filter_add(source, filter);
|
|
454
437
|
}
|
|
455
438
|
|
|
456
439
|
// Store the source in the sources map.
|
|
457
|
-
sources[
|
|
440
|
+
sources[real_name] = source;
|
|
441
|
+
|
|
442
|
+
// Store the dimensions so we can fire a callback if they change.
|
|
443
|
+
uint32_t w = obs_source_get_width(source);
|
|
444
|
+
uint32_t h = obs_source_get_height(source);
|
|
445
|
+
sizes[real_name] = { w, h };
|
|
446
|
+
|
|
447
|
+
return real_name;
|
|
458
448
|
}
|
|
459
449
|
|
|
460
450
|
void ObsInterface::deleteSource(std::string name) {
|
|
@@ -473,18 +463,40 @@ void ObsInterface::deleteSource(std::string name) {
|
|
|
473
463
|
volmeters.erase(name);
|
|
474
464
|
}
|
|
475
465
|
|
|
466
|
+
// Now deal with the callback context.
|
|
467
|
+
auto ctx_it = volmeter_cb_ctx.find(name);
|
|
468
|
+
|
|
469
|
+
if (ctx_it != volmeter_cb_ctx.end()) {
|
|
470
|
+
SignalContext* ctx = ctx_it->second;
|
|
471
|
+
delete ctx;
|
|
472
|
+
volmeter_cb_ctx.erase(ctx_it);
|
|
473
|
+
}
|
|
474
|
+
|
|
476
475
|
// Now deal with the source itself.
|
|
477
476
|
auto it = sources.find(name);
|
|
478
477
|
|
|
479
478
|
if (it == sources.end()) {
|
|
480
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
479
|
+
blog(LOG_WARNING, "Source %s not found when deleting", name.c_str());
|
|
481
480
|
return;
|
|
482
481
|
}
|
|
483
482
|
|
|
484
483
|
obs_source_t* source = it->second;
|
|
484
|
+
|
|
485
|
+
// Remove and release any filters.
|
|
486
|
+
auto filter_it = filters.find(name);
|
|
487
|
+
|
|
488
|
+
if (filter_it != filters.end()) {
|
|
489
|
+
obs_source_t* filter = filter_it->second;
|
|
490
|
+
obs_source_filter_remove(source, filter);
|
|
491
|
+
obs_source_release(filter);
|
|
492
|
+
filters.erase(name);
|
|
493
|
+
blog(LOG_INFO, "Filter deleted for source: %s", name.c_str());
|
|
494
|
+
}
|
|
495
|
+
|
|
485
496
|
obs_source_remove(source); // ???
|
|
486
497
|
obs_source_release(source);
|
|
487
498
|
sources.erase(name);
|
|
499
|
+
sizes.erase(name);
|
|
488
500
|
blog(LOG_INFO, "Source deleted: %s", name.c_str());
|
|
489
501
|
}
|
|
490
502
|
|
|
@@ -494,7 +506,7 @@ obs_data_t* ObsInterface::getSourceSettings(std::string name) {
|
|
|
494
506
|
auto it = sources.find(name);
|
|
495
507
|
|
|
496
508
|
if (it == sources.end()) {
|
|
497
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
509
|
+
blog(LOG_WARNING, "Source %s not found when getting settings", name.c_str());
|
|
498
510
|
throw std::runtime_error("Source not found!");
|
|
499
511
|
}
|
|
500
512
|
|
|
@@ -506,7 +518,6 @@ obs_data_t* ObsInterface::getSourceSettings(std::string name) {
|
|
|
506
518
|
throw std::runtime_error("Failed to get source settings!");
|
|
507
519
|
}
|
|
508
520
|
|
|
509
|
-
// obs_data_release(settings); TODO release after returning to client.
|
|
510
521
|
return settings;
|
|
511
522
|
}
|
|
512
523
|
|
|
@@ -515,13 +526,27 @@ void ObsInterface::setSourceSettings(std::string name, obs_data_t* settings) {
|
|
|
515
526
|
auto it = sources.find(name);
|
|
516
527
|
|
|
517
528
|
if (it == sources.end()) {
|
|
518
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
529
|
+
blog(LOG_WARNING, "Source %s not found when setting settings", name.c_str());
|
|
519
530
|
throw std::runtime_error("Source not found!");
|
|
520
531
|
}
|
|
521
532
|
|
|
522
533
|
obs_source_t* source = it->second;
|
|
523
|
-
|
|
524
534
|
obs_source_update(source, settings);
|
|
535
|
+
|
|
536
|
+
// If this is an audio source, it may have an attached volmeter.
|
|
537
|
+
auto vol_it = volmeters.find(name);
|
|
538
|
+
|
|
539
|
+
if (vol_it != volmeters.end()) {
|
|
540
|
+
// Rebind it. This avoids leaving it attached to stale audio stream
|
|
541
|
+
// in the event of a device change.
|
|
542
|
+
blog(LOG_INFO, "Rebinding volmeter for source: %s", name.c_str());
|
|
543
|
+
obs_volmeter_t* volmeter = vol_it->second;
|
|
544
|
+
obs_volmeter_attach_source(volmeter, source);
|
|
545
|
+
|
|
546
|
+
// Flush the volmeter: send a zero signal in-case it never triggers any
|
|
547
|
+
// more callbacks. That can happen on selecting a device with no audio.
|
|
548
|
+
zeroVolmeter(name);
|
|
549
|
+
}
|
|
525
550
|
}
|
|
526
551
|
|
|
527
552
|
obs_properties_t* ObsInterface::getSourceProperties(std::string name) {
|
|
@@ -529,7 +554,7 @@ obs_properties_t* ObsInterface::getSourceProperties(std::string name) {
|
|
|
529
554
|
auto it = sources.find(name);
|
|
530
555
|
|
|
531
556
|
if (it == sources.end()) {
|
|
532
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
557
|
+
blog(LOG_WARNING, "Source %s not found when getting properties", name.c_str());
|
|
533
558
|
throw std::runtime_error("Source not found!");
|
|
534
559
|
}
|
|
535
560
|
|
|
@@ -671,15 +696,30 @@ void draw_callback(void* data, uint32_t cx, uint32_t cy) {
|
|
|
671
696
|
// Renders the scene now the graphics context is setup.
|
|
672
697
|
obs_render_main_texture();
|
|
673
698
|
|
|
674
|
-
// Draw boxes around sources.
|
|
675
|
-
obs_scene_t* scene = obs_get_scene_by_name("WCR Scene");
|
|
699
|
+
// Draw boxes around sources, if enabled.
|
|
676
700
|
if (obsInterface->getDrawSourceOutlineEnabled()) {
|
|
701
|
+
obs_scene_t* scene = obs_get_scene_by_name("Base Scene");
|
|
677
702
|
obs_scene_enum_items(scene, draw_source_outline, NULL);
|
|
703
|
+
obs_scene_release(scene);
|
|
678
704
|
}
|
|
679
|
-
obs_scene_release(scene);
|
|
680
705
|
|
|
681
706
|
gs_projection_pop();
|
|
682
707
|
gs_viewport_pop();
|
|
708
|
+
|
|
709
|
+
// Iterate over the sources and check for changes to size.
|
|
710
|
+
for (const auto& [name, source] : obsInterface->sources) {
|
|
711
|
+
SourceSize last = obsInterface->sizes[name];
|
|
712
|
+
|
|
713
|
+
uint32_t w = obs_source_get_width(source);
|
|
714
|
+
uint32_t h = obs_source_get_height(source);
|
|
715
|
+
|
|
716
|
+
if (w != last.width || h != last.height) {
|
|
717
|
+
blog(LOG_INFO, "Source %s changed size from (%d x %d) to (%d x %d)",
|
|
718
|
+
name.c_str(), last.width, last.height, w, h);
|
|
719
|
+
obsInterface->sourceCallback(name);
|
|
720
|
+
obsInterface->sizes[name] = { w, h };
|
|
721
|
+
}
|
|
722
|
+
}
|
|
683
723
|
}
|
|
684
724
|
|
|
685
725
|
void ObsInterface::initPreview(HWND parent) {
|
|
@@ -712,8 +752,8 @@ void ObsInterface::initPreview(HWND parent) {
|
|
|
712
752
|
|
|
713
753
|
gs_init_data gs_data = {};
|
|
714
754
|
gs_data.adapter = 0;
|
|
715
|
-
gs_data.cx = 1920; //
|
|
716
|
-
gs_data.cy = 1080; //
|
|
755
|
+
gs_data.cx = 1920; // Gets overwritten when we call configurePreview().
|
|
756
|
+
gs_data.cy = 1080; // Gets overwritten when we call configurePreview().
|
|
717
757
|
gs_data.format = GS_BGRA;
|
|
718
758
|
gs_data.zsformat = GS_ZS_NONE;
|
|
719
759
|
gs_data.num_backbuffers = 1;
|
|
@@ -733,7 +773,7 @@ void ObsInterface::initPreview(HWND parent) {
|
|
|
733
773
|
}
|
|
734
774
|
|
|
735
775
|
void ObsInterface::configurePreview(int x, int y, int width, int height) {
|
|
736
|
-
blog(LOG_INFO, "ObsInterface::
|
|
776
|
+
blog(LOG_INFO, "ObsInterface::configurePreview");
|
|
737
777
|
|
|
738
778
|
if (!preview_hwnd || !display) {
|
|
739
779
|
blog(LOG_ERROR, "Preview window not initialized");
|
|
@@ -756,9 +796,6 @@ void ObsInterface::configurePreview(int x, int y, int width, int height) {
|
|
|
756
796
|
return;
|
|
757
797
|
}
|
|
758
798
|
|
|
759
|
-
uint32_t w, h;
|
|
760
|
-
obs_display_size(display, &w, &h); // Get the display size to match the video context.
|
|
761
|
-
blog(LOG_INFO, "Current Display size set to (%d x %d)", w, h);
|
|
762
799
|
obs_display_resize(display, width, height);
|
|
763
800
|
obs_display_set_enabled(display, true);
|
|
764
801
|
}
|
|
@@ -829,7 +866,6 @@ bool ObsInterface::getDrawSourceOutlineEnabled() {
|
|
|
829
866
|
ObsInterface::ObsInterface(
|
|
830
867
|
const std::string& distPath,
|
|
831
868
|
const std::string& logPath,
|
|
832
|
-
const std::string& recordingPath,
|
|
833
869
|
Napi::ThreadSafeFunction cb
|
|
834
870
|
) {
|
|
835
871
|
// Setup logs first so we have logs for the initialization.
|
|
@@ -841,19 +877,16 @@ ObsInterface::ObsInterface(
|
|
|
841
877
|
|
|
842
878
|
// Setup callback function.
|
|
843
879
|
jscb = cb;
|
|
844
|
-
recording_path = recordingPath;
|
|
845
880
|
|
|
881
|
+
// Contexts for signal callbacks.
|
|
846
882
|
starting_ctx = new SignalContext{ this, "starting" };
|
|
847
883
|
start_ctx = new SignalContext{ this, "start" };
|
|
848
884
|
stopping_ctx = new SignalContext{ this, "stopping" };
|
|
849
885
|
stop_ctx = new SignalContext{ this, "stop" };
|
|
850
886
|
|
|
851
887
|
// Create the resources we rely on.
|
|
852
|
-
create_output();
|
|
853
888
|
create_scene();
|
|
854
|
-
|
|
855
|
-
video_encoder_id = "obs_x264";
|
|
856
|
-
video_encoder_settings = obs_data_create();
|
|
889
|
+
create_output();
|
|
857
890
|
create_video_encoders();
|
|
858
891
|
create_audio_encoders();
|
|
859
892
|
}
|
|
@@ -870,6 +903,12 @@ ObsInterface::~ObsInterface() {
|
|
|
870
903
|
volmeters.erase(kv.first);
|
|
871
904
|
}
|
|
872
905
|
|
|
906
|
+
for (auto& kv : volmeter_cb_ctx) {
|
|
907
|
+
SignalContext* ctx = kv.second;
|
|
908
|
+
delete ctx;
|
|
909
|
+
volmeter_cb_ctx.erase(kv.first);
|
|
910
|
+
}
|
|
911
|
+
|
|
873
912
|
delete starting_ctx;
|
|
874
913
|
delete start_ctx;
|
|
875
914
|
delete stopping_ctx;
|
|
@@ -878,6 +917,17 @@ ObsInterface::~ObsInterface() {
|
|
|
878
917
|
for (auto& kv : sources) {
|
|
879
918
|
std::string name = kv.first;
|
|
880
919
|
obs_source_t* source = kv.second;
|
|
920
|
+
|
|
921
|
+
auto filter_it = filters.find(name);
|
|
922
|
+
|
|
923
|
+
if (filter_it != filters.end()) {
|
|
924
|
+
obs_source_t* filter = filter_it->second;
|
|
925
|
+
obs_source_filter_remove(source, filter);
|
|
926
|
+
obs_source_release(filter);
|
|
927
|
+
filters.erase(name);
|
|
928
|
+
blog(LOG_INFO, "Filter removed for source: %s on shutdown", name.c_str());
|
|
929
|
+
}
|
|
930
|
+
|
|
881
931
|
blog(LOG_DEBUG, "Releasing source: %s", name.c_str());
|
|
882
932
|
obs_source_release(source);
|
|
883
933
|
sources.erase(name);
|
|
@@ -888,24 +938,14 @@ ObsInterface::~ObsInterface() {
|
|
|
888
938
|
obs_scene_release(scene);
|
|
889
939
|
}
|
|
890
940
|
|
|
891
|
-
if (
|
|
892
|
-
if (obs_output_active(
|
|
941
|
+
if (output) {
|
|
942
|
+
if (obs_output_active(output)) {
|
|
893
943
|
blog(LOG_DEBUG, "Force stopping output");
|
|
894
|
-
obs_output_force_stop(
|
|
944
|
+
obs_output_force_stop(output);
|
|
895
945
|
}
|
|
896
946
|
|
|
897
947
|
blog(LOG_DEBUG, "Releasing output");
|
|
898
|
-
obs_output_release(
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
if (file_output) {
|
|
902
|
-
if (obs_output_active(file_output)) {
|
|
903
|
-
blog(LOG_DEBUG, "Force stopping output");
|
|
904
|
-
obs_output_force_stop(file_output);
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
blog(LOG_DEBUG, "Releasing output");
|
|
908
|
-
obs_output_release(file_output);
|
|
948
|
+
obs_output_release(output);
|
|
909
949
|
}
|
|
910
950
|
|
|
911
951
|
// if (video_encoder) {
|
|
@@ -927,16 +967,14 @@ ObsInterface::~ObsInterface() {
|
|
|
927
967
|
}
|
|
928
968
|
}
|
|
929
969
|
|
|
930
|
-
|
|
931
|
-
obs_output_t* output = buffering ? buffer_output : file_output;
|
|
932
|
-
|
|
970
|
+
void ObsInterface::setBuffering(bool value) {
|
|
933
971
|
if (obs_output_active(output)) {
|
|
934
972
|
blog(LOG_ERROR, "Cannot change buffering state while output is active");
|
|
935
|
-
|
|
973
|
+
throw new std::runtime_error("Cannot change buffering state while output is active");
|
|
936
974
|
}
|
|
937
975
|
|
|
938
976
|
buffering = value;
|
|
939
|
-
|
|
977
|
+
create_output();
|
|
940
978
|
}
|
|
941
979
|
|
|
942
980
|
void ObsInterface::startBuffering() {
|
|
@@ -947,8 +985,6 @@ void ObsInterface::startBuffering() {
|
|
|
947
985
|
throw std::runtime_error("Buffering is not enabled!");
|
|
948
986
|
}
|
|
949
987
|
|
|
950
|
-
obs_output_t* output = buffer_output;
|
|
951
|
-
|
|
952
988
|
if (!output) {
|
|
953
989
|
blog(LOG_ERROR, "Output is not initialized!");
|
|
954
990
|
throw std::runtime_error("Output is not initialized!");
|
|
@@ -973,7 +1009,11 @@ void ObsInterface::startBuffering() {
|
|
|
973
1009
|
|
|
974
1010
|
void ObsInterface::startRecording(int offset) {
|
|
975
1011
|
blog(LOG_INFO, "ObsInterface::startRecording enter");
|
|
976
|
-
|
|
1012
|
+
|
|
1013
|
+
if (recording_path == "") {
|
|
1014
|
+
blog(LOG_ERROR, "Recording path is not set");
|
|
1015
|
+
throw std::runtime_error("Recording path is not set");
|
|
1016
|
+
}
|
|
977
1017
|
|
|
978
1018
|
if (buffering) {
|
|
979
1019
|
bool is_active = obs_output_active(output);
|
|
@@ -992,10 +1032,10 @@ void ObsInterface::startRecording(int offset) {
|
|
|
992
1032
|
calldata_free(&cd);
|
|
993
1033
|
|
|
994
1034
|
if (!success) {
|
|
1035
|
+
blog(LOG_ERROR, "Failed to call convert procedure handler");
|
|
995
1036
|
throw std::runtime_error("Failed to call convert procedure handler");
|
|
996
1037
|
}
|
|
997
1038
|
} else {
|
|
998
|
-
|
|
999
1039
|
obs_data_t *ffmpeg_settings = obs_data_create();
|
|
1000
1040
|
std::string filename = recording_path + "\\" + get_current_date_time() + ".mp4";
|
|
1001
1041
|
obs_data_set_string(ffmpeg_settings, "path", filename.c_str());
|
|
@@ -1027,7 +1067,6 @@ void ObsInterface::startRecording(int offset) {
|
|
|
1027
1067
|
|
|
1028
1068
|
void ObsInterface::stopRecording() {
|
|
1029
1069
|
blog(LOG_INFO, "ObsInterface::stopRecording enter");
|
|
1030
|
-
obs_output_t* output = buffering ? buffer_output : file_output;
|
|
1031
1070
|
bool is_active = obs_output_active(output);
|
|
1032
1071
|
|
|
1033
1072
|
if (!is_active) {
|
|
@@ -1041,7 +1080,6 @@ void ObsInterface::stopRecording() {
|
|
|
1041
1080
|
|
|
1042
1081
|
void ObsInterface::forceStopRecording() {
|
|
1043
1082
|
blog(LOG_INFO, "ObsInterface::forceStopRecording enter");
|
|
1044
|
-
obs_output_t* output = buffering ? buffer_output : file_output;
|
|
1045
1083
|
bool is_active = obs_output_active(output);
|
|
1046
1084
|
|
|
1047
1085
|
if (!is_active) {
|
|
@@ -1058,7 +1096,6 @@ std::string ObsInterface::getLastRecording() {
|
|
|
1058
1096
|
calldata cd;
|
|
1059
1097
|
calldata_init(&cd);
|
|
1060
1098
|
|
|
1061
|
-
obs_output_t* output = buffering ? buffer_output : file_output;
|
|
1062
1099
|
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
|
1063
1100
|
|
|
1064
1101
|
const char* type = obs_output_get_id(output);
|
|
@@ -1089,22 +1126,25 @@ std::string ObsInterface::getLastRecording() {
|
|
|
1089
1126
|
void ObsInterface::addSourceToScene(std::string name) {
|
|
1090
1127
|
blog(LOG_INFO, "ObsInterface::addSourceToScene called for source: %s", name.c_str());
|
|
1091
1128
|
|
|
1129
|
+
obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
|
|
1130
|
+
|
|
1131
|
+
if (item) {
|
|
1132
|
+
blog(LOG_WARNING, "Source %s already in scene", name.c_str());
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1092
1136
|
auto it = sources.find(name);
|
|
1093
1137
|
|
|
1094
1138
|
if (it == sources.end()) {
|
|
1095
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
1096
|
-
|
|
1139
|
+
blog(LOG_WARNING, "Source %s not found when adding to scene", name.c_str());
|
|
1140
|
+
return;
|
|
1097
1141
|
}
|
|
1098
1142
|
|
|
1099
1143
|
obs_source_t* source = it->second;
|
|
1100
|
-
|
|
1101
|
-
// TODO refuse to add twice?
|
|
1102
|
-
obs_sceneitem_t *item = obs_scene_add(scene, source);
|
|
1144
|
+
item = obs_scene_add(scene, source);
|
|
1103
1145
|
|
|
1104
1146
|
if (!item) {
|
|
1105
1147
|
blog(LOG_ERROR, "Failed to add source to scene: %s", name.c_str());
|
|
1106
|
-
obs_source_release(source);
|
|
1107
|
-
throw std::runtime_error("Failed to add source to scene");
|
|
1108
1148
|
}
|
|
1109
1149
|
|
|
1110
1150
|
blog(LOG_INFO, "ObsInterface::addSourceToScene exited");
|
|
@@ -1129,7 +1169,7 @@ void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* s
|
|
|
1129
1169
|
auto it = sources.find(name);
|
|
1130
1170
|
|
|
1131
1171
|
if (it == sources.end()) {
|
|
1132
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
1172
|
+
blog(LOG_WARNING, "Source %s not found when getting source position", name.c_str());
|
|
1133
1173
|
throw std::runtime_error("Source not found!");
|
|
1134
1174
|
}
|
|
1135
1175
|
|
|
@@ -1184,8 +1224,13 @@ std::vector<std::string> ObsInterface::listAvailableVideoEncoders()
|
|
|
1184
1224
|
}
|
|
1185
1225
|
|
|
1186
1226
|
void ObsInterface::setVideoEncoder(std::string id, obs_data_t* settings) {
|
|
1187
|
-
|
|
1227
|
+
if (obs_output_active(output)) {
|
|
1228
|
+
blog(LOG_WARNING, "Cannot change video encoder while output is active");
|
|
1229
|
+
throw new std::runtime_error("Output is active when trying to change encoder");
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1188
1232
|
video_encoder_id = id;
|
|
1233
|
+
obs_data_release(video_encoder_settings);
|
|
1189
1234
|
video_encoder_settings = settings;
|
|
1190
1235
|
create_video_encoders();
|
|
1191
1236
|
}
|
|
@@ -1197,7 +1242,7 @@ void ObsInterface::setMuteAudioInputs(bool mute) {
|
|
|
1197
1242
|
obs_source_t* source = kv.second;
|
|
1198
1243
|
|
|
1199
1244
|
if (!source) {
|
|
1200
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
1245
|
+
blog(LOG_WARNING, "Source %s not found when muting audio inputs", name.c_str());
|
|
1201
1246
|
continue;
|
|
1202
1247
|
}
|
|
1203
1248
|
|
|
@@ -1209,70 +1254,132 @@ void ObsInterface::setMuteAudioInputs(bool mute) {
|
|
|
1209
1254
|
}
|
|
1210
1255
|
}
|
|
1211
1256
|
|
|
1212
|
-
void ObsInterface::
|
|
1213
|
-
blog(LOG_INFO, "Setting
|
|
1214
|
-
output_volume = volume;
|
|
1257
|
+
void ObsInterface::setSourceVolume(std::string name, float volume) {
|
|
1258
|
+
blog(LOG_INFO, "Setting source %s volume to %f", name.c_str(), volume);
|
|
1215
1259
|
|
|
1216
|
-
|
|
1217
|
-
const std::string& name = kv.first;
|
|
1218
|
-
obs_source_t* source = kv.second;
|
|
1260
|
+
auto it = sources.find(name);
|
|
1219
1261
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1262
|
+
if (it == sources.end()) {
|
|
1263
|
+
blog(LOG_WARNING, "Source %s not found when setting volume", name.c_str());
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1224
1266
|
|
|
1225
|
-
|
|
1267
|
+
obs_source_t* source = it->second;
|
|
1268
|
+
const char* type = obs_source_get_id(source);
|
|
1269
|
+
|
|
1270
|
+
bool audio =
|
|
1271
|
+
strcmp(type, AUDIO_OUTPUT) == 0 ||
|
|
1272
|
+
strcmp(type, AUDIO_INPUT) == 0 ||
|
|
1273
|
+
strcmp(type, AUDIO_PROCESS) == 0;
|
|
1226
1274
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1275
|
+
if (!audio) {
|
|
1276
|
+
blog(LOG_WARNING, "Source %s is not a valid audio source", name.c_str());
|
|
1277
|
+
return;
|
|
1230
1278
|
}
|
|
1279
|
+
|
|
1280
|
+
obs_source_set_volume(source, volume);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
void ObsInterface::setVolmeterEnabled(bool enabled) {
|
|
1284
|
+
blog(LOG_INFO, "Setting volmeter enabled: %d", enabled);
|
|
1285
|
+
volmeter_enabled = enabled;
|
|
1231
1286
|
}
|
|
1232
1287
|
|
|
1233
|
-
void ObsInterface::
|
|
1234
|
-
blog(LOG_INFO, "
|
|
1235
|
-
|
|
1288
|
+
void ObsInterface::setForceMono(bool enabled) {
|
|
1289
|
+
blog(LOG_INFO, "%s force mono on all input sources", enabled ? "Enabling" : "Disabling");
|
|
1290
|
+
force_mono = enabled;
|
|
1236
1291
|
|
|
1292
|
+
// Loop over existing sources and update the force mono flags.
|
|
1237
1293
|
for (const auto& kv : sources) {
|
|
1238
1294
|
const std::string& name = kv.first;
|
|
1239
1295
|
obs_source_t* source = kv.second;
|
|
1240
1296
|
|
|
1241
1297
|
if (!source) {
|
|
1242
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
1298
|
+
blog(LOG_WARNING, "Source %s not found when setting force mono", name.c_str());
|
|
1243
1299
|
continue;
|
|
1244
1300
|
}
|
|
1245
1301
|
|
|
1246
1302
|
const char* type = obs_source_get_id(source);
|
|
1247
1303
|
|
|
1248
|
-
if (strcmp(type, AUDIO_INPUT)
|
|
1249
|
-
|
|
1304
|
+
if (strcmp(type, AUDIO_INPUT) != 0) {
|
|
1305
|
+
// Force mono is only applicable to microphones, skip other types.
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
if (enabled) {
|
|
1310
|
+
blog(LOG_INFO, "Setting force mono flag on source %s", name.c_str());
|
|
1311
|
+
uint32_t flags = obs_source_get_flags(source);
|
|
1312
|
+
obs_source_set_flags(source, flags | OBS_SOURCE_FLAG_FORCE_MONO);
|
|
1313
|
+
} else {
|
|
1314
|
+
blog(LOG_INFO, "Unsetting force mono flag on source %s", name.c_str());
|
|
1315
|
+
uint32_t flags = obs_source_get_flags(source);
|
|
1316
|
+
obs_source_set_flags(source, flags & ~OBS_SOURCE_FLAG_FORCE_MONO);
|
|
1250
1317
|
}
|
|
1251
1318
|
}
|
|
1252
1319
|
}
|
|
1253
1320
|
|
|
1254
|
-
void ObsInterface::
|
|
1255
|
-
blog(LOG_INFO, "
|
|
1256
|
-
|
|
1321
|
+
void ObsInterface::setAudioSuppression(bool enabled) {
|
|
1322
|
+
blog(LOG_INFO, "%s audio suppression on all input devices", enabled ? "Enabling" : "Disabling");
|
|
1323
|
+
audio_suppression = enabled;
|
|
1257
1324
|
|
|
1325
|
+
// Loop over existing sources and add filters to any that need it.
|
|
1258
1326
|
for (const auto& kv : sources) {
|
|
1259
1327
|
const std::string& name = kv.first;
|
|
1260
1328
|
obs_source_t* source = kv.second;
|
|
1261
1329
|
|
|
1262
1330
|
if (!source) {
|
|
1263
|
-
blog(LOG_WARNING, "Source %s not found", name.c_str());
|
|
1331
|
+
blog(LOG_WARNING, "Source %s not found when adding filters", name.c_str());
|
|
1264
1332
|
continue;
|
|
1265
1333
|
}
|
|
1266
1334
|
|
|
1267
1335
|
const char* type = obs_source_get_id(source);
|
|
1268
1336
|
|
|
1269
|
-
if (strcmp(type,
|
|
1270
|
-
|
|
1337
|
+
if (strcmp(type, AUDIO_INPUT) != 0) {
|
|
1338
|
+
// Don't care about non-input sources. This is purely for suppressing
|
|
1339
|
+
// microphone background noise.
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// Check for a filter existing and add or remove it as appropriate.
|
|
1344
|
+
auto filter_it = filters.find(name);
|
|
1345
|
+
|
|
1346
|
+
if (audio_suppression && filter_it == filters.end()) {
|
|
1347
|
+
blog(LOG_INFO, "Setting up filter for source: %s", name.c_str());
|
|
1348
|
+
|
|
1349
|
+
std::string filter_name = "Filter for " + name;
|
|
1350
|
+
|
|
1351
|
+
obs_source_t *filter = obs_source_create(
|
|
1352
|
+
"noise_suppress_filter_v2",
|
|
1353
|
+
filter_name.c_str(),
|
|
1354
|
+
nullptr, // Defaults are sensible.
|
|
1355
|
+
nullptr
|
|
1356
|
+
);
|
|
1357
|
+
|
|
1358
|
+
if (!filter) {
|
|
1359
|
+
blog(LOG_ERROR, "Failed to create filter for source: %s", name.c_str());
|
|
1360
|
+
throw std::runtime_error("Failed to create filter!");
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
filters[name] = filter;
|
|
1364
|
+
obs_source_filter_add(source, filter);
|
|
1365
|
+
} else if (!audio_suppression && filter_it != filters.end()) {
|
|
1366
|
+
blog(LOG_INFO, "Removing filters for source: %s", name.c_str());
|
|
1367
|
+
obs_source_t* filter = filter_it->second;
|
|
1368
|
+
obs_source_filter_remove(source, filter);
|
|
1369
|
+
filters.erase(name);
|
|
1370
|
+
obs_source_release(filter);
|
|
1271
1371
|
}
|
|
1272
1372
|
}
|
|
1273
1373
|
}
|
|
1274
1374
|
|
|
1275
|
-
void ObsInterface::
|
|
1276
|
-
blog(LOG_INFO, "
|
|
1277
|
-
|
|
1278
|
-
|
|
1375
|
+
void ObsInterface::sourceCallback(std::string name) {
|
|
1376
|
+
blog(LOG_INFO, "Source callback triggered for %s", name.c_str());
|
|
1377
|
+
SignalData* sd = new SignalData{ "source", name.c_str(), 0 };
|
|
1378
|
+
jscb.NonBlockingCall(sd, call_jscb);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
void ObsInterface::zeroVolmeter(std::string name) {
|
|
1382
|
+
blog(LOG_INFO, "Zeroing volmeter for %s", name.c_str());
|
|
1383
|
+
SignalData* sd = new SignalData{ "volmeter", name.c_str(), 0, 0 };
|
|
1384
|
+
jscb.NonBlockingCall(sd, call_jscb);
|
|
1385
|
+
}
|