Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Laky-64 committed Sep 9, 2024
2 parents e065b3c + b243d85 commit ed84fb0
Show file tree
Hide file tree
Showing 90 changed files with 4,077 additions and 91 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
build_list+=",{\"os\":\"macos-14\",\"cibw_archs\":\"native\",\"shared_name\":\"macos-arm64\",\"cibw_os_build\":\"macosx_\"}"
fi
if [[ "${{ github.event.inputs.windows-build }}" == "true" ]]; then
build_list+=",{\"os\":\"windows-2019\",\"cibw_archs\":\"native\",\"shared_name\":\"windows-x86_64\"}"
build_list+=",{\"os\":\"windows-2022\",\"cibw_archs\":\"native\",\"shared_name\":\"windows-x86_64\"}"
fi
if [[ -n "$build_list" ]]; then
build_list="${build_list:1}"
Expand Down Expand Up @@ -238,7 +238,7 @@ jobs:
- name: Create Release
id: create-new-release
uses: softprops/action-gh-release@v2.0.4
uses: softprops/action-gh-release@v2
with:
files: |
./releases/*
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_clang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ endif ()
include(ExternalProject)

# https://chromiumdash.appspot.com/branches
set(WEBRTC_REVISION m123.6312.3.5)
set(BOOST_REVISION 1.85.0)
set(WEBRTC_REVISION m128.6613.2.0)
set(BOOST_REVISION 1.86.0)
set(BOOST_LIBS filesystem)

option(STATIC_BUILD "Build static libraries" ON)
Expand All @@ -17,7 +17,7 @@ if(DEFINED PY_VERSION_INFO)
set(IS_PYTHON TRUE)
endif()

project(ntgcalls VERSION 1.2.1 LANGUAGES C CXX)
project(ntgcalls VERSION 1.2.2 LANGUAGES C CXX)
add_compile_definitions(NTG_VERSION="${CMAKE_PROJECT_VERSION}")

find_package(Threads REQUIRED)
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ RUN yum install -y \
ENV MAKEFLAGS="-j$(nproc)"
ENV CFLAGS="-march=native -O3"
ENV CXXFLAGS="-march=native -O3"
RUN git clone --depth=1 -b release/18.x https://github.com/llvm/llvm-project.git \
RUN git clone --depth=1 -b release/19.x https://github.com/llvm/llvm-project.git \
&& cd llvm-project \
&& mkdir build \
&& cd build \
Expand All @@ -14,5 +14,5 @@ RUN git clone --depth=1 -b release/18.x https://github.com/llvm/llvm-project.git
&& make install \
&& cd ../.. \
&& rm -rf llvm-project \
&& ln -s /usr/local/bin/clang++ /usr/local/bin/clang++-18 \
&& ln -s /usr/local/bin/clang++ /usr/local/bin/clang++-19 \
&& ln -s /usr/local/bin/python3.12 /usr/local/bin/python3
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ NativeTgCalls offers Py Bindings, enabling seamless integration with Python. Fol
```shell
python3 setup.py install
```
### Go Bindings
NativeTgCalls offers Go Bindings, enabling seamless integration with Go. Follow these steps to compile NativeTgCalls with Go Bindings:
1. There is an example project for Go in `./examples/go/` directory, ensure you are in that directory
2. Prerequisites for building are the same as for building library itself and can be found [here](https://pytgcalls.github.io/NTgCalls/Build%20Guide#Installing=Prerequisites)
3. Download **shared** release of the library from https://github.com/pytgcalls/ntgcalls/releases
1. Static won't work
4. Copy `ntgcalls.h` file into `./examples/go/ntgcalls/` directory
5. The rest of the files should be copied to `./examples/go/` directory
1. `ntgcalls.dll` and `ntgcalls.lib` files in case of Windows amd64 shared release
6. Then in `./examples/go/` directory run `go build` or `go run .` with CGO_ENABLED=1 env variable set
1. `$env:CGO_ENABLED=1; go run .` for Windows PowerShell
2. `CGO_ENABLED=1 go run .` for UNIX
### C Bindings
For developers looking to use NativeTgCalls with C and C++, we provide C Bindings. Follow these steps to compile NativeTgCalls with C Bindings:
1. Ensure you are in the root directory of the NativeTgCalls project.
Expand Down
2 changes: 1 addition & 1 deletion cmake/FindBoost.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ if(NOT DEFINED LAST_BOOST_LIBS OR

set(BOOST_DOWNLOAD_DIR ${BOOST_DIR}/download)
DownloadProject(
URL https://boostorg.jfrog.io/artifactory/main/release/${BOOST_REVISION}/source/boost_${BOOST_REVISION_UNDERSCORE}.tar.gz
URL https://archives.boost.io/release/${BOOST_REVISION}/source/boost_${BOOST_REVISION_UNDERSCORE}.tar.gz
DOWNLOAD_DIR ${BOOST_DOWNLOAD_DIR}
SOURCE_DIR ${BOOST_WORKDIR}
)
Expand Down
4 changes: 2 additions & 2 deletions cmake/FindLibCXX.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ if(LINUX)
DIRECTORY ${LIBCXX_INCLUDE}
)
GitFile(
URL https://chromium.googlesource.com/chromium/src/buildtools.git/+/refs/heads/main/third_party/libc++/__config_site
URL https://chromium.googlesource.com/chromium/src/buildtools.git/+/${BUILDTOOLS_COMMIT}/third_party/libc++/__config_site
DIRECTORY ${LIBCXX_INCLUDE}/include/__config_site
)
GitFile(
URL https://chromium.googlesource.com/chromium/src/buildtools.git/+/refs/heads/main/third_party/libc++/__assertion_handler
URL https://chromium.googlesource.com/chromium/src/buildtools.git/+/${BUILDTOOLS_COMMIT}/third_party/libc++/__assertion_handler
DIRECTORY ${LIBCXX_INCLUDE}/include/__assertion_handler
)
GitClone(
Expand Down
2 changes: 2 additions & 0 deletions cmake/FindWebRTC.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,6 @@ if(NOT TARGET WebRTC::webrtc)
set(LIBCXX_COMMIT ${CMAKE_MATCH_1})
string(REGEX MATCH "WEBRTC_SRC_THIRD_PARTY_LIBCXXABI_SRC_COMMIT=([^ \n]+)" matched "${WEBRTC_DATA}")
set(LIBCXX_ABI_COMMIT ${CMAKE_MATCH_1})
string(REGEX MATCH "WEBRTC_SRC_BUILDTOOLS_COMMIT=([^ \n]+)" matched "${WEBRTC_DATA}")
set(BUILDTOOLS_COMMIT ${CMAKE_MATCH_1})
endif ()
1 change: 1 addition & 0 deletions cmake/macOS.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ target_link_libraries(${target_name} PUBLIC
"-framework MetalKit"
"-framework OpenGL"
"-framework IOSurface"
"-framework ScreenCaptureKit"
)
2 changes: 1 addition & 1 deletion deps/pybind11
Submodule pybind11 updated 171 files
2 changes: 1 addition & 1 deletion examples/python/shell_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async def main():
link = 'https://docs.evostream.com/sample_content/assets/sintel1m720p.mp4'

async with client:
call_params = wrtc.create_call(
call_params = await wrtc.create_call(
chat_id,
MediaDescription(
audio=AudioDescription(
Expand Down
2 changes: 1 addition & 1 deletion examples/python/youtube_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async def main():

audio, video = await get_youtube_stream("https://www.youtube.com/watch?v=u__gKd2mCVA")
async with client:
call_params = wrtc.create_call(
call_params = await wrtc.create_call(
chat_id,
MediaDescription(
audio=AudioDescription(
Expand Down
5 changes: 3 additions & 2 deletions ntgcalls/instances/call_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ namespace ntgcalls {

CallInterface::~CallInterface() {
RTC_LOG(LS_VERBOSE) << "Destroying CallInterface";
isExiting = true;
std::lock_guard lock(mutex);
connectionChangeCallback = nullptr;
stream = nullptr;
if (connection) {
connection->onConnectionChange(nullptr);
connection->close();
connection = nullptr;
RTC_LOG(LS_VERBOSE) << "Connection closed";
}
connection = nullptr;
updateThread = nullptr;
cancelNetworkListener();
RTC_LOG(LS_VERBOSE) << "CallInterface destroyed";
Expand Down Expand Up @@ -80,6 +80,7 @@ namespace ntgcalls {
RTC_LOG(LS_INFO) << "Connecting...";
(void) connectionChangeCallback(ConnectionState::Connecting);
connection->onConnectionChange([this](const wrtc::ConnectionState state) {
if (isExiting) return;
std::lock_guard lock(mutex);
switch (state) {
case wrtc::ConnectionState::Connecting:
Expand Down
1 change: 1 addition & 0 deletions ntgcalls/instances/call_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace ntgcalls {

class CallInterface {
bool connected = false;
std::atomic_bool isExiting;

void cancelNetworkListener();

Expand Down
160 changes: 143 additions & 17 deletions ntgcalls/instances/p2p_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

#include "ntgcalls/exceptions.hpp"
#include "ntgcalls/signaling/crypto/mod_exp_first.hpp"
#include "ntgcalls/signaling/messages/candidates_message.hpp"
#include "ntgcalls/signaling/messages/candidate_message.hpp"
#include "ntgcalls/signaling/messages/initial_setup_message.hpp"
#include "ntgcalls/signaling/messages/media_state_message.hpp"
#include "ntgcalls/signaling/messages/message.hpp"
#include "ntgcalls/signaling/messages/negotiate_channels_message.hpp"
#include "ntgcalls/signaling/messages/rtc_description_message.hpp"
#include "wrtc/interfaces/native_connection.hpp"
#include "wrtc/utils/encryption.hpp"

namespace ntgcalls {
Expand Down Expand Up @@ -99,21 +103,30 @@ namespace ntgcalls {
auto encryptionKey = std::make_shared<std::array<uint8_t, signaling::EncryptionKey::kSize>>();
memcpy(encryptionKey->data(), key.value().data(), signaling::EncryptionKey::kSize);
protocolVersion = signaling::Signaling::matchVersion(versions);
connection = std::make_unique<wrtc::PeerConnection>(
if (protocolVersion & signaling::Signaling::Version::V2Full) {
connection = std::make_unique<wrtc::PeerConnection>(
RTCServer::toIceServers(servers),
true,
p2pAllowed
);
Safe<wrtc::PeerConnection>(connection)->onRenegotiationNeeded([this] {
if (makingNegotation) {
RTC_LOG(LS_INFO) << "Renegotiation needed";
sendLocalDescription();
}
});
Safe<wrtc::PeerConnection>(connection)->onRenegotiationNeeded([this] {
if (makingNegotation) {
RTC_LOG(LS_INFO) << "Renegotiation needed";
sendLocalDescription();
}
});
} else {
connection = std::make_unique<wrtc::NativeConnection>(
RTCServer::toRtcServers(servers),
p2pAllowed,
type() == Type::Outgoing
);
}
signaling = signaling::Signaling::Create(
protocolVersion,
connection->networkThread(),
connection->signalingThread(),
connection->environment(),
signaling::EncryptionKey(std::move(encryptionKey), type() == Type::Outgoing),
[this](const bytes::binary &data) {
(void) onEmitData(data);
Expand All @@ -125,12 +138,20 @@ namespace ntgcalls {
}
);
connection->onIceCandidate([this](const wrtc::IceCandidate& candidate) {
signaling::CandidateMessage candMess;
candMess.sdp = candidate.sdp;
candMess.mid = candidate.mid;
candMess.mLine = candidate.mLine;
RTC_LOG(LS_INFO) << "Sending candidate: " << bytes::to_string(candMess.serialize());
signaling->send(candMess.serialize());
bytes::binary message;
if (protocolVersion & signaling::Signaling::Version::V2Full) {
signaling::CandidateMessage candMess;
candMess.sdp = candidate.sdp;
candMess.mid = candidate.mid;
candMess.mLine = candidate.mLine;
message = candMess.serialize();
} else {
signaling::CandidatesMessage candMess;
candMess.iceCandidates.push_back({candidate.sdp});
message = candMess.serialize();
}
RTC_LOG(LS_INFO) << "Sending candidate: " << bytes::to_string(message);
signaling->send(message);
});
connection->onDataChannelOpened([this] {
sendMediaState(stream->getState());
Expand All @@ -141,10 +162,15 @@ namespace ntgcalls {
sendMediaState(mediaState);
});
if (type() == Type::Outgoing) {
RTC_LOG(LS_INFO) << "Creating data channel";
Safe<wrtc::PeerConnection>(connection)->createDataChannel("data");
makingNegotation = true;
sendLocalDescription();
if (protocolVersion & signaling::Signaling::Version::V2Full) {
RTC_LOG(LS_INFO) << "Creating data channel";
Safe<wrtc::PeerConnection>(connection)->createDataChannel("data");
makingNegotation = true;
sendLocalDescription();
} else {
sendInitialSetup();
sendOfferIfNeeded();
}
}
setConnectionObserver();
}
Expand All @@ -153,6 +179,64 @@ namespace ntgcalls {
RTC_LOG(LS_INFO) << "processSignalingData: " << std::string(buffer.begin(), buffer.end());
try {
switch (signaling::Message::type(buffer)) {
case signaling::Message::Type::InitialSetup: {
const auto message = signaling::InitialSetupMessage::deserialize(buffer);
wrtc::PeerIceParameters remoteIceParameters;
remoteIceParameters.ufrag = message->ufrag;
remoteIceParameters.pwd = message->pwd;
remoteIceParameters.supportsRenomination = message->supportsRenomination;

std::unique_ptr<rtc::SSLFingerprint> fingerprint;
std::string sslSetup;
if (!message->fingerprints.empty()) {
fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(message->fingerprints[0].hash, message->fingerprints[0].fingerprint);
sslSetup = message->fingerprints[0].setup;
}
Safe<wrtc::NativeConnection>(connection)->setRemoteParams(remoteIceParameters, std::move(fingerprint), sslSetup);
handshakeCompleted = true;
if (type() == Type::Incoming) {
sendInitialSetup();
}
applyPendingIceCandidates();
break;
}
case signaling::Message::Type::Candidates: {
for (const auto message = signaling::CandidatesMessage::deserialize(buffer); const auto&[sdpString] : message->iceCandidates) {
webrtc::JsepIceCandidate parseCandidate{ std::string(), 0 };
if (!parseCandidate.Initialize(sdpString, nullptr)) {
RTC_LOG(LS_ERROR) << "Could not parse candidate: " << sdpString;
continue;
}
std::string sdp;
parseCandidate.ToString(&sdp);
pendingIceCandidates.emplace_back(
parseCandidate.sdp_mid(),
parseCandidate.sdp_mline_index(),
sdp
);
}
if (handshakeCompleted) {
applyPendingIceCandidates();
}
break;
}
case signaling::Message::Type::NegotiateChannels: {
const auto message = signaling::NegotiateChannelsMessage::deserialize(buffer);
auto negotiationContents = std::make_unique<wrtc::ContentNegotiationContext::NegotiationContents>();
negotiationContents->exchangeId = message->exchangeId;
negotiationContents->contents = message->contents;
auto negotiation = message->serialize();
if (const auto response = Safe<wrtc::NativeConnection>(connection)->setPendingAnswer(std::move(negotiationContents))) {
signaling::NegotiateChannelsMessage channelMessage;
channelMessage.exchangeId = response->exchangeId;
channelMessage.contents = response->contents;
RTC_LOG(LS_INFO) << "Sending negotiate channels: " << bytes::to_string(channelMessage.serialize());
signaling->send(channelMessage.serialize());
}
sendOfferIfNeeded();
Safe<wrtc::NativeConnection>(connection)->createChannels();
break;
}
case signaling::Message::Type::RtcDescription: {
const auto message = signaling::RtcDescriptionMessage::deserialize(buffer);
if (
Expand Down Expand Up @@ -260,6 +344,48 @@ namespace ntgcalls {
connection->sendDataChannelMessage(message.serialize());
}

void P2PCall::sendOfferIfNeeded() const {
if (const auto offer = Safe<wrtc::NativeConnection>(connection)->getPendingOffer()) {
signaling::NegotiateChannelsMessage data;
data.exchangeId = offer->exchangeId;
data.contents = offer->contents;
RTC_LOG(LS_INFO) << "Sending offer: " << bytes::to_string(data.serialize());
signaling->send(data.serialize());
}
}

void P2PCall::sendInitialSetup() const {
connection->networkThread()->PostTask([this] {
const auto localFingerprint = Safe<wrtc::NativeConnection>(connection)->localFingerprint();
std::string hash;
std::string fingerprint;
if (localFingerprint) {
hash = localFingerprint->algorithm;
fingerprint = localFingerprint->GetRfc4572Fingerprint();
}
std::string setup;
if (type() == Type::Outgoing) {
setup = "actpass";
} else {
setup = "passive";
}
const auto localIceParams = Safe<wrtc::NativeConnection>(connection)->localIceParameters();
connection->signalingThread()->PostTask([this, localIceParams, hash, fingerprint, setup] {
signaling::InitialSetupMessage message;
message.ufrag = localIceParams.ufrag;
message.pwd = localIceParams.pwd;
message.supportsRenomination = localIceParams.supportsRenomination;
signaling::InitialSetupMessage::DtlsFingerprint dtlsFingerprint;
dtlsFingerprint.hash = hash;
dtlsFingerprint.fingerprint = fingerprint;
dtlsFingerprint.setup = setup;
message.fingerprints.push_back(std::move(dtlsFingerprint));
RTC_LOG(LS_INFO) << "Sending initial setup: " << bytes::to_string(message.serialize());
signaling->send(message.serialize());
});
});
}

void P2PCall::onSignalingData(const std::function<void(const bytes::binary&)>& callback) {
onEmitData = callback;
}
Expand Down
Loading

0 comments on commit ed84fb0

Please sign in to comment.