mirror of
https://github.com/facefusion/facefusion.git
synced 2026-08-29 20:10:38 +02:00
Move RTC init helpers to bindings layer and clean up structs (#1086)
* converted from type() factory to proper ctypes.Structure subclasses * change class to method * bring back rtcSetLocalDescription * rename rtc_bindings.py to datachannel.py * rename rtc_library to datachannel_library and rearrange methods * cleanup
This commit is contained in:
@@ -0,0 +1,141 @@
|
|||||||
|
import ctypes
|
||||||
|
from functools import lru_cache
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
return\
|
||||||
|
{
|
||||||
|
'hashes':
|
||||||
|
{
|
||||||
|
'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')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_binary_file() -> Optional[str]:
|
||||||
|
if is_linux():
|
||||||
|
return 'linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so'
|
||||||
|
if is_macos():
|
||||||
|
return 'macos-universal-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.dylib'
|
||||||
|
if is_windows():
|
||||||
|
return 'windows-x64-openssl-h264-vp8-av1-opus-datachannel-0.24.1.dll'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def create_rtc_configuration() -> ctypes.Structure:
|
||||||
|
return type('RTC_CONFIGURATION', (ctypes.Structure,),
|
||||||
|
{
|
||||||
|
'_fields_':
|
||||||
|
[
|
||||||
|
('iceServers', ctypes.POINTER(ctypes.c_char_p)),
|
||||||
|
('iceServersCount', ctypes.c_int),
|
||||||
|
('proxyServer', ctypes.c_char_p),
|
||||||
|
('bindAddress', ctypes.c_char_p),
|
||||||
|
('certificateType', ctypes.c_int),
|
||||||
|
('iceTransportPolicy', ctypes.c_int),
|
||||||
|
('enableIceTcp', ctypes.c_bool),
|
||||||
|
('enableIceUdpMux', ctypes.c_bool),
|
||||||
|
('disableAutoNegotiation', ctypes.c_bool),
|
||||||
|
('forceMediaTransport', ctypes.c_bool),
|
||||||
|
('portRangeBegin', ctypes.c_ushort),
|
||||||
|
('portRangeEnd', ctypes.c_ushort),
|
||||||
|
('mtu', ctypes.c_int),
|
||||||
|
('maxMessageSize', ctypes.c_int)
|
||||||
|
]
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
||||||
|
def create_rtc_packetizer_init() -> ctypes.Structure:
|
||||||
|
return type('RTC_PACKETIZER_INIT', (ctypes.Structure,),
|
||||||
|
{
|
||||||
|
'_fields_':
|
||||||
|
[
|
||||||
|
('ssrc', ctypes.c_uint32),
|
||||||
|
('cname', ctypes.c_char_p),
|
||||||
|
('payloadType', ctypes.c_uint8),
|
||||||
|
('clockRate', ctypes.c_uint32),
|
||||||
|
('sequenceNumber', ctypes.c_uint16),
|
||||||
|
('timestamp', ctypes.c_uint32),
|
||||||
|
('maxFragmentSize', ctypes.c_uint16)
|
||||||
|
]
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def create_static_datachannel_library() -> Optional[ctypes.CDLL]:
|
||||||
|
binary_path = create_static_download_set().get('sources').get('datachannel').get('path')
|
||||||
|
|
||||||
|
if binary_path:
|
||||||
|
datachannel_library = ctypes.CDLL(binary_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.restype = None
|
||||||
|
datachannel_library.rtcInitLogger(4, LOG_CB_TYPE(0))
|
||||||
|
|
||||||
|
datachannel_library.rtcCreatePeerConnection.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcDeletePeerConnection.argtypes = [ ctypes.c_int ]
|
||||||
|
datachannel_library.rtcDeletePeerConnection.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
||||||
|
datachannel_library.rtcSetLocalDescription.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetRemoteDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p ]
|
||||||
|
datachannel_library.rtcSetRemoteDescription.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcAddTrack.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
||||||
|
datachannel_library.rtcAddTrack.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSendMessage.argtypes = [ ctypes.c_int, ctypes.c_void_p, ctypes.c_int ]
|
||||||
|
datachannel_library.rtcSendMessage.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetVP8Packetizer.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcChainRtcpSrReporter.argtypes = [ ctypes.c_int ]
|
||||||
|
datachannel_library.rtcChainRtcpSrReporter.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetTrackRtpTimestamp.argtypes = [ ctypes.c_int, ctypes.c_uint32 ]
|
||||||
|
datachannel_library.rtcSetTrackRtpTimestamp.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcIsOpen.argtypes = [ ctypes.c_int ]
|
||||||
|
datachannel_library.rtcIsOpen.restype = ctypes.c_bool
|
||||||
|
|
||||||
|
datachannel_library.rtcChainRtcpNackResponder.argtypes = [ ctypes.c_int, ctypes.c_uint ]
|
||||||
|
datachannel_library.rtcChainRtcpNackResponder.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcGetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p, ctypes.c_int ]
|
||||||
|
datachannel_library.rtcGetLocalDescription.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
||||||
|
datachannel_library.rtcSetLocalDescription.restype = ctypes.c_int
|
||||||
|
|
||||||
|
datachannel_library.rtcSetOpusPacketizer.restype = ctypes.c_int
|
||||||
|
|
||||||
|
return datachannel_library
|
||||||
+31
-80
@@ -1,48 +1,10 @@
|
|||||||
import ctypes
|
import ctypes
|
||||||
import time
|
import time
|
||||||
from functools import lru_cache
|
from typing import List, Optional
|
||||||
from typing import Dict, List, Optional
|
|
||||||
|
|
||||||
from facefusion.common_helper import is_linux, is_macos, is_windows
|
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.filesystem import resolve_relative_path
|
from facefusion.types import MediaDirection, PeerConnection, RtcAudioTrack, RtcPeer, RtcVideoTrack, SdpAnswer, SdpOffer
|
||||||
from facefusion.rtc_bindings import RTC_CONFIGURATION, RTC_PACKETIZER_INIT, init_ctypes
|
|
||||||
from facefusion.types import DownloadSet, MediaDirection, PeerConnection, RtcAudioTrack, RtcPeer, RtcVideoTrack, SdpAnswer, SdpOffer
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_binary_file() -> Optional[str]:
|
|
||||||
if is_linux():
|
|
||||||
return 'linux-x64-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.so'
|
|
||||||
if is_macos():
|
|
||||||
return 'macos-universal-openssl-h264-vp8-av1-opus-libdatachannel-0.24.1.dylib'
|
|
||||||
if is_windows():
|
|
||||||
return 'windows-x64-openssl-h264-vp8-av1-opus-datachannel-0.24.1.dll'
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
def create_static_download_set() -> Dict[str, DownloadSet]: # TODO: replace once conda package is in place
|
|
||||||
binary_name = resolve_binary_file()
|
|
||||||
|
|
||||||
return\
|
|
||||||
{
|
|
||||||
'hashes':
|
|
||||||
{
|
|
||||||
'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')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def pre_check() -> bool:
|
def pre_check() -> bool:
|
||||||
@@ -53,17 +15,6 @@ def pre_check() -> bool:
|
|||||||
return conditional_download_sources(download_set.get('sources'))
|
return conditional_download_sources(download_set.get('sources'))
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
def create_static_rtc_library() -> Optional[ctypes.CDLL]:
|
|
||||||
binary_path = create_static_download_set().get('sources').get('datachannel').get('path')
|
|
||||||
|
|
||||||
if binary_path:
|
|
||||||
rtc_library = ctypes.CDLL(binary_path)
|
|
||||||
return init_ctypes(rtc_library)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def create_peer_connection(
|
def create_peer_connection(
|
||||||
ice_servers : Optional[ctypes.Array[ctypes.c_char_p]] = None,
|
ice_servers : Optional[ctypes.Array[ctypes.c_char_p]] = None,
|
||||||
ice_servers_count : int = 0, proxy_server : Optional[bytes] = None,
|
ice_servers_count : int = 0, proxy_server : Optional[bytes] = None,
|
||||||
@@ -78,8 +29,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:
|
||||||
|
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
rtc_configuration = RTC_CONFIGURATION()
|
rtc_configuration = create_rtc_configuration()
|
||||||
|
|
||||||
rtc_configuration.iceServers = ice_servers
|
rtc_configuration.iceServers = ice_servers
|
||||||
rtc_configuration.iceServersCount = ice_servers_count
|
rtc_configuration.iceServersCount = ice_servers_count
|
||||||
@@ -96,7 +47,7 @@ def create_peer_connection(
|
|||||||
rtc_configuration.mtu = max_packet_size
|
rtc_configuration.mtu = max_packet_size
|
||||||
rtc_configuration.maxMessageSize = max_message_size
|
rtc_configuration.maxMessageSize = max_message_size
|
||||||
|
|
||||||
return rtc_library.rtcCreatePeerConnection(ctypes.byref(rtc_configuration))
|
return datachannel_library.rtcCreatePeerConnection(ctypes.byref(rtc_configuration))
|
||||||
|
|
||||||
|
|
||||||
def build_media_description(media_type : str, payload_type : int, rtp_codec : str, media_direction : MediaDirection, media_id : int) -> bytes:
|
def build_media_description(media_type : str, payload_type : int, rtp_codec : str, media_direction : MediaDirection, media_id : int) -> bytes:
|
||||||
@@ -112,64 +63,64 @@ 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:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_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 = rtc_library.rtcAddTrack(peer_connection, media_description)
|
audio_track = datachannel_library.rtcAddTrack(peer_connection, media_description)
|
||||||
|
|
||||||
audio_packetizer = RTC_PACKETIZER_INIT()
|
audio_packetizer = create_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
|
||||||
audio_packetizer.clockRate = 48000
|
audio_packetizer.clockRate = 48000
|
||||||
|
|
||||||
rtc_library.rtcSetOpusPacketizer(audio_track, ctypes.byref(audio_packetizer))
|
datachannel_library.rtcSetOpusPacketizer(audio_track, ctypes.byref(audio_packetizer))
|
||||||
rtc_library.rtcChainRtcpSrReporter(audio_track)
|
datachannel_library.rtcChainRtcpSrReporter(audio_track)
|
||||||
|
|
||||||
return audio_track
|
return audio_track
|
||||||
|
|
||||||
|
|
||||||
def add_video_track(peer_connection : PeerConnection, media_direction : MediaDirection) -> RtcVideoTrack:
|
def add_video_track(peer_connection : PeerConnection, media_direction : MediaDirection) -> RtcVideoTrack:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_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 = rtc_library.rtcAddTrack(peer_connection, media_description)
|
video_track = datachannel_library.rtcAddTrack(peer_connection, media_description)
|
||||||
|
|
||||||
video_packetizer = RTC_PACKETIZER_INIT()
|
video_packetizer = create_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
|
||||||
video_packetizer.clockRate = 90000
|
video_packetizer.clockRate = 90000
|
||||||
video_packetizer.maxFragmentSize = 1200
|
video_packetizer.maxFragmentSize = 1200
|
||||||
|
|
||||||
rtc_library.rtcSetVP8Packetizer(video_track, ctypes.byref(video_packetizer))
|
datachannel_library.rtcSetVP8Packetizer(video_track, ctypes.byref(video_packetizer))
|
||||||
rtc_library.rtcChainRtcpSrReporter(video_track)
|
datachannel_library.rtcChainRtcpSrReporter(video_track)
|
||||||
rtc_library.rtcChainRtcpNackResponder(video_track, 512)
|
datachannel_library.rtcChainRtcpNackResponder(video_track, 512)
|
||||||
|
|
||||||
return video_track
|
return video_track
|
||||||
|
|
||||||
|
|
||||||
def create_sdp(peer_connection : PeerConnection) -> Optional[SdpOffer]:
|
def create_sdp(peer_connection : PeerConnection) -> Optional[SdpOffer]:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
rtc_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)
|
||||||
|
|
||||||
if rtc_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
if datachannel_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
||||||
return buffer_string.value.decode()
|
return buffer_string.value.decode()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def negotiate_sdp(peer_connection : PeerConnection, sdp_offer : SdpOffer) -> Optional[SdpAnswer]:
|
def negotiate_sdp(peer_connection : PeerConnection, sdp_offer : SdpOffer) -> Optional[SdpAnswer]:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
rtc_library.rtcSetRemoteDescription(peer_connection, sdp_offer.encode(), b'offer')
|
datachannel_library.rtcSetRemoteDescription(peer_connection, sdp_offer.encode(), b'offer')
|
||||||
buffer_size = 16384
|
buffer_size = 16384
|
||||||
buffer_string = ctypes.create_string_buffer(buffer_size)
|
buffer_string = ctypes.create_string_buffer(buffer_size)
|
||||||
wait_limit = time.monotonic() + 5
|
wait_limit = time.monotonic() + 5
|
||||||
|
|
||||||
while time.monotonic() < wait_limit:
|
while time.monotonic() < wait_limit:
|
||||||
if rtc_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
if datachannel_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
||||||
return buffer_string.value.decode()
|
return buffer_string.value.decode()
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
||||||
@@ -195,7 +146,7 @@ def handle_whep_offer(peers : List[RtcPeer], sdp_offer : SdpOffer) -> Optional[S
|
|||||||
|
|
||||||
|
|
||||||
def send_to_peers(peers : List[RtcPeer], data : bytes) -> None:
|
def send_to_peers(peers : List[RtcPeer], data : bytes) -> None:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
|
|
||||||
if peers:
|
if peers:
|
||||||
timestamp = int(time.monotonic() * 90000) & 0xFFFFFFFF
|
timestamp = int(time.monotonic() * 90000) & 0xFFFFFFFF
|
||||||
@@ -205,32 +156,32 @@ def send_to_peers(peers : List[RtcPeer], data : bytes) -> None:
|
|||||||
for rtc_peer in peers:
|
for rtc_peer in peers:
|
||||||
video_track_id = rtc_peer.get('video_track')
|
video_track_id = rtc_peer.get('video_track')
|
||||||
|
|
||||||
if video_track_id and rtc_library.rtcIsOpen(video_track_id):
|
if video_track_id and datachannel_library.rtcIsOpen(video_track_id):
|
||||||
rtc_library.rtcSetTrackRtpTimestamp(video_track_id, timestamp)
|
datachannel_library.rtcSetTrackRtpTimestamp(video_track_id, timestamp)
|
||||||
rtc_library.rtcSendMessage(video_track_id, data_buffer, data_total)
|
datachannel_library.rtcSendMessage(video_track_id, data_buffer, data_total)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def delete_peers(peers : List[RtcPeer]) -> None:
|
def delete_peers(peers : List[RtcPeer]) -> None:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
|
|
||||||
for rtc_peer in peers:
|
for rtc_peer in peers:
|
||||||
peer_connection_id = rtc_peer.get('peer_connection')
|
peer_connection_id = rtc_peer.get('peer_connection')
|
||||||
|
|
||||||
if peer_connection_id:
|
if peer_connection_id:
|
||||||
rtc_library.rtcDeletePeerConnection(peer_connection_id)
|
datachannel_library.rtcDeletePeerConnection(peer_connection_id)
|
||||||
|
|
||||||
peers.clear()
|
peers.clear()
|
||||||
|
|
||||||
|
|
||||||
def is_peer_connected(peers : List[RtcPeer]) -> bool:
|
def is_peer_connected(peers : List[RtcPeer]) -> bool:
|
||||||
rtc_library = create_static_rtc_library()
|
datachannel_library = create_static_datachannel_library()
|
||||||
|
|
||||||
for rtc_peer in peers:
|
for rtc_peer in peers:
|
||||||
video_track_id = rtc_peer.get('video_track')
|
video_track_id = rtc_peer.get('video_track')
|
||||||
|
|
||||||
if video_track_id and rtc_library.rtcIsOpen(video_track_id):
|
if video_track_id and datachannel_library.rtcIsOpen(video_track_id):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
|
|
||||||
RTC_CONFIGURATION = type('RtcConfiguration', (ctypes.Structure,),
|
|
||||||
{
|
|
||||||
'_fields_':
|
|
||||||
[
|
|
||||||
('iceServers', ctypes.POINTER(ctypes.c_char_p)),
|
|
||||||
('iceServersCount', ctypes.c_int),
|
|
||||||
('proxyServer', ctypes.c_char_p),
|
|
||||||
('bindAddress', ctypes.c_char_p),
|
|
||||||
('certificateType', ctypes.c_int),
|
|
||||||
('iceTransportPolicy', ctypes.c_int),
|
|
||||||
('enableIceTcp', ctypes.c_bool),
|
|
||||||
('enableIceUdpMux', ctypes.c_bool),
|
|
||||||
('disableAutoNegotiation', ctypes.c_bool),
|
|
||||||
('forceMediaTransport', ctypes.c_bool),
|
|
||||||
('portRangeBegin', ctypes.c_ushort),
|
|
||||||
('portRangeEnd', ctypes.c_ushort),
|
|
||||||
('mtu', ctypes.c_int),
|
|
||||||
('maxMessageSize', ctypes.c_int)
|
|
||||||
]
|
|
||||||
})
|
|
||||||
RTC_PACKETIZER_INIT = type('RtcPacketizerInit', (ctypes.Structure,),
|
|
||||||
{
|
|
||||||
'_fields_':
|
|
||||||
[
|
|
||||||
('ssrc', ctypes.c_uint32),
|
|
||||||
('cname', ctypes.c_char_p),
|
|
||||||
('payloadType', ctypes.c_uint8),
|
|
||||||
('clockRate', ctypes.c_uint32),
|
|
||||||
('sequenceNumber', ctypes.c_uint16),
|
|
||||||
('timestamp', ctypes.c_uint32),
|
|
||||||
('maxFragmentSize', ctypes.c_uint16),
|
|
||||||
('nalSeparator', ctypes.c_int),
|
|
||||||
('obuPacketization', ctypes.c_int),
|
|
||||||
('playoutDelayId', ctypes.c_uint8),
|
|
||||||
('playoutDelayMin', ctypes.c_uint16),
|
|
||||||
('playoutDelayMax', ctypes.c_uint16)
|
|
||||||
]
|
|
||||||
})
|
|
||||||
LOG_CB_TYPE = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
|
|
||||||
|
|
||||||
|
|
||||||
def init_ctypes(rtc_library : ctypes.CDLL) -> ctypes.CDLL:
|
|
||||||
rtc_library.rtcInitLogger.argtypes = [ ctypes.c_int, LOG_CB_TYPE ]
|
|
||||||
rtc_library.rtcInitLogger.restype = None
|
|
||||||
rtc_library.rtcInitLogger(4, LOG_CB_TYPE(0))
|
|
||||||
|
|
||||||
rtc_library.rtcCreatePeerConnection.argtypes = [ ctypes.POINTER(RTC_CONFIGURATION) ]
|
|
||||||
rtc_library.rtcCreatePeerConnection.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcDeletePeerConnection.argtypes = [ ctypes.c_int ]
|
|
||||||
rtc_library.rtcDeletePeerConnection.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
|
||||||
rtc_library.rtcSetLocalDescription.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetRemoteDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p ]
|
|
||||||
rtc_library.rtcSetRemoteDescription.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcAddTrack.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
|
||||||
rtc_library.rtcAddTrack.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSendMessage.argtypes = [ ctypes.c_int, ctypes.c_void_p, ctypes.c_int ]
|
|
||||||
rtc_library.rtcSendMessage.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetVP8Packetizer.argtypes = [ ctypes.c_int, ctypes.POINTER(RTC_PACKETIZER_INIT) ]
|
|
||||||
rtc_library.rtcSetVP8Packetizer.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcChainRtcpSrReporter.argtypes = [ ctypes.c_int ]
|
|
||||||
rtc_library.rtcChainRtcpSrReporter.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetTrackRtpTimestamp.argtypes = [ ctypes.c_int, ctypes.c_uint32 ]
|
|
||||||
rtc_library.rtcSetTrackRtpTimestamp.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcIsOpen.argtypes = [ ctypes.c_int ]
|
|
||||||
rtc_library.rtcIsOpen.restype = ctypes.c_bool
|
|
||||||
|
|
||||||
rtc_library.rtcChainRtcpNackResponder.argtypes = [ ctypes.c_int, ctypes.c_uint ]
|
|
||||||
rtc_library.rtcChainRtcpNackResponder.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcGetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p, ctypes.c_int ]
|
|
||||||
rtc_library.rtcGetLocalDescription.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetLocalDescription.argtypes = [ ctypes.c_int, ctypes.c_char_p ]
|
|
||||||
rtc_library.rtcSetLocalDescription.restype = ctypes.c_int
|
|
||||||
|
|
||||||
rtc_library.rtcSetOpusPacketizer.argtypes = [ ctypes.c_int, ctypes.POINTER(RTC_PACKETIZER_INIT) ]
|
|
||||||
rtc_library.rtcSetOpusPacketizer.restype = ctypes.c_int
|
|
||||||
|
|
||||||
return rtc_library
|
|
||||||
@@ -10,26 +10,26 @@ from facefusion.types import SdpOffer
|
|||||||
|
|
||||||
|
|
||||||
def create_sdp_offer() -> Optional[SdpOffer]:
|
def create_sdp_offer() -> Optional[SdpOffer]:
|
||||||
rtc_library = rtc.create_static_rtc_library()
|
datachannel_library = rtc.create_static_datachannel_library()
|
||||||
peer_connection = rtc.create_peer_connection(disable_auto_negotiation = True)
|
peer_connection = rtc.create_peer_connection(disable_auto_negotiation = True)
|
||||||
|
|
||||||
rtc_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))
|
||||||
rtc_library.rtcAddTrack(peer_connection, rtc.build_media_description('audio', 111, 'opus/48000/2', 'recvonly', 1))
|
datachannel_library.rtcAddTrack(peer_connection, rtc.build_media_description('audio', 111, 'opus/48000/2', 'recvonly', 1))
|
||||||
rtc_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)
|
||||||
wait_limit = time.monotonic() + 5
|
wait_limit = time.monotonic() + 5
|
||||||
|
|
||||||
while time.monotonic() < wait_limit:
|
while time.monotonic() < wait_limit:
|
||||||
if rtc_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
if datachannel_library.rtcGetLocalDescription(peer_connection, buffer_string, buffer_size) > 0:
|
||||||
sdp = buffer_string.value.decode()
|
sdp = buffer_string.value.decode()
|
||||||
rtc_library.rtcDeletePeerConnection(peer_connection)
|
datachannel_library.rtcDeletePeerConnection(peer_connection)
|
||||||
return sdp
|
return sdp
|
||||||
|
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
|
||||||
rtc_library.rtcDeletePeerConnection(peer_connection)
|
datachannel_library.rtcDeletePeerConnection(peer_connection)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -15,14 +15,14 @@ def test_build_media_description() -> None:
|
|||||||
|
|
||||||
def test_create_peer_connection() -> None:
|
def test_create_peer_connection() -> None:
|
||||||
peer_connection = rtc.create_peer_connection()
|
peer_connection = rtc.create_peer_connection()
|
||||||
rtc_library = rtc.create_static_rtc_library()
|
datachannel_library = rtc.create_static_datachannel_library()
|
||||||
|
|
||||||
assert peer_connection > 0
|
assert peer_connection > 0
|
||||||
assert rtc_library.rtcDeletePeerConnection(peer_connection) == 0
|
assert datachannel_library.rtcDeletePeerConnection(peer_connection) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_add_audio_track() -> None:
|
def test_add_audio_track() -> None:
|
||||||
rtc_library = rtc.create_static_rtc_library()
|
datachannel_library = rtc.create_static_datachannel_library()
|
||||||
|
|
||||||
sender_connection = rtc.create_peer_connection()
|
sender_connection = rtc.create_peer_connection()
|
||||||
sender_audio_track = rtc.add_audio_track(sender_connection, 'sendonly')
|
sender_audio_track = rtc.add_audio_track(sender_connection, 'sendonly')
|
||||||
@@ -40,12 +40,12 @@ def test_add_audio_track() -> None:
|
|||||||
assert 'opus/48000/2' in sdp_offer
|
assert 'opus/48000/2' in sdp_offer
|
||||||
assert 'opus/48000/2' in sdp_answer
|
assert 'opus/48000/2' in sdp_answer
|
||||||
|
|
||||||
assert rtc_library.rtcDeletePeerConnection(sender_connection) == 0
|
assert datachannel_library.rtcDeletePeerConnection(sender_connection) == 0
|
||||||
assert rtc_library.rtcDeletePeerConnection(receiver_connection) == 0
|
assert datachannel_library.rtcDeletePeerConnection(receiver_connection) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_add_video_track() -> None:
|
def test_add_video_track() -> None:
|
||||||
rtc_library = rtc.create_static_rtc_library()
|
datachannel_library = rtc.create_static_datachannel_library()
|
||||||
|
|
||||||
sender_connection = rtc.create_peer_connection()
|
sender_connection = rtc.create_peer_connection()
|
||||||
sender_video_track = rtc.add_video_track(sender_connection, 'sendonly')
|
sender_video_track = rtc.add_video_track(sender_connection, 'sendonly')
|
||||||
@@ -63,5 +63,5 @@ def test_add_video_track() -> None:
|
|||||||
assert 'VP8/90000' in sdp_offer
|
assert 'VP8/90000' in sdp_offer
|
||||||
assert 'VP8/90000' in sdp_answer
|
assert 'VP8/90000' in sdp_answer
|
||||||
|
|
||||||
assert rtc_library.rtcDeletePeerConnection(sender_connection) == 0
|
assert datachannel_library.rtcDeletePeerConnection(sender_connection) == 0
|
||||||
assert rtc_library.rtcDeletePeerConnection(receiver_connection) == 0
|
assert datachannel_library.rtcDeletePeerConnection(receiver_connection) == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user