From 97e0df01b13af7eff00a0510751f2165e57c8298 Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Sat, 9 May 2026 09:48:40 +0200 Subject: [PATCH] move datachannel to libraries and follow datachannel conventions (#1090) * move datachannel to libraries and follow new datachannel_module convention * move datachannel to libraries and follow new datachannel_module convention --- .gitignore | 1 + facefusion/{ => libraries}/datachannel.py | 32 +++++++++++------------ facefusion/rtc.py | 24 ++++++++--------- tests/stream_helper.py | 3 ++- tests/test_rtc.py | 11 ++++---- 5 files changed, 36 insertions(+), 35 deletions(-) rename facefusion/{ => libraries}/datachannel.py (83%) diff --git a/.gitignore b/.gitignore index ed7bab3f..5cee88dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ __pycache__ .assets +.binaries .claude .caches .idea diff --git a/facefusion/datachannel.py b/facefusion/libraries/datachannel.py similarity index 83% rename from facefusion/datachannel.py rename to facefusion/libraries/datachannel.py index b77623be..e24f18b8 100644 --- a/facefusion/datachannel.py +++ b/facefusion/libraries/datachannel.py @@ -6,12 +6,10 @@ from facefusion.common_helper import is_linux, is_macos, is_windows from facefusion.filesystem import resolve_relative_path from facefusion.types import DownloadSet -LOG_CB_TYPE = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) - @lru_cache -def create_static_download_set() -> Dict[str, DownloadSet]: # TODO: replace once conda package is in place - binary_name = resolve_binary_file() +def create_static_library_set() -> Dict[str, DownloadSet]: + library_file = resolve_library_file() return\ { @@ -19,22 +17,22 @@ def create_static_download_set() -> Dict[str, DownloadSet]: # TODO: replace once { 'datachannel': { - 'url': 'https://huggingface.co/bluefoxcreation/libdatachannel/resolve/main/linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so.hash', # TODO: use url with dynamic binary_name - 'path': resolve_relative_path('../.assets/binaries/' + binary_name + '.hash') + 'url': 'https://huggingface.co/bluefoxcreation/libdatachannel/resolve/main/linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so.hash', + 'path': resolve_relative_path('../.binaries/' + library_file + '.hash') } }, 'sources': { 'datachannel': { - 'url': 'https://huggingface.co/bluefoxcreation/libdatachannel/resolve/main/linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so', # TODO: use url with dynamic binary_name - 'path': resolve_relative_path('../.assets/binaries/' + binary_name) + 'url': 'https://huggingface.co/bluefoxcreation/libdatachannel/resolve/main/linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so', + 'path': resolve_relative_path('../.binaries/' + library_file) } } } -def resolve_binary_file() -> Optional[str]: +def resolve_library_file() -> Optional[str]: if is_linux(): return 'linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so' if is_macos(): @@ -44,7 +42,7 @@ def resolve_binary_file() -> Optional[str]: return None -def create_rtc_configuration() -> ctypes.Structure: +def define_rtc_configuration() -> ctypes.Structure: return type('RTC_CONFIGURATION', (ctypes.Structure,), { '_fields_': @@ -67,7 +65,7 @@ def create_rtc_configuration() -> ctypes.Structure: })() -def create_rtc_packetizer_init() -> ctypes.Structure: +def define_rtc_packetizer_init() -> ctypes.Structure: return type('RTC_PACKETIZER_INIT', (ctypes.Structure,), { '_fields_': @@ -84,20 +82,20 @@ def create_rtc_packetizer_init() -> ctypes.Structure: @lru_cache -def create_static_datachannel_library() -> Optional[ctypes.CDLL]: - binary_path = create_static_download_set().get('sources').get('datachannel').get('path') +def create_static_library() -> Optional[ctypes.CDLL]: + library_path = create_static_library_set().get('sources').get('datachannel').get('path') - if binary_path: - datachannel_library = ctypes.CDLL(binary_path) + if library_path: + datachannel_library = ctypes.CDLL(library_path) return init_ctypes(datachannel_library) return None def init_ctypes(datachannel_library : ctypes.CDLL) -> ctypes.CDLL: - datachannel_library.rtcInitLogger.argtypes = [ ctypes.c_int, LOG_CB_TYPE ] + datachannel_library.rtcInitLogger.argtypes = [ ctypes.c_int, ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p) ] datachannel_library.rtcInitLogger.restype = None - datachannel_library.rtcInitLogger(4, LOG_CB_TYPE(0)) + datachannel_library.rtcInitLogger(4, ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)(0)) datachannel_library.rtcCreatePeerConnection.restype = ctypes.c_int diff --git a/facefusion/rtc.py b/facefusion/rtc.py index 6a8dbf85..505e97c0 100644 --- a/facefusion/rtc.py +++ b/facefusion/rtc.py @@ -3,13 +3,13 @@ import threading import time from typing import List, Optional -from facefusion.datachannel import create_rtc_configuration, create_rtc_packetizer_init, create_static_datachannel_library, create_static_download_set from facefusion.download import conditional_download_hashes, conditional_download_sources +from facefusion.libraries import datachannel as datachannel_module from facefusion.types import MediaDirection, PeerConnection, RtcAudioTrack, RtcPeer, RtcVideoTrack, SdpAnswer, SdpOffer def pre_check() -> bool: - download_set = create_static_download_set() + download_set = datachannel_module.create_static_library_set() if not conditional_download_hashes(download_set.get('hashes')): return False @@ -30,8 +30,8 @@ def create_peer_connection( max_packet_size : int = 0, max_message_size : int = 0) -> PeerConnection: - datachannel_library = create_static_datachannel_library() - rtc_configuration = create_rtc_configuration() + datachannel_library = datachannel_module.create_static_library() + rtc_configuration = datachannel_module.define_rtc_configuration() rtc_configuration.iceServers = ice_servers rtc_configuration.iceServersCount = ice_servers_count @@ -64,12 +64,12 @@ def build_media_description(media_type : str, payload_type : int, rtp_codec : st def add_audio_track(peer_connection : PeerConnection, media_direction : MediaDirection) -> RtcAudioTrack: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() media_description = build_media_description('audio', 111, 'opus/48000/2', media_direction, 1) audio_track = datachannel_library.rtcAddTrack(peer_connection, media_description) - audio_packetizer = create_rtc_packetizer_init() + audio_packetizer = datachannel_module.define_rtc_packetizer_init() audio_packetizer.ssrc = 43 audio_packetizer.cname = b'audio' audio_packetizer.payloadType = 111 @@ -82,12 +82,12 @@ def add_audio_track(peer_connection : PeerConnection, media_direction : MediaDir def add_video_track(peer_connection : PeerConnection, media_direction : MediaDirection) -> RtcVideoTrack: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() media_description = build_media_description('video', 96, 'VP8/90000', media_direction, 0) video_track = datachannel_library.rtcAddTrack(peer_connection, media_description) - video_packetizer = create_rtc_packetizer_init() + video_packetizer = datachannel_module.define_rtc_packetizer_init() video_packetizer.ssrc = 42 video_packetizer.cname = b'video' video_packetizer.payloadType = 96 @@ -102,7 +102,7 @@ def add_video_track(peer_connection : PeerConnection, media_direction : MediaDir def create_sdp(peer_connection : PeerConnection) -> Optional[SdpOffer]: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() datachannel_library.rtcSetLocalDescription(peer_connection, b'offer') buffer_size = 16384 buffer_string = ctypes.create_string_buffer(buffer_size) @@ -126,7 +126,7 @@ def on_ice_complete(peer_connection : int, state : int, user_pointer : Optional[ def negotiate_sdp(peer_connection : PeerConnection, sdp_offer : SdpOffer) -> Optional[SdpAnswer]: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() sdp_event = threading.Event() sdp_event_pointer = ctypes.cast(id(sdp_event), ctypes.c_void_p) @@ -145,7 +145,7 @@ def negotiate_sdp(peer_connection : PeerConnection, sdp_offer : SdpOffer) -> Opt def send_to_peers(rtc_peers : List[RtcPeer], data : bytes) -> None: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() if rtc_peers: timestamp = int(time.monotonic() * 90000) & 0xFFFFFFFF @@ -163,7 +163,7 @@ def send_to_peers(rtc_peers : List[RtcPeer], data : bytes) -> None: def delete_peers(rtc_peers : List[RtcPeer]) -> None: - datachannel_library = create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() for rtc_peer in rtc_peers: peer_connection_id = rtc_peer.get('peer_connection') diff --git a/tests/stream_helper.py b/tests/stream_helper.py index a83faa3d..04967b6c 100644 --- a/tests/stream_helper.py +++ b/tests/stream_helper.py @@ -6,11 +6,12 @@ from typing import Optional from starlette.testclient import TestClient from facefusion import rtc +from facefusion.libraries import datachannel as datachannel_module from facefusion.types import SdpOffer def create_sdp_offer() -> Optional[SdpOffer]: - datachannel_library = rtc.create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() peer_connection = rtc.create_peer_connection(disable_auto_negotiation = True) datachannel_library.rtcAddTrack(peer_connection, rtc.build_media_description('video', 96, 'VP8/90000', 'recvonly', 0)) diff --git a/tests/test_rtc.py b/tests/test_rtc.py index 4dfff715..0bd009f5 100644 --- a/tests/test_rtc.py +++ b/tests/test_rtc.py @@ -3,6 +3,7 @@ from typing import List import pytest from facefusion import rtc +from facefusion.libraries import datachannel as datachannel_module from facefusion.types import RtcPeer @@ -20,7 +21,7 @@ def test_build_media_description() -> None: @pytest.mark.skip def test_create_peer_connection() -> None: peer_connection = rtc.create_peer_connection() - datachannel_library = rtc.create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() assert peer_connection > 0 assert datachannel_library.rtcDeletePeerConnection(peer_connection) == 0 @@ -33,7 +34,7 @@ def test_add_audio_track() -> None: assert rtc.add_audio_track(peer_connection, 'sendonly') > 0 - rtc.create_static_datachannel_library().rtcDeletePeerConnection(peer_connection) + datachannel_module.create_static_library().rtcDeletePeerConnection(peer_connection) # TODO: enable again @@ -43,13 +44,13 @@ def test_add_video_track() -> None: assert rtc.add_video_track(peer_connection, 'sendonly') > 0 - rtc.create_static_datachannel_library().rtcDeletePeerConnection(peer_connection) + datachannel_module.create_static_library().rtcDeletePeerConnection(peer_connection) # TODO: enable again @pytest.mark.skip def test_negotiate_sdp() -> None: - datachannel_library = rtc.create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() sender_connection = rtc.create_peer_connection() rtc.add_video_track(sender_connection, 'sendonly') @@ -74,7 +75,7 @@ def test_negotiate_sdp() -> None: # TODO: enable again @pytest.mark.skip def test_delete_peers() -> None: - datachannel_library = rtc.create_static_datachannel_library() + datachannel_library = datachannel_module.create_static_library() peer_connection = rtc.create_peer_connection() rtc_peers : List[RtcPeer] =\ [