Projects
Multimedia
obs-studio
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 132
View file
obs-studio.changes
Changed
@@ -1,4 +1,19 @@ ------------------------------------------------------------------- +Sun Dec 14 00:33:25 UTC 2025 - darix <packman@nordisch.org> + +- Update to version 32.0.4: + * libobs: Update version to 32.0.4 + * docs: Add API disclaimer to canvases + * libobs: Fix default macOS monitoring device + * linux-pulseaudio: Add monitoring deduplication calls + * mac-capture: Add monitoring deduplication calls + * win-wasapi: Add monitoring deduplication calls + * libobs: Improve monitoring deduplication + * frontend: Fix transition duration not loading correctly + * frontend: Switch off deleted scenes immediately + * libobs: Do not wait for audio of removed sources + +------------------------------------------------------------------- Fri Dec 05 23:39:04 UTC 2025 - darix <packman@nordisch.org> - Update to version 32.0.3:
View file
obs-studio.spec
Changed
@@ -39,7 +39,7 @@ %endif Name: obs-studio -Version: 32.0.3 +Version: 32.0.4 Release: 0 Summary: A recording/broadcasting program Group: Productivity/Multimedia/Video/Editors and Convertors
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="manual"> <param name="versionformat">@PARENT_TAG@</param> - <param name="revision">32.0.3</param> + <param name="revision">32.0.4</param> <param name="url">https://github.com/obsproject/obs-studio.git</param> <param name="versionrewrite-pattern">(\.\d+)-(a-z.*)</param> <param name="versionrewrite-replacement">\1~\2</param>
View file
_servicedata
Changed
@@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/obsproject/obs-studio.git</param> - <param name="changesrevision">9a8470355ffcd38a797f06dca70cfcc8f7c89100</param> + <param name="changesrevision">dcdbd2e9048ae66237fdab32dbba72b745b1b9c5</param> </service> </servicedata> \ No newline at end of file
View file
obs-studio-32.0.3.tar.xz/docs/sphinx/reference-canvases.rst -> obs-studio-32.0.4.tar.xz/docs/sphinx/reference-canvases.rst
Changed
@@ -1,6 +1,16 @@ Canvas API Reference (obs_canvas_t) =================================== +.. danger:: + + Canvases are still in their early stages of implementation and the API will evolve as they are gradually integrated + across OBS Studio. + + The Canvas API should be considered **unstable** and may be changed without warning. This documentation serves to aid + in their iterative development within OBS Studio. + + **If you are developing a plugin that utilizes canvases, proceed with great caution.** + Canvases are reference-counted objects that contain scenes and define how those are rendered. They provide a video object which can be used with encoders or raw outputs.
View file
obs-studio-32.0.3.tar.xz/frontend/widgets/OBSBasic_SceneCollections.cpp -> obs-studio-32.0.4.tar.xz/frontend/widgets/OBSBasic_SceneCollections.cpp
Changed
@@ -1003,7 +1003,7 @@ ClearSceneData(); InitDefaultTransitions(); CreateDefaultQuickTransitions(); - transitionDuration = 300; + SetTransitionDuration(300); SetTransition(fadeTransition); updateRemigrationMenuItem(SceneCoordinateMode::Relative, ui->actionRemigrateSceneCollection); @@ -1303,7 +1303,7 @@ if (!curTransition) curTransition = fadeTransition; - transitionDuration = newDuration; + SetTransitionDuration(newDuration); SetTransition(curTransition); retryScene:
View file
obs-studio-32.0.3.tar.xz/frontend/widgets/OBSBasic_Scenes.cpp -> obs-studio-32.0.4.tar.xz/frontend/widgets/OBSBasic_Scenes.cpp
Changed
@@ -492,16 +492,21 @@ { OBSSource source; + bool forceSceneChange = false; + if (current) { OBSScene scene = GetOBSRef<OBSScene>(current); source = obs_scene_get_source(scene); + bool oldSceneIsRemoved = obs_source_removed(obs_scene_get_source(currentScene)); + forceSceneChange = oldSceneIsRemoved; + currentScene = scene; } else { currentScene = NULL; } - SetCurrentScene(source); + SetCurrentScene(source, forceSceneChange); if (vcamEnabled && vcamConfig.type == VCamOutputType::PreviewOutput) outputHandler->UpdateVirtualCamOutputSource();
View file
obs-studio-32.0.3.tar.xz/libobs/audio-monitoring/osx/coreaudio-enum-devices.c -> obs-studio-32.0.4.tar.xz/libobs/audio-monitoring/osx/coreaudio-enum-devices.c
Changed
@@ -106,8 +106,8 @@ static void get_default_id(char **p_id) { - AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultSystemOutputDevice, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMain}; if (*p_id) return;
View file
obs-studio-32.0.3.tar.xz/libobs/obs-audio.c -> obs-studio-32.0.4.tar.xz/libobs/obs-audio.c
Changed
@@ -48,54 +48,6 @@ !(source->info.output_flags & OBS_SOURCE_COMPOSITE); } -extern bool devices_match(const char *id1, const char *id2); - -static inline void check_audio_output_source_is_monitoring_device(obs_source_t *s, void *p) -{ - struct obs_core_audio *audio = p; - if (!audio->monitoring_device_name) - return; - - const char *id = s->info.id; - if (strcmp(id, "wasapi_output_capture") != 0 && strcmp(id, "pulse_output_capture") != 0 && - strcmp(id, "coreaudio_output_capture") != 0) - return; - - obs_data_t *settings = obs_source_get_settings(s); - if (!settings) - return; - - const char *device_id = obs_data_get_string(settings, "device_id"); - const char *mon_id = audio->monitoring_device_id; - bool id_match = false; - -#ifdef __APPLE__ - extern void get_desktop_default_id(char **p_id); - if (device_id && strcmp(device_id, "default") == 0) { - char *def_id = NULL; - get_desktop_default_id(&def_id); - id_match = devices_match(def_id, mon_id); - if (def_id) - bfree(def_id); - } else { - id_match = devices_match(device_id, mon_id); - } -#else - id_match = devices_match(device_id, mon_id); -#endif - - if (id_match) { - audio->prevent_monitoring_duplication = true; - audio->monitoring_duplicating_source = s; - if (!audio->monitoring_duplication_prevented_on_prev_tick) - blog(LOG_INFO, "Device for 'Audio Output Capture' source is also used for audio" - " monitoring:\nDeduplication logic is being applied to all monitored" - " sources.\n"); - } - - obs_data_release(settings); -} - /* * This version of push_audio_tree checks whether any source is an Audio Output Capture source ('Desktop Audio', * 'wasapi_output_capture' on Windows, 'pulse_output_capture' on Linux, 'coreaudio_output_capture' on macOS), & if the @@ -118,7 +70,6 @@ if (s) { da_push_back(audio->render_order, &s); s->audio_is_duplicated = false; - check_audio_output_source_is_monitoring_device(s, audio); } } else { /* Source already present in tree → mark as duplicated if applicable */ @@ -558,23 +509,18 @@ /* In case monitoring and an 'Audio Output Capture' source have the same device, one silences all the monitored * sources unless the 'Audio Output Capture' is muted. - * The syncing between the mute state of the 'Audio Output Capture' source set in UI and libobs is a bit tricky. There - * is an intrinsic positive delay of the 'Audio Output Capture' source with respect to monitored sources due to the - * audio OS processing (wasapi, pulseaudio or coreaudio). Unfortunately, the delay is machine dependent and we can only - * mitigate its effects. During tests, src->user_muted worked better than src->muted, maybe because it is set earlier - * than the muted flag which allows to keep a better sync. With src->muted, unmuting the 'Audio Output Capture' led to - * a systematic level increase during one tick during testing for a sine tone (about +3 dBFS). In general we - * don't expect much difference though between user_muted and muted. */ static inline bool should_silence_monitored_source(obs_source_t *source, struct obs_core_audio *audio) { - if (!audio->monitoring_duplicating_source) + obs_source_t *dup_src = audio->monitoring_duplicating_source; + + if (!dup_src || !obs_source_active(dup_src)) return false; bool fader_muted = close_float(audio->monitoring_duplicating_source->volume, 0.0f, 0.0001f); - bool output_capture_unmuted = !audio->monitoring_duplicating_source->user_muted && !fader_muted; + bool output_capture_unmuted = !audio->monitoring_duplicating_source->muted && !fader_muted; - if (audio->prevent_monitoring_duplication && output_capture_unmuted) { + if (output_capture_unmuted) { if (source->monitoring_type == OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT && source != audio->monitoring_duplicating_source) { return true; @@ -617,9 +563,6 @@ da_resize(audio->render_order, 0); da_resize(audio->root_nodes, 0); - audio->monitoring_duplication_prevented_on_prev_tick = audio->prevent_monitoring_duplication; - audio->prevent_monitoring_duplication = false; - audio->monitoring_duplicating_source = NULL; deque_push_back(&audio->buffered_timestamps, &ts, sizeof(ts)); deque_peek_front(&audio->buffered_timestamps, &ts, sizeof(ts)); @@ -656,14 +599,11 @@ if (obs->video.mixes.arrayj->mix_audio) da_push_back(audio->root_nodes, &source); - /* Build audio tree, track Audio Output Capture sources and tag duplicate individual sources */ + /* Build audio tree, tag duplicate individual sources */ obs_source_enum_active_tree(source, push_audio_tree2, audio); /* add top - level sources to audio tree */ push_audio_tree(NULL, source, audio); - - /* Check whether the source is an 'Audio Output Capture' and coincides with monitoring device */ - check_audio_output_source_is_monitoring_device(source, audio); } pthread_mutex_unlock(&view->channels_mutex); }
View file
obs-studio-32.0.3.tar.xz/libobs/obs-config.h -> obs-studio-32.0.4.tar.xz/libobs/obs-config.h
Changed
@@ -41,7 +41,7 @@ * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 3 +#define LIBOBS_API_PATCH_VER 4 #define MAKE_SEMANTIC_VERSION(major, minor, patch) ((major << 24) | (minor << 16) | patch)
View file
obs-studio-32.0.3.tar.xz/libobs/obs-internal.h -> obs-studio-32.0.4.tar.xz/libobs/obs-internal.h
Changed
@@ -460,9 +460,7 @@ pthread_mutex_t task_mutex; struct deque tasks; - volatile bool prevent_monitoring_duplication; struct obs_source *monitoring_duplicating_source; - bool monitoring_duplication_prevented_on_prev_tick; }; /* user sources, output channels, and displays */
View file
obs-studio-32.0.3.tar.xz/libobs/obs-source-transition.c -> obs-studio-32.0.4.tar.xz/libobs/obs-source-transition.c
Changed
@@ -928,6 +928,12 @@ sources0 = transition->transition_sources0; sources1 = transition->transition_sources1; + if (sources0 && obs_source_removed(sources0)) + sources0 = NULL; + + if (sources1 && obs_source_removed(sources1)) + sources1 = NULL; + min_ts = calc_min_ts(sources); if (min_ts) {
View file
obs-studio-32.0.3.tar.xz/libobs/obs-source.c -> obs-studio-32.0.4.tar.xz/libobs/obs-source.c
Changed
@@ -368,6 +368,71 @@ obs_source_hotkey_push_to_talk, source); } +void obs_source_audio_output_capture_device_activated(void *vptr, calldata_t *cd) +{ + UNUSED_PARAMETER(vptr); + obs_source_t *src = calldata_ptr(cd, "source"); + if (!src) + return; + + obs_data_t *settings = obs_source_get_settings(src); + const char *device_id = obs_data_get_string(settings, "device_id"); + obs_source_audio_output_capture_device_changed(src, device_id); + obs_data_release(settings); +} + +extern bool devices_match(const char *id1, const char *id2); +void obs_source_audio_output_capture_device_changed(obs_source_t *src, const char *device_id) +{ + struct obs_core_audio *audio = &obs->audio; + + if (!audio->monitoring_device_name) + return; + + if (!(src->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR)) + return; + + const char *mon_id = audio->monitoring_device_id; + bool id_match = false; + +#ifdef __APPLE__ + extern void get_desktop_default_id(char **p_id); + if (device_id && strcmp(device_id, "default") == 0) { + char *def_id = NULL; + get_desktop_default_id(&def_id); + id_match = devices_match(def_id, mon_id); + if (def_id) + bfree(def_id); + } else { + id_match = devices_match(device_id, mon_id); + } +#else + id_match = devices_match(device_id, mon_id); +#endif + struct calldata cd; + uint8_t stack128; + calldata_init_fixed(&cd, stack, sizeof(stack)); + + if (id_match) { + calldata_set_ptr(&cd, "source", src); + signal_handler_signal(obs->signals, "deduplication_changed", &cd); + signal_handler_connect(src->context.signals, "activate", + obs_source_audio_output_capture_device_activated, NULL); + blog(LOG_INFO, + "Device for 'Audio Output Capture' source %s is also used for audio monitoring." + "\nDeduplication logic is being applied to all monitored sources.", + src->context.name); + } else { + if (src == audio->monitoring_duplicating_source) { + calldata_set_ptr(&cd, "source", NULL); + signal_handler_disconnect(src->context.signals, "activate", + obs_source_audio_output_capture_device_activated, NULL); + signal_handler_signal(obs->signals, "deduplication_changed", &cd); + blog(LOG_INFO, "Deduplication logic stopped."); + } + } +} + static obs_source_t *obs_source_create_internal(const char *id, const char *name, const char *uuid, obs_data_t *settings, obs_data_t *hotkey_data, bool private, uint32_t last_obs_ver, obs_canvas_t *canvas) @@ -5420,6 +5485,9 @@ if (!obs_source_valid(source, "obs_source_audio_pending")) return true; + if (obs_source_removed(source)) + return true; + return (is_composite_source(source) || is_audio_source(source)) ? source->audio_pending : true; }
View file
obs-studio-32.0.3.tar.xz/libobs/obs.c -> obs-studio-32.0.4.tar.xz/libobs/obs.c
Changed
@@ -880,6 +880,22 @@ } } +void set_monitoring_duplication_source(void *param) +{ + obs_source_t *src = param; + struct obs_core_audio *audio = &obs->audio; + + audio->monitoring_duplicating_source = src; +} + +static void apply_monitoring_deduplication(void *ignored, calldata_t *cd) +{ + UNUSED_PARAMETER(ignored); + obs_source_t *src = calldata_ptr(cd, "source"); + + obs_queue_task(OBS_TASK_AUDIO, set_monitoring_duplication_source, src, false); +} + static void set_audio_thread(void *unused); static bool obs_init_audio(struct audio_output_info *ai) @@ -899,7 +915,10 @@ audio->monitoring_device_name = bstrdup("Default"); audio->monitoring_device_id = bstrdup("default"); - audio->monitoring_duplication_prevented_on_prev_tick = false; + audio->monitoring_duplicating_source = NULL; + + signal_handler_add(obs->signals, "void deduplication_changed(ptr source)"); + signal_handler_connect(obs->signals, "deduplication_changed", apply_monitoring_deduplication, NULL); errorcode = audio_output_open(&audio->audio, ai); if (errorcode == AUDIO_OUTPUT_SUCCESS) @@ -2947,6 +2966,18 @@ pthread_mutex_unlock(&obs->audio.monitoring_mutex); } +static bool check_all_aoc_sources(void *param, obs_source_t *src) +{ + UNUSED_PARAMETER(param); + if (src->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) { + obs_data_t *settings = obs_source_get_settings(src); + const char *device_id = obs_data_get_string(settings, "device_id"); + obs_source_audio_output_capture_device_changed(src, device_id); + obs_data_release(settings); + } + return true; +} + bool obs_set_audio_monitoring_device(const char *name, const char *id) { if (!name || !id || !*name || !*id) @@ -2967,10 +2998,13 @@ obs->audio.monitoring_device_name = bstrdup(name); obs->audio.monitoring_device_id = bstrdup(id); + pthread_mutex_unlock(&obs->audio.monitoring_mutex); obs_reset_audio_monitoring(); - pthread_mutex_unlock(&obs->audio.monitoring_mutex); + /* Check all Audio Output Capture sources for monitoring duplication. */ + obs_enum_sources(check_all_aoc_sources, NULL); + return true; }
View file
obs-studio-32.0.3.tar.xz/libobs/obs.h -> obs-studio-32.0.4.tar.xz/libobs/obs.h
Changed
@@ -1323,6 +1323,13 @@ EXPORT void obs_source_remove_audio_capture_callback(obs_source_t *source, obs_source_audio_capture_t callback, void *param); +/** + * For an Audio Output Capture source (like 'wasapi_output_capture') used for 'Desktop Audio', this checks whether the + * device is also used for monitoring. A signal to obs core struct is then emitted to trigger deduplication logic at + * the end of an audio tick. + */ +EXPORT void obs_source_audio_output_capture_device_changed(obs_source_t *source, const char *device_id); + typedef void (*obs_source_caption_t)(void *param, obs_source_t *source, const struct obs_source_cea_708 *captions); EXPORT void obs_source_add_caption_callback(obs_source_t *source, obs_source_caption_t callback, void *param);
View file
obs-studio-32.0.3.tar.xz/plugins/linux-pulseaudio/pulse-input.c -> obs-studio-32.0.4.tar.xz/plugins/linux-pulseaudio/pulse-input.c
Changed
@@ -509,6 +509,11 @@ if (data->stream) pulse_stop_recording(data); + + /* If the device is also used for monitoring, a cleanup is needed. */ + if (!data->input) + obs_source_audio_output_capture_device_changed(data->source, NULL); + pulse_unref(); if (data->device) @@ -523,12 +528,15 @@ { PULSE_DATA(vptr); bool restart = false; - const char *new_device; - - new_device = obs_data_get_string(settings, "device_id"); + const char *new_device = obs_data_get_string(settings, "device_id"); if (!data->device || strcmp(data->device, new_device) != 0) { + /* Signal to deduplication logic in case the device is also used for monitoring. */ + if (!data->input) + obs_source_audio_output_capture_device_changed(data->source, new_device); + if (data->device) bfree(data->device); + data->device = bstrdup(new_device); data->is_default = strcmp("default", data->device) == 0; restart = true;
View file
obs-studio-32.0.3.tar.xz/plugins/mac-capture/mac-audio.c -> obs-studio-32.0.4.tar.xz/plugins/mac-capture/mac-audio.c
Changed
@@ -784,6 +784,9 @@ if (ca) { coreaudio_shutdown(ca); + /* If the device is also used for monitoring, a cleanup is needed. */ + if (!ca->input) + obs_source_audio_output_capture_device_changed(ca->source, NULL); os_event_destroy(ca->exit_event); @@ -818,11 +821,15 @@ static void coreaudio_update(void *data, obs_data_t *settings) { struct coreaudio_data *ca = data; + const char *new_id = obs_data_get_string(settings, "device_id"); + + if (!ca->input && strcmp(new_id, ca->device_uid) != 0) + obs_source_audio_output_capture_device_changed(ca->source, new_id); coreaudio_shutdown(ca); bfree(ca->device_uid); - ca->device_uid = bstrdup(obs_data_get_string(settings, "device_id")); + ca->device_uid = bstrdup(new_id); ca->enable_downmix = obs_data_get_bool(settings, "enable_downmix"); @@ -865,6 +872,9 @@ ca->device_uid = bstrdup("default"); coreaudio_try_init(ca); + if (!ca->input) + obs_source_audio_output_capture_device_changed(source, ca->device_uid); + return ca; }
View file
obs-studio-32.0.3.tar.xz/plugins/win-wasapi/win-wasapi.cpp -> obs-studio-32.0.4.tar.xz/plugins/win-wasapi/win-wasapi.cpp
Changed
@@ -464,6 +464,9 @@ if (notify) { notify->RemoveDefaultDeviceChangedCallback(this); } + // If the device is also used for monitoring, a cleanup is needed. + if (sourceType == SourceType::DeviceOutput) + obs_source_audio_output_capture_device_changed(source, NULL); Stop(); } @@ -503,6 +506,10 @@ void WASAPISource::UpdateSettings(UpdateParams &¶ms) { + // Signal to deduplication logic in case the device is also used for monitoring. + if (device_id != params.device_id && sourceType == SourceType::DeviceOutput) + obs_source_audio_output_capture_device_changed(source, params.device_id.c_str()); + device_id = std::move(params.device_id); useDeviceTiming = params.useDeviceTiming; isDefaultDevice = params.isDefaultDevice;
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.