summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authortytan6522023-11-12 01:18:00 +0100
committertytan6522023-11-12 01:18:00 +0100
commit0a8a227566dd9a9d91cbf716766d8b9ccc329173 (patch)
treee37f03d727eb89b283fdada3a351c20561781599
parent7081490079b34bcc7a82ba77d7f190a98975fd9a (diff)
downloadaur-0a8a227566dd9a9d91cbf716766d8b9ccc329173.tar.gz
build: Update to 30.0.0
-rw-r--r--.SRCINFO31
-rw-r--r--0002-Use_system_uthash.patch47
-rw-r--r--PKGBUILD47
-rw-r--r--bind_iface.patch576
-rw-r--r--bind_iface_eyeballed.patch930
5 files changed, 990 insertions, 641 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 8b4fbaa9dc8b..e8e2b6d2b2ff 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,7 +1,7 @@
pkgbase = obs-studio-tytan652
pkgdesc = Free and open source software for video recording and live streaming. With everything except service integrations. Plus V4L2 devices by paths, my bind interface PR, and sometimes backported fixes
- pkgver = 29.1.3
- pkgrel = 6
+ pkgver = 30.0.0
+ pkgrel = 1
url = https://github.com/obsproject/obs-studio
arch = x86_64
arch = aarch64
@@ -12,9 +12,11 @@ pkgbase = obs-studio-tytan652
makedepends = git
makedepends = uthash
makedepends = libajantv2
+ makedepends = libdatachannel-nice>=0.19.2
makedepends = libfdk-aac
makedepends = luajit
makedepends = nlohmann-json
+ makedepends = onevpl
makedepends = python>=3.11
makedepends = sndio
makedepends = swig
@@ -43,6 +45,7 @@ pkgbase = obs-studio-tytan652
depends = libxkbcommon
depends = mbedtls>=3.4
depends = pciutils
+ depends = qrcodegencpp-cmake
depends = qt6-base
depends = qt6-svg
depends = qt6-wayland
@@ -68,9 +71,12 @@ pkgbase = obs-studio-tytan652
depends = nss
optdepends = jack: JACK support
optdepends = libfdk-aac: FDK AAC codec support
- optdepends = intel-media-driver: Hardware encoding (>= Broadwell)
- optdepends = libva-intel-driver: Hardware encoding (<= Haswell)
- optdepends = libva-mesa-driver: Hardware encoding
+ optdepends = onevpl: QSV encoder support
+ optdepends = intel-media-sdk: QSV encoder support(<= Rocket Lake & >= Broadwell)
+ optdepends = onevpl-intel-gpu: QSV encoder support (>= Alder Lake)
+ optdepends = intel-media-driver: VAAPI encoder support (>= Broadwell)
+ optdepends = libva-intel-driver: VAAPI encoder support (<= Haswell)
+ optdepends = libva-mesa-driver: VAAPI encoder support
optdepends = swig: Scripting
optdepends = luajit: Lua scripting
optdepends = python>=3.11: Python scripting
@@ -78,8 +84,9 @@ pkgbase = obs-studio-tytan652
optdepends = v4l-utils: V4L2 support
optdepends = systemd-libs: V4L2 support
optdepends = v4l2loopback-dkms: V4L2 virtual camera output
+ optdepends = libdatachannel>=0.19.2: WHIP Support
optdepends = decklink: Blackmagic Design DeckLink support
- provides = obs-studio=29.1.3
+ provides = obs-studio=30.0.0
provides = obs-vst
provides = obs-websocket
provides = obs-browser
@@ -90,23 +97,19 @@ pkgbase = obs-studio-tytan652
conflicts = obs-linuxbrowser
conflicts = libva-vdpau-driver
options = debug
- source = obs-studio::git+https://github.com/obsproject/obs-studio.git#tag=29.1.3
+ source = obs-studio::git+https://github.com/obsproject/obs-studio.git#tag=30.0.0
source = obs-browser::git+https://github.com/obsproject/obs-browser.git
source = obs-websocket::git+https://github.com/obsproject/obs-websocket.git
- source = qr::git+https://github.com/nayuki/QR-Code-generator.git
- source = bind_iface.patch
+ source = bind_iface_eyeballed.patch
source = v4l2_by-path.patch
source = 0001-Add_finder_for_uthash.patch
source = 0002-Use_system_uthash.patch
- source = 0003-Fix_blank_browser_dock_titles.patch
sha256sums = SKIP
sha256sums = SKIP
sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = 65116d10f03d390505fdb0bbf6fe649e8649500441dde91e029f2eb79bfdc80f
+ sha256sums = 23a0bd9f5e36d333b230ed8dfdfd06c3b4826187e3f858cde93200f5e0da2334
sha256sums = ee54b9c6f7e17fcc62c6afc094e65f18b2e97963c2fe92289b2b91972ac206e5
sha256sums = f4a56021a7f1c564f95b588d7c09b60a89efa2c1954c8a418cf6320b5a818542
- sha256sums = 966250c40ab47276e1d420941b5b1e448886b0ab8643f25ba37dce08df68f34d
- sha256sums = 8980d1e871177c3f65d5cf0c249ef36c5a9e2a6956bbc592283782ec58d825e7
+ sha256sums = 874456110d17d2efe02f8a1f47f58c877922d8bdab6435df334b9e6460b26bf8
pkgname = obs-studio-tytan652
diff --git a/0002-Use_system_uthash.patch b/0002-Use_system_uthash.patch
index b942ca763286..eaa7db1da6b6 100644
--- a/0002-Use_system_uthash.patch
+++ b/0002-Use_system_uthash.patch
@@ -1,4 +1,4 @@
-From 8d1b5aa01d290b2e2203623cc5f51b7c854012da Mon Sep 17 00:00:00 2001
+From e1e12d2acda6f511a5f70ed6b6e10d1b8c83708a Mon Sep 17 00:00:00 2001
From: tytan652 <tytan652@tytanium.xyz>
Date: Mon, 24 Jul 2023 10:52:05 +0200
Subject: [PATCH] deps,libobs: Replace uthash with prefix/system install
@@ -19,20 +19,18 @@ Subject: [PATCH] deps,libobs: Replace uthash with prefix/system install
delete mode 100644 deps/uthash/uthash/uthash.h
diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt
-index 9e92bb114..6ab050f03 100644
+index d093e29df0883..8e4cb2d412320 100644
--- a/deps/CMakeLists.txt
+++ b/deps/CMakeLists.txt
-@@ -16,7 +16,6 @@ add_subdirectory(file-updater)
+@@ -12,5 +12,4 @@ add_subdirectory(file-updater)
add_subdirectory(obs-scripting)
add_subdirectory(opts-parser)
add_subdirectory(libcaption)
-add_subdirectory(uthash)
-
- # Use bundled jansson version as fallback
- find_package(Jansson 2.5 QUIET)
+ add_subdirectory(happy-eyeballs)
diff --git a/deps/uthash/.clang-format b/deps/uthash/.clang-format
deleted file mode 100644
-index 6420a4688..000000000
+index 6420a46881e05..0000000000000
--- a/deps/uthash/.clang-format
+++ /dev/null
@@ -1,3 +0,0 @@
@@ -41,11 +39,11 @@ index 6420a4688..000000000
-DisableFormat: true
diff --git a/deps/uthash/CMakeLists.txt b/deps/uthash/CMakeLists.txt
deleted file mode 100644
-index 19f262a36..000000000
+index aecb0d74e49a5..0000000000000
--- a/deps/uthash/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
--cmake_minimum_required(VERSION 3.16...3.25)
+-cmake_minimum_required(VERSION 3.22...3.25)
-
-add_library(uthash INTERFACE)
-add_library(OBS::uthash ALIAS uthash)
@@ -55,7 +53,7 @@ index 19f262a36..000000000
-set_target_properties(uthash PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/deps/uthash/uthash/LICENSE b/deps/uthash/uthash/LICENSE
deleted file mode 100644
-index e75a243af..000000000
+index e75a243af9b99..0000000000000
--- a/deps/uthash/uthash/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
@@ -82,7 +80,7 @@ index e75a243af..000000000
-
diff --git a/deps/uthash/uthash/uthash.h b/deps/uthash/uthash/uthash.h
deleted file mode 100644
-index ac78fdab5..000000000
+index ac78fdab5a4f5..0000000000000
--- a/deps/uthash/uthash/uthash.h
+++ /dev/null
@@ -1,1136 +0,0 @@
@@ -1223,10 +1221,10 @@ index ac78fdab5..000000000
-
-#endif /* UTHASH_H */
diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt
-index d2e26710d..759e98ede 100644
+index 46112abe71f9d..185a0b6560fac 100644
--- a/libobs/CMakeLists.txt
+++ b/libobs/CMakeLists.txt
-@@ -8,6 +8,7 @@ add_library(OBS::libobs ALIAS libobs)
+@@ -16,6 +16,7 @@ add_library(OBS::libobs ALIAS libobs)
find_package(Threads REQUIRED)
find_package(FFmpeg REQUIRED avformat avutil swscale swresample OPTIONAL_COMPONENTS avcodec)
find_package(ZLIB REQUIRED)
@@ -1234,7 +1232,7 @@ index d2e26710d..759e98ede 100644
if(ENABLE_UI)
find_qt(COMPONENTS Core)
-@@ -15,7 +16,6 @@ endif()
+@@ -23,7 +24,6 @@ endif()
find_package(jansson REQUIRED)
add_subdirectory("${CMAKE_SOURCE_DIR}/deps/libcaption" "${CMAKE_BINARY_DIR}/deps/libcaption")
@@ -1242,14 +1240,15 @@ index d2e26710d..759e98ede 100644
target_sources(
libobs
-@@ -225,13 +225,13 @@ target_compile_definitions(
+@@ -232,7 +232,6 @@ target_compile_definitions(
target_link_libraries(
libobs
PRIVATE OBS::caption
- OBS::uthash
+ OBS::libobs-version
FFmpeg::avcodec
FFmpeg::avformat
- FFmpeg::avutil
+@@ -240,6 +239,7 @@ target_link_libraries(
FFmpeg::swscale
FFmpeg::swresample
jansson::jansson
@@ -1258,28 +1257,29 @@ index d2e26710d..759e98ede 100644
PUBLIC Threads::Threads)
diff --git a/libobs/cmake/legacy.cmake b/libobs/cmake/legacy.cmake
-index fcbacd7b9..f870ceb0f 100644
+index 5f13c4c0f04ab..81d82e747bfd9 100644
--- a/libobs/cmake/legacy.cmake
+++ b/libobs/cmake/legacy.cmake
-@@ -10,6 +10,7 @@ find_package(
+@@ -20,6 +20,7 @@ find_package(
COMPONENTS avformat avutil swscale swresample
OPTIONAL_COMPONENTS avcodec)
find_package(ZLIB REQUIRED)
+find_package(Uthash REQUIRED)
- if(ENABLE_UI)
- find_qt(COMPONENTS Core)
-@@ -248,7 +249,7 @@ target_link_libraries(
+ add_library(libobs SHARED)
+ add_library(OBS::libobs ALIAS libobs)
+@@ -252,8 +253,8 @@ target_link_libraries(
FFmpeg::swresample
Jansson::Jansson
OBS::caption
- OBS::uthash
+ OBS::libobs-version
+ Uthash::Uthash
ZLIB::ZLIB
PUBLIC Threads::Threads)
diff --git a/libobs/util/uthash.h b/libobs/util/uthash.h
-index 5698466ea..fb6a240da 100644
+index 5698466ea96fb..fb6a240dafff1 100644
--- a/libobs/util/uthash.h
+++ b/libobs/util/uthash.h
@@ -21,7 +21,7 @@
@@ -1291,6 +1291,3 @@ index 5698466ea..fb6a240da 100644
/* Use OBS allocator */
#undef uthash_malloc
---
-2.42.0
-
diff --git a/PKGBUILD b/PKGBUILD
index 60d6b24d1c21..be5148771e08 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,13 +1,14 @@
# Maintainer: tytan652 <tytan652 at tytanium dot xyz>
pkgname=obs-studio-tytan652
-pkgver=29.1.3
-pkgrel=6
+pkgver=30.0.0
+pkgrel=1
pkgdesc="Free and open source software for video recording and live streaming. With everything except service integrations. Plus V4L2 devices by paths, my bind interface PR, and sometimes backported fixes"
arch=("x86_64" "aarch64")
url="https://github.com/obsproject/obs-studio"
license=("GPL3")
# To manage dependency rebuild easily, this will prevent you to rebuild OBS on non-updated system
+_libdatachannelver=0.19.2
_mbedtlsver=3.4
_pythonver=3.11
depends=(
@@ -17,21 +18,22 @@ depends=(
"fontconfig" # Deps of Freetype2 plugin
"freetype2" # Deps of Freetype2 plugin
"ftl-sdk" # Deps of Outputs plugin
- "gcc-libs" # Deps of any C related binary
+ "gcc-libs" # Deps of any C++ related binary
"glib2" # Deps of libobs, PipeWire plugin and CEF
- "glibc" # Deps of any C++ related binary
+ "glibc" # Deps of any C related binary
"jansson" # Deps of libobs and rtmp-services plugin
"libgl" # Deps of libobs-opengl and OBS Studio
"libpipewire" # Deps of the PipeWire plugin
"libpulse" # Deps of PulseAudio monitoring (in libobs) and PulseAudio plugin
"librist" # Deps of FFmpeg plugin
- "libva" # Deps of FFmpeg plugin
+ "libva" # Deps of FFmpeg plugin and QSV plugin
"libx11" # Deps of libobs, libobs-opengl, X11 Capture plugin, frontend tools plugin, obs-browser and CEF
"libxcb" # Deps of libobs-opengl, X11 Capture plugin and CEF
"libxcomposite" # Deps of the X11 capture plugin
"libxkbcommon" # Deps of libobs, OBS Studio and CEF
"mbedtls>=$_mbedtlsver" # Deps of OBS Studio and Outputs plugin
"pciutils" # Deps of FFmpeg plugin
+ "qrcodegencpp-cmake" # Deps of Websocket plugin
"qt6-base" # Deps of OBS Studio and any frontend plugin
"qt6-svg" # Deps of OBS Studio
"qt6-wayland" # Needed to use Qt on Wayland platform
@@ -63,9 +65,11 @@ makedepends=(
"git"
"uthash" # Deps of libobs
"libajantv2" # Deps of AJA plugin (static lib)
+ "libdatachannel-nice>=$_libdatachannelver" # Deps of WebRTC plugin (NICE variant like the Flatpak)
"libfdk-aac" # Deps of FDK AAC plugin
"luajit" # Deps of Scripting plugin
"nlohmann-json" # Deps of Websocket plugin (headers-only lib)
+ "onevpl" # Deps of QSV plugin
"python>=$_pythonver" # Deps of Scripting plugin
"sndio" # Deps of sndio plugin
"swig" # Deps of Scripting plugin
@@ -79,9 +83,12 @@ makedepends=(
optdepends=(
"jack: JACK support"
"libfdk-aac: FDK AAC codec support"
- "intel-media-driver: Hardware encoding (>= Broadwell)"
- "libva-intel-driver: Hardware encoding (<= Haswell)"
- "libva-mesa-driver: Hardware encoding"
+ "onevpl: QSV encoder support"
+ "intel-media-sdk: QSV encoder support(<= Rocket Lake & >= Broadwell)"
+ "onevpl-intel-gpu: QSV encoder support (>= Alder Lake)"
+ "intel-media-driver: VAAPI encoder support (>= Broadwell)"
+ "libva-intel-driver: VAAPI encoder support (<= Haswell)"
+ "libva-mesa-driver: VAAPI encoder support"
"swig: Scripting"
"luajit: Lua scripting"
"python>=$_pythonver: Python scripting"
@@ -89,6 +96,7 @@ optdepends=(
"v4l-utils: V4L2 support"
"systemd-libs: V4L2 support"
"v4l2loopback-dkms: V4L2 virtual camera output"
+ "libdatachannel>=$_libdatachannelver: WHIP Support"
)
provides=("obs-studio=$pkgver" "obs-vst" "obs-websocket" "obs-browser")
conflicts=(
@@ -101,23 +109,19 @@ source=(
"obs-studio::git+https://github.com/obsproject/obs-studio.git#tag=$pkgver"
"obs-browser::git+https://github.com/obsproject/obs-browser.git"
"obs-websocket::git+https://github.com/obsproject/obs-websocket.git"
- "qr::git+https://github.com/nayuki/QR-Code-generator.git"
- "bind_iface.patch" # Based on https://patch-diff.githubusercontent.com/raw/obsproject/obs-studio/pull/4219.patch
+ "bind_iface_eyeballed.patch" # Based on https://github.com/tytan652/obs-studio/commits/bind_iface_eyeballed
"v4l2_by-path.patch" # https://patch-diff.githubusercontent.com/raw/obsproject/obs-studio/pull/3437.patch
"0001-Add_finder_for_uthash.patch"
"0002-Use_system_uthash.patch"
- "0003-Fix_blank_browser_dock_titles.patch"
)
sha256sums=(
"SKIP"
"SKIP"
"SKIP"
- "SKIP"
- "65116d10f03d390505fdb0bbf6fe649e8649500441dde91e029f2eb79bfdc80f"
+ "23a0bd9f5e36d333b230ed8dfdfd06c3b4826187e3f858cde93200f5e0da2334"
"ee54b9c6f7e17fcc62c6afc094e65f18b2e97963c2fe92289b2b91972ac206e5"
"f4a56021a7f1c564f95b588d7c09b60a89efa2c1954c8a418cf6320b5a818542"
- "966250c40ab47276e1d420941b5b1e448886b0ab8643f25ba37dce08df68f34d"
- "8980d1e871177c3f65d5cf0c249ef36c5a9e2a6956bbc592283782ec58d825e7"
+ "874456110d17d2efe02f8a1f47f58c877922d8bdab6435df334b9e6460b26bf8"
)
if [[ $CARCH == 'x86_64' ]]; then
@@ -132,30 +136,21 @@ prepare() {
patch -Np1 -i "$srcdir/0001-Add_finder_for_uthash.patch"
patch -Np1 -i "$srcdir/0002-Use_system_uthash.patch"
- # https://github.com/obsproject/obs-studio/pull/9373
- patch -Np1 -i "$srcdir/0003-Fix_blank_browser_dock_titles.patch"
-
- cd plugins/obs-websocket
- git config submodule.deps/qr.url $srcdir/qr
- git -c protocol.file.allow=always submodule update deps/qr
cd "$srcdir/obs-studio"
- ## Add network interface binding for RTMP on Linux (https://github.com/obsproject/obs-studio/pull/4219)
- patch -Np1 < "$srcdir/bind_iface.patch"
+ ## Add network interface binding for RTMP on Linux (https://github.com/tytan652/obs-studio/commits/bind_iface_eyeballed)
+ patch -Np1 < "$srcdir/bind_iface_eyeballed.patch"
## (not up to date for 29) linux-v4l2: Save device by id or path (https://github.com/obsproject/obs-studio/pull/6493)
## patch -Np1 < "$srcdir/v4l2_by-path.patch"
}
build() {
- export CXXFLAGS="$CXXFLAGS -Wno-error=dangling-reference"
-
cmake -B build -S obs-studio \
-DCMAKE_BUILD_TYPE=None \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=lib \
-DENABLE_RTMPS=ON \
- -DQT_VERSION=6 \
-DENABLE_LIBFDK=ON \
-DENABLE_JACK=ON \
-DENABLE_SNDIO=ON \
diff --git a/bind_iface.patch b/bind_iface.patch
deleted file mode 100644
index b18db49f36d2..000000000000
--- a/bind_iface.patch
+++ /dev/null
@@ -1,576 +0,0 @@
-From d2c20c3996cc4ef6fab975f816d7cf0831830173 Mon Sep 17 00:00:00 2001
-From: tytan652 <tytan652@tytanium.xyz>
-Date: Thu, 11 Feb 2021 14:29:08 +0100
-Subject: [PATCH 1/3] librtmp: Add interface binding for Linux
-
-librtmp: Make log message more accurate
----
- plugins/obs-outputs/librtmp/rtmp.c | 19 ++++++++++++++++++-
- plugins/obs-outputs/librtmp/rtmp.h | 1 +
- 2 files changed, 19 insertions(+), 1 deletion(-)
-
-diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c
-index 28239cb0351c8..01f669cb5c6ed 100644
---- a/plugins/obs-outputs/librtmp/rtmp.c
-+++ b/plugins/obs-outputs/librtmp/rtmp.c
-@@ -877,13 +877,30 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service, socklen_t addrlen)
- #ifdef SO_NOSIGPIPE
- setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof(int));
- #endif
-+#endif
-+
-+#ifdef __linux__
-+ if(r->m_bindInterface.av_len)
-+ {
-+ if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_BINDTODEVICE,
-+ r->m_bindInterface.av_val,
-+ r->m_bindInterface.av_len) < 0)
-+ {
-+ int err = GetSockError();
-+ RTMP_Log(RTMP_LOGERROR, "%s, failed to bind socket to interface: %s (%d)",
-+ __FUNCTION__, socketerror(err), err);
-+ r->last_error_code = err;
-+ RTMP_Close(r);
-+ return FALSE;
-+ }
-+ }
- #endif
- if(r->m_bindIP.addrLen)
- {
- if (bind(r->m_sb.sb_socket, (const struct sockaddr *)&r->m_bindIP.addr, r->m_bindIP.addrLen) < 0)
- {
- int err = GetSockError();
-- RTMP_Log(RTMP_LOGERROR, "%s, failed to bind socket: %s (%d)",
-+ RTMP_Log(RTMP_LOGERROR, "%s, failed to bind socket to address: %s (%d)",
- __FUNCTION__, socketerror(err), err);
- r->last_error_code = err;
- RTMP_Close(r);
-diff --git a/plugins/obs-outputs/librtmp/rtmp.h b/plugins/obs-outputs/librtmp/rtmp.h
-index b1c48e2f3a9f6..a900efbe17a0d 100644
---- a/plugins/obs-outputs/librtmp/rtmp.h
-+++ b/plugins/obs-outputs/librtmp/rtmp.h
-@@ -420,6 +420,7 @@ extern "C"
- void* m_customSendParam;
- CUSTOMSEND m_customSendFunc;
-
-+ AVal m_bindInterface;
- RTMP_BINDINFO m_bindIP;
-
- uint8_t m_bSendChunkSizeInfo;
-
-From e333022f1f357ab891fcb5323b38ac4a393adad8 Mon Sep 17 00:00:00 2001
-From: tytan652 <tytan652@tytanium.xyz>
-Date: Thu, 11 Feb 2021 14:47:45 +0100
-Subject: [PATCH 2/3] obs-outputs: Add RTMP iface binding for Linux
-
----
- plugins/obs-outputs/net-if.c | 32 +++++++++++++++++++++++++++++
- plugins/obs-outputs/net-if.h | 15 ++++++++++++++
- plugins/obs-outputs/rtmp-stream.c | 34 +++++++++++++++++++++++++++++++
- plugins/obs-outputs/rtmp-stream.h | 2 ++
- 4 files changed, 83 insertions(+)
-
-diff --git a/plugins/obs-outputs/net-if.c b/plugins/obs-outputs/net-if.c
-index 29bb57d6a42bc..1587be47887b8 100644
---- a/plugins/obs-outputs/net-if.c
-+++ b/plugins/obs-outputs/net-if.c
-@@ -139,6 +139,38 @@ static inline bool is_loopback(struct ifaddrs *ifa)
- return n && (strcmp(n, "lo") == 0 || strcmp(n, "lo0") == 0);
- }
-
-+#ifdef __linux__
-+void netif_get_ifaces(struct netif_siface_data *ifaces)
-+{
-+ da_init(ifaces->ifaces);
-+
-+ struct ifaddrs *ifaddr, *ifa;
-+ unsigned int family;
-+
-+ if (getifaddrs(&ifaddr) == -1) {
-+ warn("getifaddrs() failed");
-+ return;
-+ }
-+
-+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-+ if (ifa->ifa_addr == NULL || is_loopback(ifa))
-+ continue;
-+ family = ifa->ifa_addr->sa_family;
-+
-+ if ((family == AF_INET) || (family == AF_INET6)) {
-+ char *item;
-+ char *iface_dup = bstrdup(ifa->ifa_name);
-+
-+ item = iface_dup;
-+
-+ da_push_back(ifaces->ifaces, &item);
-+ }
-+ }
-+
-+ freeifaddrs(ifaddr);
-+}
-+#endif
-+
- static inline void netif_get_addrs_nix(struct netif_saddr_data *ifaddrs)
- {
- struct ifaddrs *ifaddr, *ifa;
-diff --git a/plugins/obs-outputs/net-if.h b/plugins/obs-outputs/net-if.h
-index 757ee00e82781..6b045666cfba6 100644
---- a/plugins/obs-outputs/net-if.h
-+++ b/plugins/obs-outputs/net-if.h
-@@ -53,6 +53,21 @@
-
- #endif
-
-+#ifdef __linux__
-+struct netif_siface_data {
-+ DARRAY(char *) ifaces;
-+};
-+
-+static inline void netif_siface_data_free(struct netif_siface_data *data)
-+{
-+ for (size_t i = 0; i < data->ifaces.num; i++)
-+ bfree(data->ifaces.array[i]);
-+ da_free(data->ifaces);
-+}
-+
-+extern void netif_get_ifaces(struct netif_siface_data *ifaces);
-+#endif
-+
- struct netif_saddr_item {
- char *name;
- char *addr;
-diff --git a/plugins/obs-outputs/rtmp-stream.c b/plugins/obs-outputs/rtmp-stream.c
-index 899881765a90d..631b0b0e2211e 100644
---- a/plugins/obs-outputs/rtmp-stream.c
-+++ b/plugins/obs-outputs/rtmp-stream.c
-@@ -131,6 +131,7 @@ static void rtmp_stream_destroy(void *data)
- dstr_free(&stream->username);
- dstr_free(&stream->password);
- dstr_free(&stream->encoder_name);
-+ dstr_free(&stream->bind_interface);
- dstr_free(&stream->bind_ip);
- os_event_destroy(stream->stop_event);
- os_sem_destroy(stream->send_sem);
-@@ -1252,6 +1253,17 @@ static int try_connect(struct rtmp_stream *stream)
- stream->rtmp.Link.swfUrl = stream->rtmp.Link.tcUrl;
- stream->rtmp.Link.customConnectEncode = add_connect_data;
-
-+ if (dstr_is_empty(&stream->bind_interface) ||
-+ dstr_cmp(&stream->bind_interface, "default") == 0) {
-+ memset(&stream->rtmp.m_bindInterface, 0,
-+ sizeof(stream->rtmp.m_bindInterface));
-+ } else {
-+ set_rtmp_dstr(&stream->rtmp.m_bindInterface,
-+ &stream->bind_interface);
-+ info("Binding to interface %s",
-+ stream->rtmp.m_bindInterface.av_val);
-+ }
-+
- if (dstr_is_empty(&stream->bind_ip) ||
- dstr_cmp(&stream->bind_ip, "default") == 0) {
- memset(&stream->rtmp.m_bindIP, 0,
-@@ -1294,6 +1306,7 @@ static bool init_connect(struct rtmp_stream *stream)
- {
- obs_service_t *service;
- obs_data_t *settings;
-+ const char *bind_interface;
- const char *bind_ip;
- int64_t drop_p;
- int64_t drop_b;
-@@ -1378,6 +1391,9 @@ static bool init_connect(struct rtmp_stream *stream)
- stream->drop_threshold_usec = 1000 * drop_b;
- stream->pframe_drop_threshold_usec = 1000 * drop_p;
-
-+ bind_interface = obs_data_get_string(settings, OPT_BIND_INTERFACE);
-+ dstr_copy(&stream->bind_interface, bind_interface);
-+
- bind_ip = obs_data_get_string(settings, OPT_BIND_IP);
- dstr_copy(&stream->bind_ip, bind_ip);
-
-@@ -1799,6 +1815,9 @@ static obs_properties_t *rtmp_stream_properties(void *unused)
- UNUSED_PARAMETER(unused);
-
- obs_properties_t *props = obs_properties_create();
-+#ifdef __linux__
-+ struct netif_siface_data ifaces = {0};
-+#endif
- struct netif_saddr_data addrs = {0};
- obs_property_t *p;
-
-@@ -1806,6 +1825,21 @@ static obs_properties_t *rtmp_stream_properties(void *unused)
- obs_module_text("RTMPStream.DropThreshold"),
- 200, 10000, 100);
- obs_property_int_set_suffix(p, " ms");
-+#ifdef __linux__
-+ p = obs_properties_add_list(props, OPT_BIND_INTERFACE,
-+ obs_module_text("RTMPStream.BindInterface"),
-+ OBS_COMBO_TYPE_LIST,
-+ OBS_COMBO_FORMAT_STRING);
-+
-+ obs_property_list_add_string(p, obs_module_text("Default"), "default");
-+
-+ netif_get_ifaces(&ifaces);
-+ for (size_t i = 0; i < ifaces.ifaces.num; i++) {
-+ char *item = ifaces.ifaces.array[i];
-+ obs_property_list_add_string(p, item, item);
-+ }
-+ netif_siface_data_free(&ifaces);
-+#endif
-
- p = obs_properties_add_list(props, OPT_BIND_IP,
- obs_module_text("RTMPStream.BindIP"),
-diff --git a/plugins/obs-outputs/rtmp-stream.h b/plugins/obs-outputs/rtmp-stream.h
-index 6a33ff9c9b068..329c2e1807179 100644
---- a/plugins/obs-outputs/rtmp-stream.h
-+++ b/plugins/obs-outputs/rtmp-stream.h
-@@ -27,6 +27,7 @@
- #define OPT_DROP_THRESHOLD "drop_threshold_ms"
- #define OPT_PFRAME_DROP_THRESHOLD "pframe_drop_threshold_ms"
- #define OPT_MAX_SHUTDOWN_TIME_SEC "max_shutdown_time_sec"
-+#define OPT_BIND_INTERFACE "bind_interface"
- #define OPT_BIND_IP "bind_ip"
- #define OPT_NEWSOCKETLOOP_ENABLED "new_socket_loop_enabled"
- #define OPT_LOWLATENCY_ENABLED "low_latency_mode_enabled"
-@@ -81,6 +82,7 @@ struct rtmp_stream {
- struct dstr path, key;
- struct dstr username, password;
- struct dstr encoder_name;
-+ struct dstr bind_interface;
- struct dstr bind_ip;
-
- /* frame drop variables */
-
-From 960e5a7152e1e0000fc886c5d46801d355aeaee5 Mon Sep 17 00:00:00 2001
-From: tytan652 <tytan652@tytanium.xyz>
-Date: Thu, 11 Feb 2021 14:51:42 +0100
-Subject: [PATCH 3/3] UI: Add interface binding property for Linux
-
----
- UI/data/locale/en-US.ini | 1 +
- UI/forms/OBSBasicSettings.ui | 24 ++++++--
- UI/window-basic-auto-config-test.cpp | 3 +
- UI/window-basic-main-outputs.cpp | 6 ++
- UI/window-basic-main.cpp | 2 +
- UI/window-basic-settings.cpp | 91 +++++++++++++++++++++++++++-
- UI/window-basic-settings.hpp | 3 +
- 7 files changed, 123 insertions(+), 7 deletions(-)
-
-diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
-index 4c03aa7db816d..0780d5a4fd276 100644
---- a/UI/data/locale/en-US.ini
-+++ b/UI/data/locale/en-US.ini
-@@ -1229,6 +1229,7 @@ Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase de
- Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
- Basic.Settings.Advanced.Network="Network"
- Basic.Settings.Advanced.Network.Disabled="The currently selected streaming protocol does not support changing network settings."
-+Basic.Settings.Advanced.Network.BindToInterface="Bind to interface"
- Basic.Settings.Advanced.Network.BindToIP="Bind to IP"
- Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable network optimizations"
- Basic.Settings.Advanced.Network.EnableLowLatencyMode="Enable TCP pacing"
-diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
-index b7b47a1d45ba7..cbb1316219e6b 100644
---- a/UI/forms/OBSBasicSettings.ui
-+++ b/UI/forms/OBSBasicSettings.ui
-@@ -7560,6 +7560,19 @@
- </widget>
- </item>
- <item row="1" column="0">
-+ <widget class="QLabel" name="bindToIfaceLabel">
-+ <property name="text">
-+ <string>Basic.Settings.Advanced.Network.BindToInterface</string>
-+ </property>
-+ <property name="buddy">
-+ <cstring>bindToInterface</cstring>
-+ </property>
-+ </widget>
-+ </item>
-+ <item row="1" column="1">
-+ <widget class="QComboBox" name="bindToInterface"/>
-+ </item>
-+ <item row="2" column="0">
- <widget class="QLabel" name="bindToIPLabel">
- <property name="text">
- <string>Basic.Settings.Advanced.Network.BindToIP</string>
-@@ -7569,17 +7582,17 @@
- </property>
- </widget>
- </item>
-- <item row="1" column="1">
-+ <item row="2" column="1">
- <widget class="QComboBox" name="bindToIP"/>
- </item>
-- <item row="3" column="1">
-+ <item row="4" column="1">
- <widget class="QCheckBox" name="enableNewSocketLoop">
- <property name="text">
- <string>Basic.Settings.Advanced.Network.EnableNewSocketLoop</string>
- </property>
- </widget>
- </item>
-- <item row="4" column="1">
-+ <item row="5" column="1">
- <widget class="QCheckBox" name="enableLowLatencyMode">
- <property name="enabled">
- <bool>false</bool>
-@@ -7589,7 +7602,7 @@
- </property>
- </widget>
- </item>
-- <item row="3" column="0">
-+ <item row="4" column="0">
- <spacer name="horizontalSpacer_7">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
-@@ -7602,7 +7615,7 @@
- </property>
- </spacer>
- </item>
-- <item row="2" column="1">
-+ <item row="3" column="1">
- <widget class="QCheckBox" name="dynBitrate">
- <property name="toolTip">
- <string>Basic.Settings.Output.DynamicBitrate.TT</string>
-@@ -7931,6 +7944,7 @@
- <tabstop>reconnectRetryDelay</tabstop>
- <tabstop>reconnectMaxRetries</tabstop>
- <tabstop>bindToIP</tabstop>
-+ <tabstop>bindToInterface</tabstop>
- <tabstop>dynBitrate</tabstop>
- <tabstop>enableNewSocketLoop</tabstop>
- <tabstop>enableLowLatencyMode</tabstop>
-diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
-index 2d89d73472c8d..1705da129c1b0 100644
---- a/UI/window-basic-auto-config-test.cpp
-+++ b/UI/window-basic-auto-config-test.cpp
-@@ -245,6 +245,9 @@ void AutoConfigTestPage::TestBandwidthThread()
- obs_data_set_int(aencoder_settings, "bitrate", 32);
-
- OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
-+ const char *bind_interface =
-+ config_get_string(main->Config(), "Output", "BindInterface");
-+ obs_data_set_string(output_settings, "bind_interface", bind_interface);
- const char *bind_ip =
- config_get_string(main->Config(), "Output", "BindIP");
- obs_data_set_string(output_settings, "bind_ip", bind_ip);
-diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
-index 737ab966d15e3..7b3a2fb03402b 100644
---- a/UI/window-basic-main-outputs.cpp
-+++ b/UI/window-basic-main-outputs.cpp
-@@ -1164,6 +1164,8 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
- int delaySec = config_get_int(main->Config(), "Output", "DelaySec");
- bool preserveDelay =
- config_get_bool(main->Config(), "Output", "DelayPreserve");
-+ const char *bindInterface =
-+ config_get_string(main->Config(), "Output", "BindInterface");
- const char *bindIP =
- config_get_string(main->Config(), "Output", "BindIP");
- #ifdef _WIN32
-@@ -1176,6 +1178,7 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
- config_get_bool(main->Config(), "Output", "DynamicBitrate");
-
- OBSDataAutoRelease settings = obs_data_create();
-+ obs_data_set_string(settings, "bind_interface", bindInterface);
- obs_data_set_string(settings, "bind_ip", bindIP);
- #ifdef _WIN32
- obs_data_set_bool(settings, "new_socket_loop_enabled",
-@@ -2110,6 +2113,8 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
- int delaySec = config_get_int(main->Config(), "Output", "DelaySec");
- bool preserveDelay =
- config_get_bool(main->Config(), "Output", "DelayPreserve");
-+ const char *bindInterface =
-+ config_get_string(main->Config(), "Output", "BindInterface");
- const char *bindIP =
- config_get_string(main->Config(), "Output", "BindIP");
- #ifdef _WIN32
-@@ -2122,6 +2127,7 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
- config_get_bool(main->Config(), "Output", "DynamicBitrate");
-
- OBSDataAutoRelease settings = obs_data_create();
-+ obs_data_set_string(settings, "bind_interface", bindInterface);
- obs_data_set_string(settings, "bind_ip", bindIP);
- #ifdef _WIN32
- obs_data_set_bool(settings, "new_socket_loop_enabled",
-diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
-index 8b0714ad7e0d2..ddcebc74aabba 100644
---- a/UI/window-basic-main.cpp
-+++ b/UI/window-basic-main.cpp
-@@ -1610,6 +1610,8 @@ bool OBSBasic::InitBasicConfigDefaults()
- config_set_default_uint(basicConfig, "Output", "RetryDelay", 2);
- config_set_default_uint(basicConfig, "Output", "MaxRetries", 25);
-
-+ config_set_default_string(basicConfig, "Output", "BindInterface",
-+ "default");
- config_set_default_string(basicConfig, "Output", "BindIP", "default");
- config_set_default_bool(basicConfig, "Output", "NewSocketLoopEnable",
- false);
-diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
-index 643aa0eacb683..7ba47b3144210 100644
---- a/UI/window-basic-settings.cpp
-+++ b/UI/window-basic-settings.cpp
-@@ -625,6 +625,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
- HookWidget(ui->reconnectMaxRetries, SCROLL_CHANGED, ADV_CHANGED);
- HookWidget(ui->processPriority, COMBO_CHANGED, ADV_CHANGED);
- HookWidget(ui->confirmOnExit, CHECK_CHANGED, ADV_CHANGED);
-+#ifdef __linux__
-+ HookWidget(ui->bindToInterface, COMBO_CHANGED, ADV_CHANGED);
-+#endif
- HookWidget(ui->bindToIP, COMBO_CHANGED, ADV_CHANGED);
- HookWidget(ui->enableNewSocketLoop, CHECK_CHANGED, ADV_CHANGED);
- HookWidget(ui->enableLowLatencyMode, CHECK_CHANGED, ADV_CHANGED);
-@@ -733,6 +736,13 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
- ui->resetOSXVSync = nullptr;
- #endif
-
-+#ifndef __linux__
-+ delete ui->bindToIfaceLabel;
-+ delete ui->bindToInterface;
-+ ui->bindToIfaceLabel = nullptr;
-+ ui->bindToInterface = nullptr;
-+#endif
-+
- connect(ui->streamDelaySec, SIGNAL(valueChanged(int)), this,
- SLOT(UpdateStreamDelayEstimate()));
- connect(ui->outputMode, SIGNAL(currentIndexChanged(int)), this,
-@@ -884,9 +894,37 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
- SLOT(AdvReplayBufferChanged()));
- connect(ui->advRBSecMax, SIGNAL(valueChanged(int)), this,
- SLOT(AdvReplayBufferChanged()));
-+#ifdef __linux__
-+ connect(ui->bindToInterface, SIGNAL(currentIndexChanged(int)), this,
-+ SLOT(UpdateAddrList()));
-
-- // Get Bind to IP Addresses
-+ ui->bindToIP->setEnabled(false);
-+#endif
-+
-+ // Get Bind to interfaces Interfaces (Linux only)
-+ // Get Bind to IP Addresses (Others)
- obs_properties_t *ppts = obs_get_output_properties("rtmp_output");
-+#ifdef __linux__
-+ obs_property_t *p_iface = obs_properties_get(ppts, "bind_interface");
-+ QStringList dedup_iface = {};
-+
-+ ui->bindToInterface->blockSignals(true);
-+
-+ size_t count_iface = obs_property_list_item_count(p_iface);
-+ for (size_t i = 0; i < count_iface; i++) {
-+ const char *name = obs_property_list_item_name(p_iface, i);
-+ const char *val = obs_property_list_item_string(p_iface, i);
-+
-+ // Add interfaces without duplicates
-+ if (!dedup_iface.contains(QT_UTF8(name))) {
-+ dedup_iface.append(QT_UTF8(name));
-+ ui->bindToInterface->addItem(QT_UTF8(name), val);
-+ }
-+ }
-+
-+ UpdateAddrList();
-+ ui->bindToInterface->blockSignals(false);
-+#else
- obs_property_t *p = obs_properties_get(ppts, "bind_ip");
-
- size_t count = obs_property_list_item_count(p);
-@@ -896,7 +934,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
-
- ui->bindToIP->addItem(QT_UTF8(name), val);
- }
--
-+#endif
- obs_properties_destroy(ppts);
-
- InitStreamPage();
-@@ -2883,6 +2921,10 @@ void OBSBasicSettings::LoadAdvancedSettings()
- "FilenameFormatting");
- bool overwriteIfExists =
- config_get_bool(main->Config(), "Output", "OverwriteIfExists");
-+#ifdef __linux__
-+ const char *bindInterface =
-+ config_get_string(main->Config(), "Output", "BindInterface");
-+#endif
- const char *bindIP =
- config_get_string(main->Config(), "Output", "BindIP");
- const char *rbPrefix = config_get_string(main->Config(), "SimpleOutput",
-@@ -2936,6 +2978,12 @@ void OBSBasicSettings::LoadAdvancedSettings()
- ui->sdrWhiteLevel->setValue(sdrWhiteLevel);
- ui->hdrNominalPeakLevel->setValue(hdrNominalPeakLevel);
-
-+#ifdef __linux__
-+ if (!SetComboByValue(ui->bindToInterface, bindInterface))
-+ SetInvalidValue(ui->bindToInterface, bindInterface,
-+ bindInterface);
-+#endif
-+
- if (!SetComboByValue(ui->bindToIP, bindIP))
- SetInvalidValue(ui->bindToIP, bindIP, bindIP);
-
-@@ -3668,6 +3716,9 @@ void OBSBasicSettings::SaveAdvancedSettings()
- SaveCheckBox(ui->reconnectEnable, "Output", "Reconnect");
- SaveSpinBox(ui->reconnectRetryDelay, "Output", "RetryDelay");
- SaveSpinBox(ui->reconnectMaxRetries, "Output", "MaxRetries");
-+#ifdef __linux__
-+ SaveComboData(ui->bindToInterface, "Output", "BindInterface");
-+#endif
- SaveComboData(ui->bindToIP, "Output", "BindIP");
- SaveCheckBox(ui->autoRemux, "Video", "AutoRemux");
- SaveCheckBox(ui->dynBitrate, "Output", "DynamicBitrate");
-@@ -6202,6 +6253,9 @@ void OBSBasicSettings::UpdateAdvNetworkGroup()
- #ifdef _WIN32
- ui->enableNewSocketLoop->setVisible(enabled);
- ui->enableLowLatencyMode->setVisible(enabled);
-+#elif defined(__linux__)
-+ ui->bindToIfaceLabel->setVisible(enabled);
-+ ui->bindToInterface->setVisible(enabled);
- #endif
- }
-
-@@ -6240,3 +6294,36 @@ void OBSBasicSettings::AdvAudioEncodersChanged()
- ui->advOutTrack6Bitrate},
- 320);
- }
-+
-+#ifdef __linux__
-+void OBSBasicSettings::UpdateAddrList()
-+{
-+ ui->bindToIP->clear();
-+
-+ // Get Bind to IP Addresses (Linux only)
-+ obs_properties_t *ppts = obs_get_output_properties("rtmp_output");
-+ obs_property_t *p = obs_properties_get(ppts, "bind_ip");
-+
-+ size_t count_addr = obs_property_list_item_count(p);
-+ for (size_t i = 0; i < count_addr; i++) {
-+ const char *name = obs_property_list_item_name(p, i);
-+ const char *val = obs_property_list_item_string(p, i);
-+
-+ //Put only the addresses from the selected interface
-+ if (QT_UTF8(name).contains(
-+ ui->bindToInterface->currentText()) ||
-+ QT_UTF8(val).contains("default"))
-+ ui->bindToIP->addItem(QT_UTF8(name), val);
-+ }
-+
-+ obs_properties_destroy(ppts);
-+
-+ if (ui->bindToInterface->currentIndex() > 0) {
-+ ui->bindToIP->setEnabled(true);
-+ } else {
-+ ui->bindToIP->setEnabled(false);
-+ if (!SetComboByValue(ui->bindToIP, "default"))
-+ SetInvalidValue(ui->bindToIP, "default", "default");
-+ }
-+}
-+#endif
-diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp
-index 6c91532aec963..482699b82c42b 100644
---- a/UI/window-basic-settings.hpp
-+++ b/UI/window-basic-settings.hpp
-@@ -468,6 +468,9 @@ private slots:
- void SetHotkeysIcon(const QIcon &icon);
- void SetAccessibilityIcon(const QIcon &icon);
- void SetAdvancedIcon(const QIcon &icon);
-+#ifdef __linux__
-+ void UpdateAddrList();
-+#endif
-
- void UseStreamKeyAdvClicked();
-
diff --git a/bind_iface_eyeballed.patch b/bind_iface_eyeballed.patch
new file mode 100644
index 000000000000..f291161ec074
--- /dev/null
+++ b/bind_iface_eyeballed.patch
@@ -0,0 +1,930 @@
+From f1bf4babb6644edb60bf4850b20a41b5afa436d1 Mon Sep 17 00:00:00 2001
+From: tytan652 <tytan652@tytanium.xyz>
+Date: Thu, 14 Sep 2023 11:25:31 +0200
+Subject: [PATCH 1/5] Revert "UI: Fix IP settings order"
+
+---
+ UI/forms/OBSBasicSettings.ui | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
+index 870eea85a..14331408e 100644
+--- a/UI/forms/OBSBasicSettings.ui
++++ b/UI/forms/OBSBasicSettings.ui
+@@ -7563,30 +7563,30 @@
+ </widget>
+ </item>
+ <item row="1" column="0">
+- <widget class="QLabel" name="ipFamilyLabel">
++ <widget class="QLabel" name="bindToIPLabel">
+ <property name="text">
+- <string>Basic.Settings.Advanced.Network.IPFamily</string>
++ <string>Basic.Settings.Advanced.Network.BindToIP</string>
+ </property>
+ <property name="buddy">
+- <cstring>ipFamily</cstring>
++ <cstring>bindToIP</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+- <widget class="QComboBox" name="ipFamily"/>
++ <widget class="QComboBox" name="bindToIP"/>
+ </item>
+ <item row="2" column="0">
+- <widget class="QLabel" name="bindToIPLabel">
++ <widget class="QLabel" name="ipFamilyLabel">
+ <property name="text">
+- <string>Basic.Settings.Advanced.Network.BindToIP</string>
++ <string>Basic.Settings.Advanced.Network.IPFamily</string>
+ </property>
+ <property name="buddy">
+- <cstring>bindToIP</cstring>
++ <cstring>ipFamily</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+- <widget class="QComboBox" name="bindToIP"/>
++ <widget class="QComboBox" name="ipFamily"/>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="enableNewSocketLoop">
+--
+2.42.1
+
+
+From 526aa47027982782fefae1799274a514fc55f8f8 Mon Sep 17 00:00:00 2001
+From: tytan652 <tytan652@tytanium.xyz>
+Date: Thu, 14 Sep 2023 11:25:50 +0200
+Subject: [PATCH 2/5] Revert "UI: Add IPv4 / IPv6 selection setting"
+
+This reverts commit 488a96bc4b0c27749b1ef143ed76a71c1830fe0a.
+---
+ UI/data/locale/en-US.ini | 1 -
+ UI/forms/OBSBasicSettings.ui | 21 ++++-----------------
+ UI/window-basic-auto-config-test.cpp | 4 ----
+ UI/window-basic-main-outputs.cpp | 6 ------
+ UI/window-basic-main.cpp | 2 --
+ UI/window-basic-settings.cpp | 19 +------------------
+ 6 files changed, 5 insertions(+), 48 deletions(-)
+
+diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
+index cb35ba2b0..f1dfd16eb 100644
+--- a/UI/data/locale/en-US.ini
++++ b/UI/data/locale/en-US.ini
+@@ -1245,7 +1245,6 @@ Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
+ Basic.Settings.Advanced.Network="Network"
+ Basic.Settings.Advanced.Network.Disabled="The currently selected streaming protocol does not support changing network settings."
+ Basic.Settings.Advanced.Network.BindToIP="Bind to IP"
+-Basic.Settings.Advanced.Network.IPFamily="IP Family"
+ Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable network optimizations"
+ Basic.Settings.Advanced.Network.EnableLowLatencyMode="Enable TCP pacing"
+ Basic.Settings.Advanced.Network.TCPPacing.Tooltip="Attempts to make RTMP output friendlier to other latency sensitive applications on the network by regulating the rate of transmission.\nIt may increase the risk of dropped frames on unstable connections."
+diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
+index 14331408e..bd18c168d 100644
+--- a/UI/forms/OBSBasicSettings.ui
++++ b/UI/forms/OBSBasicSettings.ui
+@@ -7575,27 +7575,14 @@
+ <item row="1" column="1">
+ <widget class="QComboBox" name="bindToIP"/>
+ </item>
+- <item row="2" column="0">
+- <widget class="QLabel" name="ipFamilyLabel">
+- <property name="text">
+- <string>Basic.Settings.Advanced.Network.IPFamily</string>
+- </property>
+- <property name="buddy">
+- <cstring>ipFamily</cstring>
+- </property>
+- </widget>
+- </item>
+- <item row="2" column="1">
+- <widget class="QComboBox" name="ipFamily"/>
+- </item>
+- <item row="4" column="1">
++ <item row="3" column="1">
+ <widget class="QCheckBox" name="enableNewSocketLoop">
+ <property name="text">
+ <string>Basic.Settings.Advanced.Network.EnableNewSocketLoop</string>
+ </property>
+ </widget>
+ </item>
+- <item row="5" column="1">
++ <item row="4" column="1">
+ <widget class="QCheckBox" name="enableLowLatencyMode">
+ <property name="enabled">
+ <bool>false</bool>
+@@ -7605,7 +7592,7 @@
+ </property>
+ </widget>
+ </item>
+- <item row="4" column="0">
++ <item row="3" column="0">
+ <spacer name="horizontalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+@@ -7618,7 +7605,7 @@
+ </property>
+ </spacer>
+ </item>
+- <item row="3" column="1">
++ <item row="2" column="1">
+ <widget class="QCheckBox" name="dynBitrate">
+ <property name="toolTip">
+ <string>Basic.Settings.Output.DynamicBitrate.TT</string>
+diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
+index 7d7c4278e..45bf800b0 100644
+--- a/UI/window-basic-auto-config-test.cpp
++++ b/UI/window-basic-auto-config-test.cpp
+@@ -249,10 +249,6 @@ void AutoConfigTestPage::TestBandwidthThread()
+ config_get_string(main->Config(), "Output", "BindIP");
+ obs_data_set_string(output_settings, "bind_ip", bind_ip);
+
+- const char *ip_family =
+- config_get_string(main->Config(), "Output", "IPFamily");
+- obs_data_set_string(output_settings, "ip_family", ip_family);
+-
+ /* -----------------------------------*/
+ /* determine which servers to test */
+
+diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
+index c17b0d744..fa2a1e2f3 100644
+--- a/UI/window-basic-main-outputs.cpp
++++ b/UI/window-basic-main-outputs.cpp
+@@ -1206,8 +1206,6 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
+ config_get_bool(main->Config(), "Output", "DelayPreserve");
+ const char *bindIP =
+ config_get_string(main->Config(), "Output", "BindIP");
+- const char *ipFamily =
+- config_get_string(main->Config(), "Output", "IPFamily");
+ #ifdef _WIN32
+ bool enableNewSocketLoop = config_get_bool(main->Config(), "Output",
+ "NewSocketLoopEnable");
+@@ -1219,7 +1217,6 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
+
+ OBSDataAutoRelease settings = obs_data_create();
+ obs_data_set_string(settings, "bind_ip", bindIP);
+- obs_data_set_string(settings, "ip_family", ipFamily);
+ #ifdef _WIN32
+ obs_data_set_bool(settings, "new_socket_loop_enabled",
+ enableNewSocketLoop);
+@@ -2166,8 +2163,6 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
+ config_get_bool(main->Config(), "Output", "DelayPreserve");
+ const char *bindIP =
+ config_get_string(main->Config(), "Output", "BindIP");
+- const char *ipFamily =
+- config_get_string(main->Config(), "Output", "IPFamily");
+ #ifdef _WIN32
+ bool enableNewSocketLoop = config_get_bool(main->Config(), "Output",
+ "NewSocketLoopEnable");
+@@ -2179,7 +2174,6 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
+
+ OBSDataAutoRelease settings = obs_data_create();
+ obs_data_set_string(settings, "bind_ip", bindIP);
+- obs_data_set_string(settings, "ip_family", ipFamily);
+ #ifdef _WIN32
+ obs_data_set_bool(settings, "new_socket_loop_enabled",
+ enableNewSocketLoop);
+diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
+index 01e58f75b..70cd03083 100644
+--- a/UI/window-basic-main.cpp
++++ b/UI/window-basic-main.cpp
+@@ -1681,8 +1681,6 @@ bool OBSBasic::InitBasicConfigDefaults()
+ config_set_default_uint(basicConfig, "Output", "MaxRetries", 25);
+
+ config_set_default_string(basicConfig, "Output", "BindIP", "default");
+- config_set_default_string(basicConfig, "Output", "IPFamily",
+- "IPv4+IPv6");
+ config_set_default_bool(basicConfig, "Output", "NewSocketLoopEnable",
+ false);
+ config_set_default_bool(basicConfig, "Output", "LowLatencyEnable",
+diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
+index b1e6bd6fb..80c3f63a4 100644
+--- a/UI/window-basic-settings.cpp
++++ b/UI/window-basic-settings.cpp
+@@ -562,7 +562,6 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+ HookWidget(ui->processPriority, COMBO_CHANGED, ADV_CHANGED);
+ HookWidget(ui->confirmOnExit, CHECK_CHANGED, ADV_CHANGED);
+ HookWidget(ui->bindToIP, COMBO_CHANGED, ADV_CHANGED);
+- HookWidget(ui->ipFamily, COMBO_CHANGED, ADV_CHANGED);
+ HookWidget(ui->enableNewSocketLoop, CHECK_CHANGED, ADV_CHANGED);
+ HookWidget(ui->enableLowLatencyMode, CHECK_CHANGED, ADV_CHANGED);
+ HookWidget(ui->hotkeyFocusType, COMBO_CHANGED, ADV_CHANGED);
+@@ -831,17 +830,6 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+ ui->bindToIP->addItem(QT_UTF8(name), val);
+ }
+
+- // Add IP Family options
+- p = obs_properties_get(ppts, "ip_family");
+-
+- count = obs_property_list_item_count(p);
+- for (size_t i = 0; i < count; i++) {
+- const char *name = obs_property_list_item_name(p, i);
+- const char *val = obs_property_list_item_string(p, i);
+-
+- ui->ipFamily->addItem(QT_UTF8(name), val);
+- }
+-
+ obs_properties_destroy(ppts);
+
+ InitStreamPage();
+@@ -2840,8 +2828,7 @@ void OBSBasicSettings::LoadAdvancedSettings()
+ App()->GlobalConfig(), "General", "HotkeyFocusType");
+ bool dynBitrate =
+ config_get_bool(main->Config(), "Output", "DynamicBitrate");
+- const char *ipFamily =
+- config_get_string(main->Config(), "Output", "IPFamily");
++
+ bool confirmOnExit =
+ config_get_bool(GetGlobalConfig(), "General", "ConfirmOnExit");
+
+@@ -2881,7 +2868,6 @@ void OBSBasicSettings::LoadAdvancedSettings()
+ ui->sdrWhiteLevel->setValue(sdrWhiteLevel);
+ ui->hdrNominalPeakLevel->setValue(hdrNominalPeakLevel);
+
+- SetComboByValue(ui->ipFamily, ipFamily);
+ if (!SetComboByValue(ui->bindToIP, bindIP))
+ SetInvalidValue(ui->bindToIP, bindIP, bindIP);
+
+@@ -3615,7 +3601,6 @@ void OBSBasicSettings::SaveAdvancedSettings()
+ SaveSpinBox(ui->reconnectRetryDelay, "Output", "RetryDelay");
+ SaveSpinBox(ui->reconnectMaxRetries, "Output", "MaxRetries");
+ SaveComboData(ui->bindToIP, "Output", "BindIP");
+- SaveComboData(ui->ipFamily, "Output", "IPFamily");
+ SaveCheckBox(ui->autoRemux, "Video", "AutoRemux");
+ SaveCheckBox(ui->dynBitrate, "Output", "DynamicBitrate");
+
+@@ -6166,8 +6151,6 @@ void OBSBasicSettings::UpdateAdvNetworkGroup()
+ ui->bindToIPLabel->setVisible(enabled);
+ ui->bindToIP->setVisible(enabled);
+ ui->dynBitrate->setVisible(enabled);
+- ui->ipFamilyLabel->setVisible(enabled);
+- ui->ipFamily->setVisible(enabled);
+ #ifdef _WIN32
+ ui->enableNewSocketLoop->setVisible(enabled);
+ ui->enableLowLatencyMode->setVisible(enabled);
+--
+2.42.1
+
+
+From dda9f089ef93971d48a309a2c88726d837ffc89c Mon Sep 17 00:00:00 2001
+From: tytan652 <tytan652@tytanium.xyz>
+Date: Thu, 11 Feb 2021 14:29:08 +0100
+Subject: [PATCH 3/5] happy-eyeballs,librtmp: Add interface binding for Linux
+
+---
+ deps/happy-eyeballs/happy-eyeballs.c | 39 ++++++++++++++++++++++++++--
+ deps/happy-eyeballs/happy-eyeballs.h | 10 +++++++
+ plugins/obs-outputs/librtmp/rtmp.c | 3 +++
+ plugins/obs-outputs/librtmp/rtmp.h | 1 +
+ 4 files changed, 51 insertions(+), 2 deletions(-)
+
+diff --git a/deps/happy-eyeballs/happy-eyeballs.c b/deps/happy-eyeballs/happy-eyeballs.c
+index 0ed15376b..3a3828743 100644
+--- a/deps/happy-eyeballs/happy-eyeballs.c
++++ b/deps/happy-eyeballs/happy-eyeballs.c
+@@ -101,12 +101,22 @@ struct happy_eyeballs_ctx {
+ const char *error_message;
+
+ /**
+- * Set along with bind_addr to hint which interface to use.
++ * Set along with bind_iface to hint which interface to use.
++ */
++ int bind_iface_len;
++
++ /**
++ * Set along with bind_iface_len to hint which interface to use.
++ */
++ char *bind_iface;
++
++ /**
++ * Set along with bind_addr to hint which address to use.
+ */
+ socklen_t bind_addr_len;
+
+ /**
+- * Set along with bind_addr_len to hint which interface to use.
++ * Set along with bind_addr_len to hint which address to use.
+ */
+ struct sockaddr_storage bind_addr;
+
+@@ -349,6 +359,14 @@ static void *happy_connect_worker(void *arg)
+ setsockopt(args->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1},
+ sizeof(int));
+ #endif
++
++#ifdef __linux__
++ if (setsockopt(args->sockfd, SOL_SOCKET, SO_BINDTODEVICE,
++ context->bind_iface, context->bind_iface_len) < 0) {
++ goto failure;
++ }
++#endif
++
+ if (context->bind_addr.ss_family != 0 &&
+ bind(args->sockfd, (const struct sockaddr *)&context->bind_addr,
+ context->bind_addr_len) < 0) {
+@@ -696,6 +714,7 @@ int happy_eyeballs_destroy(struct happy_eyeballs_ctx *context)
+ freeaddrinfo(context->addresses);
+
+ da_free(context->candidates);
++ bfree(context->bind_iface);
+ free(context);
+ return STATUS_SUCCESS;
+ }
+@@ -703,6 +722,22 @@ int happy_eyeballs_destroy(struct happy_eyeballs_ctx *context)
+ /* ------------------------------------------------------------------------- */
+ /* Setters & Getters */
+
++int happy_eyeballs_set_bind_iface(struct happy_eyeballs_ctx *context,
++ int iface_len, const char *iface)
++{
++ if (!context)
++ return STATUS_INVALID_ARGUMENT;
++
++ if (iface && iface_len > 0) {
++ context->bind_iface = bstrdup(iface);
++ context->bind_iface_len = iface_len;
++ } else {
++ context->bind_iface_len = 0;
++ context->bind_iface = NULL;
++ }
++ return STATUS_SUCCESS;
++}
++
+ int happy_eyeballs_set_bind_addr(struct happy_eyeballs_ctx *context,
+ socklen_t addr_len,
+ struct sockaddr_storage *addr_storage)
+diff --git a/deps/happy-eyeballs/happy-eyeballs.h b/deps/happy-eyeballs/happy-eyeballs.h
+index 3ef62e2de..b939868db 100644
+--- a/deps/happy-eyeballs/happy-eyeballs.h
++++ b/deps/happy-eyeballs/happy-eyeballs.h
+@@ -82,6 +82,16 @@ int happy_eyeballs_create(struct happy_eyeballs_ctx **context);
+ int happy_eyeballs_connect(struct happy_eyeballs_ctx *context,
+ const char *hostname, int port);
+
++/**
++ * Optionally set the interface. You may pass 0 and NULL for these
++ * parameters, respectively, to clear this setting. This must be called before
++ * happy_eyeballs_connect.
++ *
++ * Returns 0 on success or -EINVAL if context is not set.
++ */
++int happy_eyeballs_set_bind_iface(struct happy_eyeballs_ctx *context,
++ int iface_len, const char *iface);
++
+ /**
+ * Optionally set the interface address. You may pass 0 and NULL for these
+ * parameters, respectively, to clear this setting. This must be called before
+diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c
+index cfc7288a0..ed844243e 100644
+--- a/plugins/obs-outputs/librtmp/rtmp.c
++++ b/plugins/obs-outputs/librtmp/rtmp.c
+@@ -1063,6 +1063,9 @@ RTMP_Connect(RTMP *r, RTMPPacket *cp)
+ port = r->Link.port;
+ }
+
++ /* Set local bind interface (if present) */
++ happy_eyeballs_set_bind_iface(happy_ctx, r->m_bindInterface.av_len, r->m_bindInterface.av_val);
++
+ /* Set local bind address (if present) */
+ happy_eyeballs_set_bind_addr(happy_ctx, r->m_bindIP.addrLen, &r->m_bindIP.addr);
+
+diff --git a/plugins/obs-outputs/librtmp/rtmp.h b/plugins/obs-outputs/librtmp/rtmp.h
+index d1cddd412..a1fd60550 100644
+--- a/plugins/obs-outputs/librtmp/rtmp.h
++++ b/plugins/obs-outputs/librtmp/rtmp.h
+@@ -421,6 +421,7 @@ extern "C"
+ void* m_customSendParam;
+ CUSTOMSEND m_customSendFunc;
+
++ AVal m_bindInterface;
+ RTMP_BINDINFO m_bindIP;
+
+ uint8_t m_bSendChunkSizeInfo;
+--
+2.42.1
+
+
+From 73812df599e626a93f5c56d3fab7e1affd5297c0 Mon Sep 17 00:00:00 2001
+From: tytan652 <tytan652@tytanium.xyz>
+Date: Thu, 11 Feb 2021 14:47:45 +0100
+Subject: [PATCH 4/5] obs-outputs: Add RTMP iface binding for Linux
+
+---
+ plugins/obs-outputs/net-if.c | 32 +++++++++++++++++++++++++++++
+ plugins/obs-outputs/net-if.h | 15 ++++++++++++++
+ plugins/obs-outputs/rtmp-stream.c | 34 +++++++++++++++++++++++++++++++
+ plugins/obs-outputs/rtmp-stream.h | 2 ++
+ 4 files changed, 83 insertions(+)
+
+diff --git a/plugins/obs-outputs/net-if.c b/plugins/obs-outputs/net-if.c
+index 6ffb2679a..ae89ffed4 100644
+--- a/plugins/obs-outputs/net-if.c
++++ b/plugins/obs-outputs/net-if.c
+@@ -154,6 +154,38 @@ static inline bool is_loopback(struct ifaddrs *ifa)
+ return n && (strcmp(n, "lo") == 0 || strcmp(n, "lo0") == 0);
+ }
+
++#ifdef __linux__
++void netif_get_ifaces(struct netif_siface_data *ifaces)
++{
++ da_init(ifaces->ifaces);
++
++ struct ifaddrs *ifaddr, *ifa;
++ unsigned int family;
++
++ if (getifaddrs(&ifaddr) == -1) {
++ warn("getifaddrs() failed");
++ return;
++ }
++
++ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
++ if (ifa->ifa_addr == NULL || is_loopback(ifa))
++ continue;
++ family = ifa->ifa_addr->sa_family;
++
++ if ((family == AF_INET) || (family == AF_INET6)) {
++ char *item;
++ char *iface_dup = bstrdup(ifa->ifa_name);
++
++ item = iface_dup;
++
++ da_push_back(ifaces->ifaces, &item);
++ }
++ }
++
++ freeifaddrs(ifaddr);
++}
++#endif
++
+ static inline void netif_get_addrs_nix(struct netif_saddr_data *ifaddrs)
+ {
+ struct ifaddrs *ifaddr, *ifa;
+diff --git a/plugins/obs-outputs/net-if.h b/plugins/obs-outputs/net-if.h
+index fe30eb7f2..68a334d4e 100644
+--- a/plugins/obs-outputs/net-if.h
++++ b/plugins/obs-outputs/net-if.h
+@@ -53,6 +53,21 @@
+
+ #endif
+
++#ifdef __linux__
++struct netif_siface_data {
++ DARRAY(char *) ifaces;
++};
++
++static inline void netif_siface_data_free(struct netif_siface_data *data)
++{
++ for (size_t i = 0; i < data->ifaces.num; i++)
++ bfree(data->ifaces.array[i]);
++ da_free(data->ifaces);
++}
++
++extern void netif_get_ifaces(struct netif_siface_data *ifaces);
++#endif
++
+ struct netif_saddr_item {
+ char *name;
+ char *addr;
+diff --git a/plugins/obs-outputs/rtmp-stream.c b/plugins/obs-outputs/rtmp-stream.c
+index dab8cdd27..654720c7c 100644
+--- a/plugins/obs-outputs/rtmp-stream.c
++++ b/plugins/obs-outputs/rtmp-stream.c
+@@ -126,6 +126,7 @@ static void rtmp_stream_destroy(void *data)
+ dstr_free(&stream->username);
+ dstr_free(&stream->password);
+ dstr_free(&stream->encoder_name);
++ dstr_free(&stream->bind_interface);
+ dstr_free(&stream->bind_ip);
+ os_event_destroy(stream->stop_event);
+ os_sem_destroy(stream->send_sem);
+@@ -1185,6 +1186,17 @@ static int try_connect(struct rtmp_stream *stream)
+ set_rtmp_dstr(&stream->rtmp.Link.flashVer, &stream->encoder_name);
+ stream->rtmp.Link.swfUrl = stream->rtmp.Link.tcUrl;
+
++ if (dstr_is_empty(&stream->bind_interface) ||
++ dstr_cmp(&stream->bind_interface, "default") == 0) {
++ memset(&stream->rtmp.m_bindInterface, 0,
++ sizeof(stream->rtmp.m_bindInterface));
++ } else {
++ set_rtmp_dstr(&stream->rtmp.m_bindInterface,
++ &stream->bind_interface);
++ info("Binding to interface %s",
++ stream->rtmp.m_bindInterface.av_val);
++ }
++
+ if (dstr_is_empty(&stream->bind_ip) ||
+ dstr_cmp(&stream->bind_ip, "default") == 0) {
+ memset(&stream->rtmp.m_bindIP, 0,
+@@ -1235,6 +1247,7 @@ static bool init_connect(struct rtmp_stream *stream)
+ {
+ obs_service_t *service;
+ obs_data_t *settings;
++ const char *bind_interface;
+ const char *bind_ip;
+ const char *ip_family;
+ int64_t drop_p;
+@@ -1320,6 +1333,9 @@ static bool init_connect(struct rtmp_stream *stream)
+ stream->drop_threshold_usec = 1000 * drop_b;
+ stream->pframe_drop_threshold_usec = 1000 * drop_p;
+
++ bind_interface = obs_data_get_string(settings, OPT_BIND_INTERFACE);
++ dstr_copy(&stream->bind_interface, bind_interface);
++
+ bind_ip = obs_data_get_string(settings, OPT_BIND_IP);
+ dstr_copy(&stream->bind_ip, bind_ip);
+
+@@ -1740,6 +1756,9 @@ static obs_properties_t *rtmp_stream_properties(void *unused)
+ UNUSED_PARAMETER(unused);
+
+ obs_properties_t *props = obs_properties_create();
++#ifdef __linux__
++ struct netif_siface_data ifaces = {0};
++#endif
+ struct netif_saddr_data addrs = {0};
+ obs_property_t *p;
+
+@@ -1747,6 +1766,21 @@ static obs_properties_t *rtmp_stream_properties(void *unused)
+ obs_module_text("RTMPStream.DropThreshold"),
+ 200, 10000, 100);
+ obs_property_int_set_suffix(p, " ms");
++#ifdef __linux__
++ p = obs_properties_add_list(props, OPT_BIND_INTERFACE,
++ obs_module_text("RTMPStream.BindInterface"),
++ OBS_COMBO_TYPE_LIST,
++ OBS_COMBO_FORMAT_STRING);
++
++ obs_property_list_add_string(p, obs_module_text("Default"), "default");
++
++ netif_get_ifaces(&ifaces);
++ for (size_t i = 0; i < ifaces.ifaces.num; i++) {
++ char *item = ifaces.ifaces.array[i];
++ obs_property_list_add_string(p, item, item);
++ }
++ netif_siface_data_free(&ifaces);
++#endif
+
+ p = obs_properties_add_list(props, OPT_IP_FAMILY,
+ obs_module_text("IPFamily"),
+diff --git a/plugins/obs-outputs/rtmp-stream.h b/plugins/obs-outputs/rtmp-stream.h
+index c570ccb77..9b81ccef2 100644
+--- a/plugins/obs-outputs/rtmp-stream.h
++++ b/plugins/obs-outputs/rtmp-stream.h
+@@ -27,6 +27,7 @@
+ #define OPT_DROP_THRESHOLD "drop_threshold_ms"
+ #define OPT_PFRAME_DROP_THRESHOLD "pframe_drop_threshold_ms"
+ #define OPT_MAX_SHUTDOWN_TIME_SEC "max_shutdown_time_sec"
++#define OPT_BIND_INTERFACE "bind_interface"
+ #define OPT_BIND_IP "bind_ip"
+ #define OPT_IP_FAMILY "ip_family"
+ #define OPT_NEWSOCKETLOOP_ENABLED "new_socket_loop_enabled"
+@@ -81,6 +82,7 @@ struct rtmp_stream {
+ struct dstr path, key;
+ struct dstr username, password;
+ struct dstr encoder_name;
++ struct dstr bind_interface;
+ struct dstr bind_ip;
+ socklen_t addrlen_hint; /* hint IPv4 vs IPv6 */
+
+--
+2.42.1
+
+
+From 006b2f8300154cc8fbf6688148049dc74b39d00e Mon Sep 17 00:00:00 2001
+From: tytan652 <tytan652@tytanium.xyz>
+Date: Thu, 11 Feb 2021 14:51:42 +0100
+Subject: [PATCH 5/5] UI: Add interface binding property for Linux
+
+---
+ UI/data/locale/en-US.ini | 1 +
+ UI/forms/OBSBasicSettings.ui | 24 ++++++--
+ UI/window-basic-auto-config-test.cpp | 3 +
+ UI/window-basic-main-outputs.cpp | 6 ++
+ UI/window-basic-main.cpp | 2 +
+ UI/window-basic-settings.cpp | 91 +++++++++++++++++++++++++++-
+ UI/window-basic-settings.hpp | 3 +
+ 7 files changed, 123 insertions(+), 7 deletions(-)
+
+diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
+index f1dfd16eb..6a7e21362 100644
+--- a/UI/data/locale/en-US.ini
++++ b/UI/data/locale/en-US.ini
+@@ -1244,6 +1244,7 @@ Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase de
+ Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
+ Basic.Settings.Advanced.Network="Network"
+ Basic.Settings.Advanced.Network.Disabled="The currently selected streaming protocol does not support changing network settings."
++Basic.Settings.Advanced.Network.BindToInterface="Bind to interface"
+ Basic.Settings.Advanced.Network.BindToIP="Bind to IP"
+ Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable network optimizations"
+ Basic.Settings.Advanced.Network.EnableLowLatencyMode="Enable TCP pacing"
+diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
+index bd18c168d..98dd5d486 100644
+--- a/UI/forms/OBSBasicSettings.ui
++++ b/UI/forms/OBSBasicSettings.ui
+@@ -7563,6 +7563,19 @@
+ </widget>
+ </item>
+ <item row="1" column="0">
++ <widget class="QLabel" name="bindToIfaceLabel">
++ <property name="text">
++ <string>Basic.Settings.Advanced.Network.BindToInterface</string>
++ </property>
++ <property name="buddy">
++ <cstring>bindToInterface</cstring>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QComboBox" name="bindToInterface"/>
++ </item>
++ <item row="2" column="0">
+ <widget class="QLabel" name="bindToIPLabel">
+ <property name="text">
+ <string>Basic.Settings.Advanced.Network.BindToIP</string>
+@@ -7572,17 +7585,17 @@
+ </property>
+ </widget>
+ </item>
+- <item row="1" column="1">
++ <item row="2" column="1">
+ <widget class="QComboBox" name="bindToIP"/>
+ </item>
+- <item row="3" column="1">
++ <item row="4" column="1">
+ <widget class="QCheckBox" name="enableNewSocketLoop">
+ <property name="text">
+ <string>Basic.Settings.Advanced.Network.EnableNewSocketLoop</string>
+ </property>
+ </widget>
+ </item>
+- <item row="4" column="1">
++ <item row="5" column="1">
+ <widget class="QCheckBox" name="enableLowLatencyMode">
+ <property name="enabled">
+ <bool>false</bool>
+@@ -7592,7 +7605,7 @@
+ </property>
+ </widget>
+ </item>
+- <item row="3" column="0">
++ <item row="4" column="0">
+ <spacer name="horizontalSpacer_7">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+@@ -7605,7 +7618,7 @@
+ </property>
+ </spacer>
+ </item>
+- <item row="2" column="1">
++ <item row="3" column="1">
+ <widget class="QCheckBox" name="dynBitrate">
+ <property name="toolTip">
+ <string>Basic.Settings.Output.DynamicBitrate.TT</string>
+@@ -7934,6 +7947,7 @@
+ <tabstop>reconnectRetryDelay</tabstop>
+ <tabstop>reconnectMaxRetries</tabstop>
+ <tabstop>bindToIP</tabstop>
++ <tabstop>bindToInterface</tabstop>
+ <tabstop>dynBitrate</tabstop>
+ <tabstop>enableNewSocketLoop</tabstop>
+ <tabstop>enableLowLatencyMode</tabstop>
+diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp
+index 45bf800b0..a7a87ab40 100644
+--- a/UI/window-basic-auto-config-test.cpp
++++ b/UI/window-basic-auto-config-test.cpp
+@@ -245,6 +245,9 @@ void AutoConfigTestPage::TestBandwidthThread()
+ obs_data_set_int(aencoder_settings, "bitrate", 32);
+
+ OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
++ const char *bind_interface =
++ config_get_string(main->Config(), "Output", "BindInterface");
++ obs_data_set_string(output_settings, "bind_interface", bind_interface);
+ const char *bind_ip =
+ config_get_string(main->Config(), "Output", "BindIP");
+ obs_data_set_string(output_settings, "bind_ip", bind_ip);
+diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
+index fa2a1e2f3..d02dbd65d 100644
+--- a/UI/window-basic-main-outputs.cpp
++++ b/UI/window-basic-main-outputs.cpp
+@@ -1204,6 +1204,8 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
+ int delaySec = config_get_int(main->Config(), "Output", "DelaySec");
+ bool preserveDelay =
+ config_get_bool(main->Config(), "Output", "DelayPreserve");
++ const char *bindInterface =
++ config_get_string(main->Config(), "Output", "BindInterface");
+ const char *bindIP =
+ config_get_string(main->Config(), "Output", "BindIP");
+ #ifdef _WIN32
+@@ -1216,6 +1218,7 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
+ config_get_bool(main->Config(), "Output", "DynamicBitrate");
+
+ OBSDataAutoRelease settings = obs_data_create();
++ obs_data_set_string(settings, "bind_interface", bindInterface);
+ obs_data_set_string(settings, "bind_ip", bindIP);
+ #ifdef _WIN32
+ obs_data_set_bool(settings, "new_socket_loop_enabled",
+@@ -2161,6 +2164,8 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
+ int delaySec = config_get_int(main->Config(), "Output", "DelaySec");
+ bool preserveDelay =
+ config_get_bool(main->Config(), "Output", "DelayPreserve");
++ const char *bindInterface =
++ config_get_string(main->Config(), "Output", "BindInterface");
+ const char *bindIP =
+ config_get_string(main->Config(), "Output", "BindIP");
+ #ifdef _WIN32
+@@ -2173,6 +2178,7 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
+ config_get_bool(main->Config(), "Output", "DynamicBitrate");
+
+ OBSDataAutoRelease settings = obs_data_create();
++ obs_data_set_string(settings, "bind_interface", bindInterface);
+ obs_data_set_string(settings, "bind_ip", bindIP);
+ #ifdef _WIN32
+ obs_data_set_bool(settings, "new_socket_loop_enabled",
+diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
+index 70cd03083..50296a5d6 100644
+--- a/UI/window-basic-main.cpp
++++ b/UI/window-basic-main.cpp
+@@ -1680,6 +1680,8 @@ bool OBSBasic::InitBasicConfigDefaults()
+ config_set_default_uint(basicConfig, "Output", "RetryDelay", 2);
+ config_set_default_uint(basicConfig, "Output", "MaxRetries", 25);
+
++ config_set_default_string(basicConfig, "Output", "BindInterface",
++ "default");
+ config_set_default_string(basicConfig, "Output", "BindIP", "default");
+ config_set_default_bool(basicConfig, "Output", "NewSocketLoopEnable",
+ false);
+diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
+index 80c3f63a4..42c832680 100644
+--- a/UI/window-basic-settings.cpp
++++ b/UI/window-basic-settings.cpp
+@@ -561,6 +561,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+ HookWidget(ui->reconnectMaxRetries, SCROLL_CHANGED, ADV_CHANGED);
+ HookWidget(ui->processPriority, COMBO_CHANGED, ADV_CHANGED);
+ HookWidget(ui->confirmOnExit, CHECK_CHANGED, ADV_CHANGED);
++#ifdef __linux__
++ HookWidget(ui->bindToInterface, COMBO_CHANGED, ADV_CHANGED);
++#endif
+ HookWidget(ui->bindToIP, COMBO_CHANGED, ADV_CHANGED);
+ HookWidget(ui->enableNewSocketLoop, CHECK_CHANGED, ADV_CHANGED);
+ HookWidget(ui->enableLowLatencyMode, CHECK_CHANGED, ADV_CHANGED);
+@@ -669,6 +672,13 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+ ui->resetOSXVSync = nullptr;
+ #endif
+
++#ifndef __linux__
++ delete ui->bindToIfaceLabel;
++ delete ui->bindToInterface;
++ ui->bindToIfaceLabel = nullptr;
++ ui->bindToInterface = nullptr;
++#endif
++
+ connect(ui->streamDelaySec, &QSpinBox::valueChanged, this,
+ &OBSBasicSettings::UpdateStreamDelayEstimate);
+ connect(ui->outputMode, &QComboBox::currentIndexChanged, this,
+@@ -817,9 +827,37 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+ &OBSBasicSettings::AdvReplayBufferChanged);
+ connect(ui->advRBSecMax, &QSpinBox::valueChanged, this,
+ &OBSBasicSettings::AdvReplayBufferChanged);
++#ifdef __linux__
++ connect(ui->bindToInterface, &QComboBox::currentIndexChanged, this,
++ &OBSBasicSettings::UpdateAddrList);
+
+- // Get Bind to IP Addresses
++ ui->bindToIP->setEnabled(false);
++#endif
++
++ // Get Bind to interfaces Interfaces (Linux only)
++ // Get Bind to IP Addresses (Others)
+ obs_properties_t *ppts = obs_get_output_properties("rtmp_output");
++#ifdef __linux__
++ obs_property_t *p_iface = obs_properties_get(ppts, "bind_interface");
++ QStringList dedup_iface = {};
++
++ ui->bindToInterface->blockSignals(true);
++
++ size_t count_iface = obs_property_list_item_count(p_iface);
++ for (size_t i = 0; i < count_iface; i++) {
++ const char *name = obs_property_list_item_name(p_iface, i);
++ const char *val = obs_property_list_item_string(p_iface, i);
++
++ // Add interfaces without duplicates
++ if (!dedup_iface.contains(QT_UTF8(name))) {
++ dedup_iface.append(QT_UTF8(name));
++ ui->bindToInterface->addItem(QT_UTF8(name), val);
++ }
++ }
++
++ UpdateAddrList();
++ ui->bindToInterface->blockSignals(false);
++#else
+ obs_property_t *p = obs_properties_get(ppts, "bind_ip");
+
+ size_t count = obs_property_list_item_count(p);
+@@ -829,7 +867,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
+
+ ui->bindToIP->addItem(QT_UTF8(name), val);
+ }
+-
++#endif
+ obs_properties_destroy(ppts);
+
+ InitStreamPage();
+@@ -2814,6 +2852,10 @@ void OBSBasicSettings::LoadAdvancedSettings()
+ "FilenameFormatting");
+ bool overwriteIfExists =
+ config_get_bool(main->Config(), "Output", "OverwriteIfExists");
++#ifdef __linux__
++ const char *bindInterface =
++ config_get_string(main->Config(), "Output", "BindInterface");
++#endif
+ const char *bindIP =
+ config_get_string(main->Config(), "Output", "BindIP");
+ const char *rbPrefix = config_get_string(main->Config(), "SimpleOutput",
+@@ -2868,6 +2910,12 @@ void OBSBasicSettings::LoadAdvancedSettings()
+ ui->sdrWhiteLevel->setValue(sdrWhiteLevel);
+ ui->hdrNominalPeakLevel->setValue(hdrNominalPeakLevel);
+
++#ifdef __linux__
++ if (!SetComboByValue(ui->bindToInterface, bindInterface))
++ SetInvalidValue(ui->bindToInterface, bindInterface,
++ bindInterface);
++#endif
++
+ if (!SetComboByValue(ui->bindToIP, bindIP))
+ SetInvalidValue(ui->bindToIP, bindIP, bindIP);
+
+@@ -3600,6 +3648,9 @@ void OBSBasicSettings::SaveAdvancedSettings()
+ SaveCheckBox(ui->reconnectEnable, "Output", "Reconnect");
+ SaveSpinBox(ui->reconnectRetryDelay, "Output", "RetryDelay");
+ SaveSpinBox(ui->reconnectMaxRetries, "Output", "MaxRetries");
++#ifdef __linux__
++ SaveComboData(ui->bindToInterface, "Output", "BindInterface");
++#endif
+ SaveComboData(ui->bindToIP, "Output", "BindIP");
+ SaveCheckBox(ui->autoRemux, "Video", "AutoRemux");
+ SaveCheckBox(ui->dynBitrate, "Output", "DynamicBitrate");
+@@ -6154,6 +6205,9 @@ void OBSBasicSettings::UpdateAdvNetworkGroup()
+ #ifdef _WIN32
+ ui->enableNewSocketLoop->setVisible(enabled);
+ ui->enableLowLatencyMode->setVisible(enabled);
++#elif defined(__linux__)
++ ui->bindToIfaceLabel->setVisible(enabled);
++ ui->bindToInterface->setVisible(enabled);
+ #endif
+ }
+
+@@ -6192,3 +6246,36 @@ void OBSBasicSettings::AdvAudioEncodersChanged()
+ ui->advOutTrack6Bitrate},
+ 320);
+ }
++
++#ifdef __linux__
++void OBSBasicSettings::UpdateAddrList()
++{
++ ui->bindToIP->clear();
++
++ // Get Bind to IP Addresses (Linux only)
++ obs_properties_t *ppts = obs_get_output_properties("rtmp_output");
++ obs_property_t *p = obs_properties_get(ppts, "bind_ip");
++
++ size_t count_addr = obs_property_list_item_count(p);
++ for (size_t i = 0; i < count_addr; i++) {
++ const char *name = obs_property_list_item_name(p, i);
++ const char *val = obs_property_list_item_string(p, i);
++
++ //Put only the addresses from the selected interface
++ if (QT_UTF8(name).contains(
++ ui->bindToInterface->currentText()) ||
++ QT_UTF8(val).contains("default"))
++ ui->bindToIP->addItem(QT_UTF8(name), val);
++ }
++
++ obs_properties_destroy(ppts);
++
++ if (ui->bindToInterface->currentIndex() > 0) {
++ ui->bindToIP->setEnabled(true);
++ } else {
++ ui->bindToIP->setEnabled(false);
++ if (!SetComboByValue(ui->bindToIP, "default"))
++ SetInvalidValue(ui->bindToIP, "default", "default");
++ }
++}
++#endif
+diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp
+index b874c0b85..b7d4baae7 100644
+--- a/UI/window-basic-settings.hpp
++++ b/UI/window-basic-settings.hpp
+@@ -466,6 +466,9 @@ private slots:
+ void SetHotkeysIcon(const QIcon &icon);
+ void SetAccessibilityIcon(const QIcon &icon);
+ void SetAdvancedIcon(const QIcon &icon);
++#ifdef __linux__
++ void UpdateAddrList();
++#endif
+
+ void UseStreamKeyAdvClicked();
+
+--
+2.42.1
+