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
This commit is contained in:
Henry Ruhs
2026-05-11 16:36:23 +02:00
committed by henryruhs
parent a8db033033
commit 97e0df01b1
5 changed files with 36 additions and 35 deletions
+1
View File
@@ -1,5 +1,6 @@
__pycache__ __pycache__
.assets .assets
.binaries
.claude .claude
.caches .caches
.idea .idea
@@ -6,12 +6,10 @@ from facefusion.common_helper import is_linux, is_macos, is_windows
from facefusion.filesystem import resolve_relative_path from facefusion.filesystem import resolve_relative_path
from facefusion.types import DownloadSet from facefusion.types import DownloadSet
LOG_CB_TYPE = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
@lru_cache @lru_cache
def create_static_download_set() -> Dict[str, DownloadSet]: # TODO: replace once conda package is in place def create_static_library_set() -> Dict[str, DownloadSet]:
binary_name = resolve_binary_file() library_file = resolve_library_file()
return\ return\
{ {
@@ -19,22 +17,22 @@ def create_static_download_set() -> Dict[str, DownloadSet]: # TODO: replace once
{ {
'datachannel': '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 '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('../.assets/binaries/' + binary_name + '.hash') 'path': resolve_relative_path('../.binaries/' + library_file + '.hash')
} }
}, },
'sources': 'sources':
{ {
'datachannel': '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 'url': 'https://huggingface.co/bluefoxcreation/libdatachannel/resolve/main/linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so',
'path': resolve_relative_path('../.assets/binaries/' + binary_name) 'path': resolve_relative_path('../.binaries/' + library_file)
} }
} }
} }
def resolve_binary_file() -> Optional[str]: def resolve_library_file() -> Optional[str]:
if is_linux(): if is_linux():
return 'linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so' return 'linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so'
if is_macos(): if is_macos():
@@ -44,7 +42,7 @@ def resolve_binary_file() -> Optional[str]:
return None return None
def create_rtc_configuration() -> ctypes.Structure: def define_rtc_configuration() -> ctypes.Structure:
return type('RTC_CONFIGURATION', (ctypes.Structure,), return type('RTC_CONFIGURATION', (ctypes.Structure,),
{ {
'_fields_': '_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,), return type('RTC_PACKETIZER_INIT', (ctypes.Structure,),
{ {
'_fields_': '_fields_':
@@ -84,20 +82,20 @@ def create_rtc_packetizer_init() -> ctypes.Structure:
@lru_cache @lru_cache
def create_static_datachannel_library() -> Optional[ctypes.CDLL]: def create_static_library() -> Optional[ctypes.CDLL]:
binary_path = create_static_download_set().get('sources').get('datachannel').get('path') library_path = create_static_library_set().get('sources').get('datachannel').get('path')
if binary_path: if library_path:
datachannel_library = ctypes.CDLL(binary_path) datachannel_library = ctypes.CDLL(library_path)
return init_ctypes(datachannel_library) return init_ctypes(datachannel_library)
return None return None
def init_ctypes(datachannel_library : ctypes.CDLL) -> ctypes.CDLL: 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.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 datachannel_library.rtcCreatePeerConnection.restype = ctypes.c_int
+12 -12
View File
@@ -3,13 +3,13 @@ import threading
import time import time
from typing import List, Optional 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.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 from facefusion.types import MediaDirection, PeerConnection, RtcAudioTrack, RtcPeer, RtcVideoTrack, SdpAnswer, SdpOffer
def pre_check() -> bool: 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')): if not conditional_download_hashes(download_set.get('hashes')):
return False return False
@@ -30,8 +30,8 @@ def create_peer_connection(
max_packet_size : int = 0, max_packet_size : int = 0,
max_message_size : int = 0) -> PeerConnection: max_message_size : int = 0) -> PeerConnection:
datachannel_library = create_static_datachannel_library() datachannel_library = datachannel_module.create_static_library()
rtc_configuration = create_rtc_configuration() rtc_configuration = datachannel_module.define_rtc_configuration()
rtc_configuration.iceServers = ice_servers rtc_configuration.iceServers = ice_servers
rtc_configuration.iceServersCount = ice_servers_count 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: 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) media_description = build_media_description('audio', 111, 'opus/48000/2', media_direction, 1)
audio_track = datachannel_library.rtcAddTrack(peer_connection, media_description) 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.ssrc = 43
audio_packetizer.cname = b'audio' audio_packetizer.cname = b'audio'
audio_packetizer.payloadType = 111 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: 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) media_description = build_media_description('video', 96, 'VP8/90000', media_direction, 0)
video_track = datachannel_library.rtcAddTrack(peer_connection, media_description) 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.ssrc = 42
video_packetizer.cname = b'video' video_packetizer.cname = b'video'
video_packetizer.payloadType = 96 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]: 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') datachannel_library.rtcSetLocalDescription(peer_connection, b'offer')
buffer_size = 16384 buffer_size = 16384
buffer_string = ctypes.create_string_buffer(buffer_size) 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]: 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 = threading.Event()
sdp_event_pointer = ctypes.cast(id(sdp_event), ctypes.c_void_p) 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: 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: if rtc_peers:
timestamp = int(time.monotonic() * 90000) & 0xFFFFFFFF 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: 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: for rtc_peer in rtc_peers:
peer_connection_id = rtc_peer.get('peer_connection') peer_connection_id = rtc_peer.get('peer_connection')
+2 -1
View File
@@ -6,11 +6,12 @@ from typing import Optional
from starlette.testclient import TestClient from starlette.testclient import TestClient
from facefusion import rtc from facefusion import rtc
from facefusion.libraries import datachannel as datachannel_module
from facefusion.types import SdpOffer from facefusion.types import SdpOffer
def create_sdp_offer() -> Optional[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) 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)) datachannel_library.rtcAddTrack(peer_connection, rtc.build_media_description('video', 96, 'VP8/90000', 'recvonly', 0))
+6 -5
View File
@@ -3,6 +3,7 @@ from typing import List
import pytest import pytest
from facefusion import rtc from facefusion import rtc
from facefusion.libraries import datachannel as datachannel_module
from facefusion.types import RtcPeer from facefusion.types import RtcPeer
@@ -20,7 +21,7 @@ def test_build_media_description() -> None:
@pytest.mark.skip @pytest.mark.skip
def test_create_peer_connection() -> None: def test_create_peer_connection() -> None:
peer_connection = rtc.create_peer_connection() 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 peer_connection > 0
assert datachannel_library.rtcDeletePeerConnection(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 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 # TODO: enable again
@@ -43,13 +44,13 @@ def test_add_video_track() -> None:
assert rtc.add_video_track(peer_connection, 'sendonly') > 0 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 # TODO: enable again
@pytest.mark.skip @pytest.mark.skip
def test_negotiate_sdp() -> None: 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() sender_connection = rtc.create_peer_connection()
rtc.add_video_track(sender_connection, 'sendonly') rtc.add_video_track(sender_connection, 'sendonly')
@@ -74,7 +75,7 @@ def test_negotiate_sdp() -> None:
# TODO: enable again # TODO: enable again
@pytest.mark.skip @pytest.mark.skip
def test_delete_peers() -> None: 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() peer_connection = rtc.create_peer_connection()
rtc_peers : List[RtcPeer] =\ rtc_peers : List[RtcPeer] =\
[ [