Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e5f0dbf
Add check for Metal in render function
PatTheMav Jun 20, 2025
0e38358
Fix stack smash crashes on Linux
hoshinolina Jul 26, 2025
a9848f6
Remove support for CEF 3770 and older
RytoEX Aug 23, 2025
0cc2b21
Remove support for CEF versions older than 4103
RytoEX Aug 23, 2025
e1f1cb7
Remove support for CEF versions older than 4183
RytoEX Aug 23, 2025
d1368fb
Remove support for CEF versions older than 4430
RytoEX Aug 23, 2025
93e3d1e
Remove ENABLE_WASHIDDEN
RytoEX Aug 23, 2025
963e2eb
Remove support for CEF versions older than 4472
RytoEX Aug 23, 2025
78008fc
Remove support for CEF versions older than 4638
RytoEX Aug 23, 2025
8fe72cc
Remove support for CEF versions as old as 4638
RytoEX Aug 23, 2025
0dde9f9
Use v2 of obs_properties_add_button
sebastian-s-beckmann Aug 22, 2025
53d9a09
Update clang-format to 19.1.1
sebastian-s-beckmann Aug 23, 2025
5306c61
build-aux: Update run-format script to current obs-studio state
sebastian-s-beckmann Aug 23, 2025
c3b1e81
Update version to 2.26.0
RytoEX Aug 23, 2025
da76ac8
Update translations from Crowdin
WizardCM Sep 6, 2025
37d847f
Update version to 2.26.1
RytoEX Sep 17, 2025
2bf7e77
Restore source visibility code
tytan652 Sep 25, 2025
4056a31
Update version to 2.26.2
RytoEX Sep 25, 2025
209a914
panel: Update browser shutdown code to ensure proper sequence of events
PatTheMav Oct 9, 2025
a776dd6
Update version to 2.26.3
PatTheMav Oct 17, 2025
a710c96
Update translations from Crowdin
WizardCM Jan 9, 2026
f5f64b1
Update version to 2.26.4
RytoEX Jan 9, 2026
8a45650
Update local file scheme handler
Warchamp7 Jan 21, 2026
df0330f
Update version to 2.26.5
RytoEX Jan 23, 2026
1738605
Fix cmake includes on Linux and macOS
Warchamp7 Jan 23, 2026
8725f07
Update version to 2.26.6
RytoEX Jan 24, 2026
f93477b
Fix local filepath on POSIX
Warchamp7 Jan 27, 2026
b59127a
Update version to 2.26.7
RytoEX Feb 4, 2026
cda4f1f
Revert custom scheme handler protocol
Warchamp7 Feb 12, 2026
ea04212
Update version to 2.26.8
RytoEX Feb 13, 2026
8a3b5e8
Merge upstream obs-browser 2.26.8 into obs_merge_32.1.1
aleksandr-voitenko Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ PenaltyReturnTypeOnItsOwnLine: 60

PointerAlignment: Right
ReflowComments: false
SkipMacroDefinitionBody: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
Expand Down
8 changes: 4 additions & 4 deletions .github/actions/run-clang-format/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ runs:
echo ::group::Install Dependencies
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH
echo "/home/linuxbrew/.linuxbrew/opt/clang-format@17/bin" >> $GITHUB_PATH
echo "/home/linuxbrew/.linuxbrew/opt/clang-format@19/bin" >> $GITHUB_PATH
brew install --quiet zsh
echo ::endgroup::

Expand All @@ -50,11 +50,11 @@ runs:
: Run clang-format 🐉
if (( ${+RUNNER_DEBUG} )) setopt XTRACE

print ::group::Install clang-format-17
brew install --quiet obsproject/tools/clang-format@17
print ::group::Install clang-format-19
brew install --quiet obsproject/tools/clang-format@19
print ::endgroup::

print ::group::Run clang-format-17
print ::group::Run clang-format-19
local -a changes=(${(s:,:)CHANGED_FILES//[\[\]\'\"]/})
./build-aux/run-clang-format --fail-${{ inputs.failCondition }} --check ${changes}
print ::endgroup::
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ target_sources(
cef-headers.hpp
deps/base64/base64.cpp
deps/base64/base64.hpp
deps/ip-string.hpp
deps/signal-restore.cpp
deps/signal-restore.hpp
deps/wide-string.cpp
deps/wide-string.hpp
obs-browser-plugin.cpp
obs-browser-source-audio.cpp
obs-browser-source.cpp
obs-browser-source.hpp)

Expand Down
86 changes: 0 additions & 86 deletions browser-app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,7 @@ void BrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFr
obsStudioObj->SetValue(name, func, V8_PROPERTY_ATTRIBUTE_NONE);
}

#if !ENABLE_WASHIDDEN
int id = browser->GetIdentifier();
if (browserVis.find(id) != browserVis.end()) {
SetDocumentVisibility(browser, browserVis[id]);
}
#else
UNUSED_PARAMETER(browser);
#endif
}

void BrowserApp::ExecuteJSFunction(CefRefPtr<CefBrowser> browser, const char *functionName, CefV8ValueList arguments)
Expand Down Expand Up @@ -207,81 +200,6 @@ void BrowserApp::ExecuteJSFunction(CefRefPtr<CefBrowser> browser, const char *fu
}
}

#if !ENABLE_WASHIDDEN
void BrowserApp::SetFrameDocumentVisibility(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, bool isVisible)
{
UNUSED_PARAMETER(browser);

CefRefPtr<CefV8Context> context = frame->GetV8Context();

context->Enter();

CefRefPtr<CefV8Value> globalObj = context->GetGlobal();

CefRefPtr<CefV8Value> documentObject = globalObj->GetValue("document");

if (!!documentObject) {
documentObject->SetValue("hidden", CefV8Value::CreateBool(!isVisible), V8_PROPERTY_ATTRIBUTE_READONLY);

documentObject->SetValue("visibilityState", CefV8Value::CreateString(isVisible ? "visible" : "hidden"),
V8_PROPERTY_ATTRIBUTE_READONLY);

std::string script = "new CustomEvent('visibilitychange', {});";

CefRefPtr<CefV8Value> returnValue;
CefRefPtr<CefV8Exception> exception;

/* Create the CustomEvent object
* We have to use eval to invoke the new operator */
bool success = context->Eval(script, frame->GetURL(), 0, returnValue, exception);

if (success) {
CefV8ValueList arguments;
arguments.push_back(returnValue);

CefRefPtr<CefV8Value> dispatchEvent = documentObject->GetValue("dispatchEvent");

/* Dispatch visibilitychange event on the document
* object */
dispatchEvent->ExecuteFunction(documentObject, arguments);
}
}

context->Exit();
}

void BrowserApp::SetDocumentVisibility(CefRefPtr<CefBrowser> browser, bool isVisible)
{
/* This method might be called before OnContextCreated
* call is made. We'll save the requested visibility
* state here, and use it later in OnContextCreated to
* set initial page visibility state. */
browserVis[browser->GetIdentifier()] = isVisible;

std::vector<int64> frameIdentifiers;
/* Set visibility state for every frame in the browser
*
* According to the Page Visibility API documentation:
* https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
*
* "Visibility states of an <iframe> are the same as
* the parent document. Hiding an <iframe> using CSS
* properties (such as display: none;) doesn't trigger
* visibility events or change the state of the document
* contained within the frame."
*
* Thus, we set the same visibility state for every frame of the browser.
*/
browser->GetFrameIdentifiers(frameIdentifiers);

for (int64 frameId : frameIdentifiers) {
CefRefPtr<CefFrame> frame = browser->GetFrame(frameId);

SetFrameDocumentVisibility(browser, frame, isVisible);
}
}
#endif

CefRefPtr<CefV8Value> CefValueToCefV8Value(CefRefPtr<CefValue> value)
{
CefRefPtr<CefV8Value> result;
Expand Down Expand Up @@ -348,10 +266,6 @@ bool BrowserApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefP

ExecuteJSFunction(browser, "onVisibilityChange", arguments);

#if !ENABLE_WASHIDDEN
SetDocumentVisibility(browser, args->GetBool(0));
#endif

} else if (message->GetName() == "Active") {
CefV8ValueList arguments;
arguments.push_back(CefV8Value::CreateBool(args->GetBool(0)));
Expand Down
7 changes: 0 additions & 7 deletions browser-app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,5 @@ class BrowserApp : public CefApp, public CefRenderProcessHandler, public CefBrow
QTimer frameTimer;
#endif

#if !ENABLE_WASHIDDEN
std::unordered_map<int, bool> browserVis;

void SetFrameDocumentVisibility(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, bool isVisible);
void SetDocumentVisibility(CefRefPtr<CefBrowser> browser, bool isVisible);
#endif

IMPLEMENT_REFCOUNTING(BrowserApp);
};
77 changes: 0 additions & 77 deletions browser-client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ CefRefPtr<CefAudioHandler> BrowserClient::GetAudioHandler()
return reroute_audio ? this : nullptr;
}

#if CHROME_VERSION_BUILD >= 4638
CefRefPtr<CefRequestHandler> BrowserClient::GetRequestHandler()
{
return this;
Expand Down Expand Up @@ -117,7 +116,6 @@ CefResourceRequestHandler::ReturnValue BrowserClient::OnBeforeResourceLoad(CefRe
{
return RV_CONTINUE;
}
#endif

bool BrowserClient::OnBeforePopup(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>,
#if CHROME_VERSION_BUILD >= 6834
Expand Down Expand Up @@ -568,7 +566,6 @@ static speaker_layout GetSpeakerLayout(CefAudioHandler::ChannelLayout cefLayout)
}
}

#if CHROME_VERSION_BUILD >= 4103
void BrowserClient::OnAudioStreamStarted(CefRefPtr<CefBrowser> browser, const CefAudioParameters &params_,
int channels_)
{
Expand Down Expand Up @@ -641,80 +638,6 @@ bool BrowserClient::GetAudioParameters(CefRefPtr<CefBrowser> browser, CefAudioPa
params.frames_per_buffer = kFramesPerBuffer;
return true;
}
#elif CHROME_VERSION_BUILD < 4103
void BrowserClient::OnAudioStreamStarted(CefRefPtr<CefBrowser> browser, int id, int, ChannelLayout channel_layout,
int sample_rate, int)
{
UNUSED_PARAMETER(browser);
if (!valid()) {
return;
}

AudioStream &stream = bs->audio_streams[id];
if (!stream.source) {
stream.source = obs_source_create_private("audio_line", nullptr, nullptr);

obs_source_add_active_child(bs->source, stream.source);

std::lock_guard<std::mutex> lock(bs->audio_sources_mutex);
bs->audio_sources.push_back(stream.source);
}

stream.speakers = GetSpeakerLayout(channel_layout);
stream.channels = get_audio_channels(stream.speakers);
stream.sample_rate = sample_rate;
}

void BrowserClient::OnAudioStreamPacket(CefRefPtr<CefBrowser> browser, int id, const float **data, int frames,
int64_t pts)
{
UNUSED_PARAMETER(browser);
if (!valid()) {
return;
}

AudioStream &stream = bs->audio_streams[id];
struct obs_source_audio audio = {};

const uint8_t **pcm = (const uint8_t **)data;
for (int i = 0; i < stream.channels; i++)
audio.data[i] = pcm[i];

audio.samples_per_sec = stream.sample_rate;
audio.frames = frames;
audio.format = AUDIO_FORMAT_FLOAT_PLANAR;
audio.speakers = stream.speakers;
audio.timestamp = (uint64_t)pts * 1000000LLU;

obs_source_output_audio(stream.source, &audio);
}

void BrowserClient::OnAudioStreamStopped(CefRefPtr<CefBrowser> browser, int id)
{
UNUSED_PARAMETER(browser);
if (!valid()) {
return;
}

auto pair = bs->audio_streams.find(id);
if (pair == bs->audio_streams.end()) {
return;
}

AudioStream &stream = pair->second;
{
std::lock_guard<std::mutex> lock(bs->audio_sources_mutex);
for (size_t i = 0; i < bs->audio_sources.size(); i++) {
obs_source_t *source = bs->audio_sources[i];
if (source == stream.source) {
bs->audio_sources.erase(bs->audio_sources.begin() + i);
break;
}
}
}
bs->audio_streams.erase(pair);
}
#endif

void BrowserClient::OnLoadEnd(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame> frame, int)
{
Expand Down
21 changes: 3 additions & 18 deletions browser-client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ class BrowserClient : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefRequestHandler,
#if CHROME_VERSION_BUILD >= 4638
public CefResourceRequestHandler,
#endif
public CefContextMenuHandler,
public CefRenderHandler,
public CefAudioHandler,
Expand All @@ -50,12 +48,11 @@ class BrowserClient : public CefClient,
CefRect popupRect;
CefRect originalPopupRect;

#if CHROME_VERSION_BUILD >= 4103
int sample_rate;
int channels;
ChannelLayout channel_layout;
int frames_per_buffer;
#endif

inline BrowserClient(BrowserSource *bs_, bool sharing_avail, bool reroute_audio_,
ControlLevel webpage_control_level_)
: sharing_available(sharing_avail),
Expand All @@ -70,9 +67,7 @@ class BrowserClient : public CefClient,
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() override;
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override;
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override;
#if CHROME_VERSION_BUILD >= 4638
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override;
#endif
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override;
virtual CefRefPtr<CefAudioHandler> GetAudioHandler() override;

Expand All @@ -95,7 +90,7 @@ class BrowserClient : public CefClient,
const CefPopupFeatures &popupFeatures, CefWindowInfo &windowInfo,
CefRefPtr<CefClient> &client, CefBrowserSettings &settings,
CefRefPtr<CefDictionaryValue> &extra_info, bool *no_javascript_access) override;
#if CHROME_VERSION_BUILD >= 4638

/* CefRequestHandler */
virtual CefRefPtr<CefResourceRequestHandler>
GetResourceRequestHandler(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
Expand All @@ -113,7 +108,6 @@ class BrowserClient : public CefClient,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override;
#endif

/* CefContextMenuHandler */
virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
Expand All @@ -137,7 +131,7 @@ class BrowserClient : public CefClient,
const RectList &dirtyRects, void *shared_handle, bool new_texture) override;
#endif
#endif
#if CHROME_VERSION_BUILD >= 4103

virtual void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser, const float **data, int frames,
int64_t pts) override;

Expand All @@ -148,16 +142,7 @@ class BrowserClient : public CefClient,
virtual void OnAudioStreamError(CefRefPtr<CefBrowser> browser, const CefString &message) override;
const int kFramesPerBuffer = 1024;
virtual bool GetAudioParameters(CefRefPtr<CefBrowser> browser, CefAudioParameters &params) override;
#else
virtual void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser, int audio_stream_id, const float **data,
int frames, int64_t pts) override;

virtual void OnAudioStreamStopped(CefRefPtr<CefBrowser> browser, int audio_stream_id);

virtual void OnAudioStreamStarted(CefRefPtr<CefBrowser> browser, int audio_stream_id, int channels,
ChannelLayout channel_layout, int sample_rate,
int frames_per_buffer) override;
#endif
/* CefLoadHandler */
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) override;

Expand Down
Loading