diff options
author | tytan652 | 2023-11-12 01:18:00 +0100 |
---|---|---|
committer | tytan652 | 2023-11-12 01:18:00 +0100 |
commit | 0a8a227566dd9a9d91cbf716766d8b9ccc329173 (patch) | |
tree | e37f03d727eb89b283fdada3a351c20561781599 | |
parent | 7081490079b34bcc7a82ba77d7f190a98975fd9a (diff) | |
download | aur-0a8a227566dd9a9d91cbf716766d8b9ccc329173.tar.gz |
build: Update to 30.0.0
-rw-r--r-- | .SRCINFO | 31 | ||||
-rw-r--r-- | 0002-Use_system_uthash.patch | 47 | ||||
-rw-r--r-- | PKGBUILD | 47 | ||||
-rw-r--r-- | bind_iface.patch | 576 | ||||
-rw-r--r-- | bind_iface_eyeballed.patch | 930 |
5 files changed, 990 insertions, 641 deletions
@@ -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 - @@ -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 + |