This commit is contained in:
Ali 2020-06-12 19:33:38 +04:00
parent f5d2d075e2
commit a9a992b434
29 changed files with 485 additions and 1693 deletions

View File

@ -29,7 +29,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
self.strings = strings
self.micButton = ChatTextInputMediaRecordingButton(theme: theme, presentController: presentController)
self.micButton = ChatTextInputMediaRecordingButton(theme: theme, strings: strings, presentController: presentController)
self.sendButton = HighlightTrackingButtonNode(pointerStyle: .lift)
//self.sendButton.adjustsImageWhenHighlighted = false
//self.sendButton.adjustsImageWhenDisabled = false

View File

@ -155,6 +155,7 @@ private final class ChatTextInputMediaRecordingButtonPresenter : NSObject, TGMod
final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButton, TGModernConversationInputMicButtonDelegate {
private var theme: PresentationTheme
private let strings: PresentationStrings
var mode: ChatTextInputMediaRecordingButtonMode = .audio
var account: Account?
@ -236,8 +237,9 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
}
}
init(theme: PresentationTheme, presentController: @escaping (ViewController) -> Void) {
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
self.theme = theme
self.strings = strings
self.innerIconView = UIImageView()
self.presentController = presentController
@ -399,7 +401,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
}
func micButtonLock() -> (UIView & TGModernConversationInputMicButtonLock)! {
let lockView = LockView(frame: CGRect(origin: CGPoint(), size: CGSize(width: 40.0, height: 60.0)), theme: self.theme)
let lockView = LockView(frame: CGRect(origin: CGPoint(), size: CGSize(width: 40.0, height: 60.0)), theme: self.theme, strings: self.strings)
lockView.addTarget(self, action: #selector(handleStopTap), for: .touchUpInside)
return lockView
}

View File

@ -32,9 +32,11 @@ final class LockView: UIButton, TGModernConversationInputMicButtonLock {
return view
}()
init(frame: CGRect, theme: PresentationTheme) {
init(frame: CGRect, theme: PresentationTheme, strings: PresentationStrings) {
super.init(frame: frame)
accessibilityLabel = strings.VoiceOver_Recording_StopAndPreview
addSubview(idleView)
idleView.frame = bounds

View File

@ -464,7 +464,9 @@ public final class OngoingCallContext {
break
}
}
let context = OngoingCallThreadLocalContextWebrtc(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtc(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtc), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
let context = OngoingCallThreadLocalContextWebrtc(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtc(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtc), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in
callSessionManager?.sendSignalingData(internalId: internalId, data: data)
})
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { state in
@ -513,9 +515,9 @@ public final class OngoingCallContext {
self.signalingDataDisposable = (callSessionManager.callSignalingData(internalId: internalId)
|> deliverOn(self.queue)).start(next: { [weak self] data in
self?.withContext { context in
/*if let context = context as? OngoingCallThreadLocalContextWebrtcCustom {
context.receiveSignaling(data)
}*/
if let context = context as? OngoingCallThreadLocalContextWebrtc {
context.addSignaling(data)
}
}
})
}

View File

@ -1,79 +1,50 @@
#ifndef DEMO_CONNECTOR_H
#define DEMO_CONNECTOR_H
#include "Endpoint.h"
#include "LayerBase.h"
#include "Message.h"
#include "p2p/base/basic_packet_socket_factory.h"
#include "rtc_base/proxy_info.h"
#include "rtc_base/task_utils/repeating_task.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
#include "p2p/base/p2p_transport_channel.h"
#include "p2p/client/basic_port_allocator.h"
#include "p2p/base/basic_async_resolver_factory.h"
#include <memory>
#include <map>
class Connector : public sigslot::has_slots<> {
public:
explicit Connector(std::unique_ptr<LayerBase> layer);
explicit Connector(bool isOutgoing);
~Connector() override;
void Start();
void AddEndpointRelayTcpObfuscated(const rtc::SocketAddress& addr, const Relay::PeerTag& peer_tag);
void AddEndpointRelayUdp(const rtc::SocketAddress& addr, const Relay::PeerTag& peer_tag);
void SetEndpointP2p(const rtc::SocketAddress& addr);
sigslot::signal1<const message::Base&> SignalMessage;
void SendMessage(const message::Base&);
void ResetActiveEndpoint();
void SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username,
const std::string& password);
sigslot::signal1<const std::vector<std::string>&> SignalCandidatesGathered;
sigslot::signal1<bool> SignalReadyToSendStateChanged;
sigslot::signal1<const rtc::CopyOnWriteBuffer&> SignalPacketReceived;
void AddRemoteCandidates(const std::vector<std::string> &candidates);
void SendPacket(const rtc::CopyOnWriteBuffer& data);
private:
class PingHistory {
public:
PingHistory();
void Ping(uint32_t id);
void Pong(uint32_t id);
double Average();
void CandidateGathered(cricket::IceTransportInternal *transport, const cricket::Candidate &candidate);
void CandidateGatheringState(cricket::IceTransportInternal *transport);
void TransportStateChanged(cricket::IceTransportInternal *transport);
void TransportRoleConflict(cricket::IceTransportInternal *transport);
void TransportReadyToSend(cricket::IceTransportInternal *transport);
void TransportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t &timestamp, int unused);
private:
void AppendPing(int64_t ms);
void UpdatePing(int64_t ms);
std::unique_ptr<rtc::Thread> networkThread;
static const size_t history_length;
static const int64_t unavailable_ms;
bool isOutgoing;
std::unique_ptr<rtc::BasicPacketSocketFactory> socketFactory;
std::unique_ptr<rtc::BasicNetworkManager> networkManager;
std::unique_ptr<cricket::BasicPortAllocator> portAllocator;
std::unique_ptr<webrtc::BasicAsyncResolverFactory> asyncResolverFactory;
std::unique_ptr<cricket::P2PTransportChannel> transportChannel;
std::queue<int64_t > history;
int64_t ping_sum;
uint32_t sent_id;
int64_t sent_time;
};
static const int64_t tcp_reconnect_delay;
static const int64_t ping_interval_ms;
static const int64_t endpoint_ping_diff_ms;
static const std::set<message::Type> multicast_types;
EndpointP2p *GetP2pEndpoint() const;
void AddEndpoint(std::unique_ptr<EndpointBase>);
void DeleteEndpoint(EndpointBase *ep);
void RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us);
void Ready(rtc::AsyncPacketSocket *);
void RecvMessage(const message::Base&, EndpointBase *);
void UpdateActiveEndpoint();
rtc::ProxyInfo proxy_info;
EndpointBase *active_endpoint;
std::unique_ptr<rtc::Thread> thread;
rtc::BasicPacketSocketFactory socket_factory;
std::unique_ptr<rtc::AsyncPacketSocket> socket;
std::unique_ptr<LayerBase> layer;
std::map<EndpointBase *, std::unique_ptr<EndpointBase>> endpoints;
std::map<EndpointBase *, PingHistory> ping_history;
webrtc::RepeatingTaskHandle pinger;
uint32_t ping_seq;
std::vector<std::string> collectedLocalCandidates;
};
#endif //DEMO_CONNECTOR_H

View File

@ -1,232 +1,158 @@
#include "Connector.h"
#include "Endpoint.h"
#include "Layer92.h"
#include "MediaEngineWebrtc.h"
#include "Protocol10.h"
#include "api/packet_socket_factory.h"
#include "rtc_base/task_utils/to_queued_task.h"
#include "p2p/base/ice_credentials_iterator.h"
#include "api/jsep_ice_candidate.h"
#include <memory>
const int64_t Connector::tcp_reconnect_delay = 5000;
const int64_t Connector::ping_interval_ms = 10000;
const int64_t Connector::endpoint_ping_diff_ms = 20;
const std::set<message::Type> Connector::multicast_types = {
message::Type::tInit, message::Type::tInitAck, message::Type::tPing
};
const size_t Connector::PingHistory::history_length = 5;
const int64_t Connector::PingHistory::unavailable_ms = 100000;
Connector::Connector(bool isOutgoing) {
networkThread = rtc::Thread::CreateWithSocketServer();
Connector::PingHistory::PingHistory()
: ping_sum(0)
, sent_id(0)
, sent_time(0) {
for (size_t i = 0; i < history_length; ++i)
AppendPing(unavailable_ms);
this->isOutgoing = isOutgoing;
}
void Connector::PingHistory::AppendPing(int64_t ms) {
if (history.size() >= history_length) {
ping_sum -= history.front();
history.pop();
}
if (history.size() < history_length) {
ping_sum += ms;
history.emplace(ms);
}
}
void Connector::PingHistory::UpdatePing(int64_t ms) {
if (!history.empty()) {
ping_sum = ping_sum - history.back() + ms;
history.back() = ms;
} else
AppendPing(ms);
}
void Connector::PingHistory::Ping(uint32_t id) {
sent_id = id;
sent_time = rtc::TimeMillis();
}
void Connector::PingHistory::Pong(uint32_t id) {
if (id != sent_id)
return;
sent_id = 0;
UpdatePing(std::min(rtc::TimeMillis() - sent_time, unavailable_ms));
sent_time = 0;
}
double Connector::PingHistory::Average() {
return static_cast<double>(ping_sum) / history.size();
}
Connector::Connector(std::unique_ptr<LayerBase> layer)
: active_endpoint(nullptr)
, thread(rtc::Thread::CreateWithSocketServer())
, socket_factory(thread.get())
, layer(std::move(layer))
, ping_seq(0) {
pinger = webrtc::RepeatingTaskHandle::Start(thread.get(), [this]() {
Connector::UpdateActiveEndpoint();
return webrtc::TimeDelta::ms(ping_interval_ms);
Connector::~Connector() {
networkThread->Invoke<void>(RTC_FROM_HERE, [this]() {
transportChannel = nullptr;
asyncResolverFactory = nullptr;
portAllocator = nullptr;
networkManager = nullptr;
socketFactory = nullptr;
});
}
void Connector::Start() {
thread->Start();
thread->Invoke<void>(RTC_FROM_HERE, [this]() {
socket.reset(socket_factory.CreateUdpSocket(
rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0), 0, 0));
socket->SignalReadPacket.connect(this, &Connector::RecvPacket);
socket->SignalReadyToSend.connect(this, &Connector::Ready);
NSLog(@"Started %d", (int)[[NSDate date] timeIntervalSince1970]);
networkThread->Start();
networkThread->Invoke<void>(RTC_FROM_HERE, [this] {
socketFactory.reset(new rtc::BasicPacketSocketFactory(networkThread.get()));
networkManager = std::make_unique<rtc::BasicNetworkManager>();
portAllocator.reset(new cricket::BasicPortAllocator(networkManager.get(), socketFactory.get(), /*turn_customizer=*/ nullptr, /*relay_port_factory=*/ nullptr));
uint32_t flags = cricket::PORTALLOCATOR_DISABLE_TCP;
//flags |= cricket::PORTALLOCATOR_DISABLE_UDP;
portAllocator->set_flags(portAllocator->flags() | flags);
portAllocator->Initialize();
rtc::SocketAddress defaultStunAddress = rtc::SocketAddress("hlgkfjdrtjfykgulhijkljhulyo.uksouth.cloudapp.azure.com", 3478);
cricket::ServerAddresses stunServers;
stunServers.insert(defaultStunAddress);
std::vector<cricket::RelayServerConfig> turnServers;
turnServers.push_back(cricket::RelayServerConfig(
rtc::SocketAddress("hlgkfjdrtjfykgulhijkljhulyo.uksouth.cloudapp.azure.com", 3478),
"user",
"root",
cricket::PROTO_UDP
));
portAllocator->SetConfiguration(stunServers, turnServers, 2, webrtc::NO_PRUNE);
asyncResolverFactory = std::make_unique<webrtc::BasicAsyncResolverFactory>();
transportChannel.reset(new cricket::P2PTransportChannel("transport", 0, portAllocator.get(), asyncResolverFactory.get(), /*event_log=*/ nullptr));
cricket::IceConfig iceConfig;
iceConfig.continual_gathering_policy = cricket::GATHER_CONTINUALLY;
transportChannel->SetIceConfig(iceConfig);
cricket::IceParameters localIceParameters(
"gcp3",
"zWDKozH8/3JWt8he3M/CMj5R",
false
);
cricket::IceParameters remoteIceParameters(
"acp3",
"aWDKozH8/3JWt8he3M/CMj5R",
false
);
transportChannel->SetIceParameters(isOutgoing ? localIceParameters : remoteIceParameters);
transportChannel->SetIceRole(isOutgoing ? cricket::ICEROLE_CONTROLLING : cricket::ICEROLE_CONTROLLED);
transportChannel->SignalCandidateGathered.connect(this, &Connector::CandidateGathered);
transportChannel->SignalGatheringState.connect(this, &Connector::CandidateGatheringState);
transportChannel->SignalIceTransportStateChanged.connect(this, &Connector::TransportStateChanged);
transportChannel->SignalRoleConflict.connect(this, &Connector::TransportRoleConflict);
transportChannel->SignalReadPacket.connect(this, &Connector::TransportPacketReceived);
transportChannel->MaybeStartGathering();
transportChannel->SetRemoteIceMode(cricket::ICEMODE_FULL);
transportChannel->SetRemoteIceParameters((!isOutgoing) ? localIceParameters : remoteIceParameters);
});
}
void Connector::RecvPacket(rtc::AsyncPacketSocket *sock, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
for (const auto& ep : endpoints) {
auto ep_udp = dynamic_cast<EndpointUdp *>(ep.first);
if (ep_udp && ep_udp->address == remote_addr) {
ep_udp->RecvPacket(sock, data, len, remote_addr, packet_time_us);
void Connector::AddRemoteCandidates(const std::vector<std::string> &candidates) {
networkThread->Invoke<void>(RTC_FROM_HERE, [this, candidates] {
for (auto &serializedCandidate : candidates) {
webrtc::JsepIceCandidate parseCandidate("", 0);
if (parseCandidate.Initialize(serializedCandidate, nullptr)) {
auto candidate = parseCandidate.candidate();
printf("Add remote candidate %s\n", serializedCandidate.c_str());
transportChannel->AddRemoteCandidate(candidate);
}
}
});
}
void Connector::CandidateGathered(cricket::IceTransportInternal *transport, const cricket::Candidate &candidate) {
assert(networkThread->IsCurrent());
webrtc::JsepIceCandidate iceCandidate("", 0);
iceCandidate.SetCandidate(candidate);
std::string serializedCandidate;
if (iceCandidate.ToString(&serializedCandidate)) {
std::vector<std::string> arrayOfOne;
arrayOfOne.push_back(serializedCandidate);
SignalCandidatesGathered(arrayOfOne);
webrtc::JsepIceCandidate parseCandidate("", 0);
if (parseCandidate.Initialize(serializedCandidate, nullptr)) {
auto candidate = parseCandidate.candidate();
}
}
}
void Connector::CandidateGatheringState(cricket::IceTransportInternal *transport) {
if (transport->gathering_state() == cricket::IceGatheringState::kIceGatheringComplete) {
/*if (collectedLocalCandidates.size() != 0) {
SignalCandidatesGathered(collectedLocalCandidates);
}*/
}
}
void Connector::TransportStateChanged(cricket::IceTransportInternal *transport) {
auto state = transport->GetIceTransportState();
switch (state) {
case webrtc::IceTransportState::kConnected:
case webrtc::IceTransportState::kCompleted:
SignalReadyToSendStateChanged(true);
printf("===== State: Connected\n");
break;
default:
SignalReadyToSendStateChanged(false);
printf("===== State: Disconnected\n");
break;
}
}
void Connector::TransportRoleConflict(cricket::IceTransportInternal *transport) {
printf("===== Role conflict\n");
}
void Connector::Ready(rtc::AsyncPacketSocket *) {
SignalMessage(message::Ready());
void Connector::TransportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t &timestamp, __unused int unused) {
rtc::CopyOnWriteBuffer data;
data.AppendData(bytes, size);
SignalPacketReceived(data);
}
void Connector::AddEndpointRelayTcpObfuscated(const rtc::SocketAddress& addr, const Relay::PeerTag& peer_tag) {
thread->Invoke<void>(RTC_FROM_HERE, [this, addr, peer_tag]() {
std::unique_ptr<rtc::AsyncPacketSocket> sock(socket_factory.CreateClientTcpSocket(
rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0),
addr, proxy_info, "", rtc::PacketSocketTcpOptions()));
AddEndpoint(std::make_unique<EndpointRelayObfuscatedTcp>(std::move(sock), peer_tag, layer.get()));
void Connector::SendPacket(const rtc::CopyOnWriteBuffer& data) {
networkThread->Invoke<void>(RTC_FROM_HERE, [this, data] {
rtc::PacketOptions options;
transportChannel->SendPacket((const char *)data.data(), data.size(), options, 0);
});
}
void Connector::AddEndpointRelayUdp(const rtc::SocketAddress& addr, const Relay::PeerTag& peer_tag) {
thread->Invoke<void>(RTC_FROM_HERE, [this, addr, peer_tag]() {
assert(socket);
AddEndpoint(std::make_unique<EndpointRelayUdp>(addr, peer_tag, socket.get(), layer.get()));
});
}
void Connector::SetEndpointP2p(const rtc::SocketAddress& addr) {
thread->Invoke<void>(RTC_FROM_HERE, [this, addr]() {
assert(socket);
if (auto ep = GetP2pEndpoint())
DeleteEndpoint(ep);
AddEndpoint(std::make_unique<EndpointP2p>(addr, socket.get(), layer.get()));
});
}
Connector::~Connector() {
thread->Invoke<void>(RTC_FROM_HERE, [this]() {
pinger.Stop();
active_endpoint = nullptr;
endpoints.clear();
ping_history.clear();
});
}
void Connector::RecvMessage(const message::Base& msg, EndpointBase *endpoint) {
if (msg.ID == message::tDisconnected && endpoint->type == EndpointBase::Type::RelayObfuscatedTcp) {
thread->PostDelayedTask(webrtc::ToQueuedTask([this, endpoint]() {
if (endpoints.find(endpoint) == endpoints.end())
return;
auto final_ep = dynamic_cast<EndpointRelayObfuscatedTcp *>(endpoint);
if (!final_ep)
return;
std::unique_ptr<rtc::AsyncPacketSocket> sock(socket_factory.CreateClientTcpSocket(
rtc::SocketAddress(rtc::GetAnyIP(AF_INET), 0),
final_ep->address, proxy_info, "", rtc::PacketSocketTcpOptions()));
final_ep->Reconnect(std::move(sock));
}), tcp_reconnect_delay);
if (active_endpoint == endpoint)
ResetActiveEndpoint();
return;
}
if (auto msg_ping = dynamic_cast<const message::Ping *>(&msg)) {
message::Pong msg_pong;
msg_pong.id = msg_ping->id;
endpoint->SendMessage(msg_pong);
return;
}
if (auto msg_pong = dynamic_cast<const message::Pong *>(&msg)) {
ping_history[endpoint].Pong(msg_pong->id);
return;
}
// fallback if no active endpoint set
if (!active_endpoint)
active_endpoint = endpoint;
SignalMessage(msg);
}
void Connector::SendMessage(const message::Base& msg) {
if (!active_endpoint || multicast_types.find(msg.ID) != multicast_types.end()) {
for (const auto& ep : endpoints) {
ep.first->SendMessage(msg);
if (auto msg_ping = dynamic_cast<const message::Ping *>(&msg))
ping_history[ep.first].Ping(msg_ping->id);
}
return;
}
active_endpoint->SendMessage(msg);
}
EndpointP2p *Connector::GetP2pEndpoint() const {
for (const auto& ep : endpoints)
if (auto ep_p2p = dynamic_cast<EndpointP2p *>(ep.first))
return ep_p2p;
return nullptr;
}
void Connector::AddEndpoint(std::unique_ptr<EndpointBase> endpoint) {
EndpointBase *ep = endpoint.get();
ep->SignalMessage.connect(this, &Connector::RecvMessage);
endpoints[ep] = std::move(endpoint);
ping_history[ep] = PingHistory();
}
void Connector::DeleteEndpoint(EndpointBase *ep) {
// TODO: must be invoked to thread when become public
endpoints.erase(ep);
ping_history.erase(ep);
}
void Connector::ResetActiveEndpoint() {
active_endpoint = nullptr;
}
void Connector::UpdateActiveEndpoint() {
if (ping_history.empty())
return;
if (ping_history.size() == 1) {
active_endpoint = ping_history.begin()->first;
return;
}
std::vector<std::pair<double, EndpointBase*>> times;
for (auto ping : ping_history)
times.emplace_back(ping.second.Average(), ping.first);
std::sort(times.begin(), times.end());
EndpointBase *candidate = times.front().second;
if (!active_endpoint || (active_endpoint != candidate &&
ping_history[active_endpoint].Average() - times.front().first > endpoint_ping_diff_ms))
active_endpoint = candidate;
message::Ping msg;
msg.id = ++ping_seq;
SendMessage(msg);
}
void Connector::SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username,
const std::string& password) {
proxy_info.type = type;
proxy_info.address = addr;
proxy_info.username = username;
proxy_info.password = rtc::CryptString();
}

View File

@ -4,7 +4,6 @@
#include "Connector.h"
#include "MediaEngineWebrtc.h"
#include "Layer92.h"
#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/socket_address.h"
@ -30,21 +29,21 @@ public:
Reconnecting,
};
explicit Controller(bool is_outgoing, const EncryptionKey& encryption_key, size_t init_timeout, size_t reconnect_timeout);
explicit Controller(bool is_outgoing, size_t init_timeout, size_t reconnect_timeout);
~Controller() override;
void AddEndpoint(const rtc::SocketAddress& address, const Relay::PeerTag& peer_tag, EndpointType type);
void Start();
void SetNetworkType(message::NetworkType network_type);
//void SetNetworkType(message::NetworkType network_type);
void SetDataSaving(bool data_saving);
void SetMute(bool mute);
void AttachVideoView(VideoMetalView *videoView);
void SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username,
const std::string& password);
void AttachVideoView(rtc::VideoSinkInterface<webrtc::VideoFrame> *sink);
void SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username, const std::string& password);
void AddRemoteCandidates(const std::vector<std::string> &candidates);
static std::map<message::NetworkType, MediaEngineWebrtc::NetworkParams> network_params;
//static std::map<message::NetworkType, MediaEngineWebrtc::NetworkParams> network_params;
static MediaEngineWebrtc::NetworkParams default_network_params;
static MediaEngineWebrtc::NetworkParams datasaving_network_params;
sigslot::signal1<State> SignalNewState;
sigslot::signal1<const std::vector<std::string>&> SignalCandidatesGathered;
private:
std::unique_ptr<rtc::Thread> thread;
@ -59,17 +58,17 @@ private:
const size_t reconnect_timeout;
bool local_datasaving;
bool final_datasaving;
message::NetworkType local_network_type;
message::NetworkType final_network_type;
//message::NetworkType local_network_type;
//message::NetworkType final_network_type;
template <class Closure> void StartRepeating(Closure&& closure);
void StopRepeating();
void NewMessage(const message::Base& msg);
void PacketReceived(const rtc::CopyOnWriteBuffer &);
void WriteableStateChanged(bool);
void CandidatesGathered(const std::vector<std::string> &);
void SetFail();
void Play(const int16_t *data, size_t size);
void Record(int16_t *data, size_t size);
void SendRtp(rtc::CopyOnWriteBuffer packet);
void UpdateNetworkParams(const message::RtpStream& rtp);
//void UpdateNetworkParams(const message::RtpStream& rtp);
};

View File

@ -1,24 +1,22 @@
#include "Controller.h"
#include "Layer92.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/time_utils.h"
#include "rtc_base/message_handler.h"
#include <memory>
std::map<message::NetworkType, MediaEngineWebrtc::NetworkParams> Controller::network_params = {
/*std::map<message::NetworkType, MediaEngineWebrtc::NetworkParams> Controller::network_params = {
{message::NetworkType::nGprs, {6, 8, 6, 120, false, false, false}},
{message::NetworkType::nEdge, {6, 16, 6, 120, false, false, false}},
{message::NetworkType::n3gOrAbove, {6, 32, 16, 60, false, false, false}},
};
MediaEngineWebrtc::NetworkParams Controller::default_network_params = {6, 32, 16, 30, false, false, false};
MediaEngineWebrtc::NetworkParams Controller::datasaving_network_params = {6, 8, 6, 120, false, false, true};
MediaEngineWebrtc::NetworkParams Controller::datasaving_network_params = {6, 8, 6, 120, false, false, true};*/
Controller::Controller(bool is_outgoing, const EncryptionKey& encryption_key, size_t init_timeout, size_t reconnect_timeout)
Controller::Controller(bool is_outgoing, size_t init_timeout, size_t reconnect_timeout)
: thread(rtc::Thread::Create())
, connector(std::make_unique<Connector>(std::make_unique<Layer92>(encryption_key, is_outgoing)))
, connector(std::make_unique<Connector>(is_outgoing))
, state(State::Starting)
, last_recv_time(rtc::TimeMillis())
, last_send_time(rtc::TimeMillis())
@ -27,11 +25,16 @@ Controller::Controller(bool is_outgoing, const EncryptionKey& encryption_key, si
, reconnect_timeout(reconnect_timeout * 1000)
, local_datasaving(false)
, final_datasaving(false)
, local_network_type(message::NetworkType::nUnknown)
, final_network_type(message::NetworkType::nUnknown)
{
connector->SignalMessage.connect(this, &Controller::NewMessage);
connector->SignalReadyToSendStateChanged.connect(this, &Controller::WriteableStateChanged);
connector->SignalPacketReceived.connect(this, &Controller::PacketReceived);
connector->SignalCandidatesGathered.connect(this, &Controller::CandidatesGathered);
thread->Start();
thread->Invoke<void>(RTC_FROM_HERE, [this, is_outgoing]() {
media.reset(new MediaEngineWebrtc(is_outgoing));
media->Send.connect(this, &Controller::SendRtp);
});
}
Controller::~Controller() {
@ -41,121 +44,37 @@ Controller::~Controller() {
});
}
void Controller::AddEndpoint(const rtc::SocketAddress& address, const Relay::PeerTag &peer_tag,
Controller::EndpointType type) {
if (type == EndpointType::UDP)
connector->AddEndpointRelayUdp(address, peer_tag);
else if (type == EndpointType::TCP)
connector->AddEndpointRelayTcpObfuscated(address, peer_tag);
else if (type == EndpointType::P2P)
connector->SetEndpointP2p(address);
}
void Controller::Start() {
last_recv_time = rtc::TimeMillis();
connector->Start();
}
void Controller::NewMessage(const message::Base& msg) {
if (msg.ID == message::tReady && state == State::Starting) {
state = State::WaitInit;
SignalNewState(state);
StartRepeating([this]() {
message::Init msg;
msg.minVer = ProtocolBase::minimal_version;
msg.ver = ProtocolBase::actual_version;
connector->SendMessage(msg);
//if (rtc::TimeMillis() - last_recv_time > init_timeout)
// SetFail();
return webrtc::TimeDelta::seconds(1);
});
} else if ((msg.ID == message::tInit || msg.ID == message::tInitAck) && state == State::WaitInit) {
state = State::WaitInitAck;
SignalNewState(state);
StartRepeating([this]() {
message::InitAck msg;
// TODO: version matching
msg.minVer = ProtocolBase::minimal_version;
msg.ver = ProtocolBase::actual_version;
connector->SendMessage(msg);
//if (rtc::TimeMillis() - last_recv_time > init_timeout)
// SetFail();
return webrtc::TimeDelta::seconds(1);
});
} else if ((msg.ID == message::tInitAck || msg.ID == message::tRtpStream) && state == State::WaitInitAck) {
state = State::Established;
SignalNewState(state);
thread->PostTask(RTC_FROM_HERE, [this]() {
media = std::make_unique<MediaEngineWebrtc>(is_outgoing);
media->Send.connect(this, &Controller::SendRtp);
});
StartRepeating([this]() {
if (state == State::Established && rtc::TimeMillis() - last_recv_time > 1000) {
connector->ResetActiveEndpoint();
state = State::Reconnecting;
SignalNewState(state);
} else if (state == State::Reconnecting && rtc::TimeMillis() - last_recv_time > reconnect_timeout) {
//SetFail();
}
return webrtc::TimeDelta::seconds(1);
});
} if ((msg.ID == message::tRtpStream) && (state == State::Established || state == State::Reconnecting)) {
const auto msg_rtp = *dynamic_cast<const message::RtpStream *>(&msg);
thread->PostTask(RTC_FROM_HERE, [this, msg_rtp]() {
void Controller::PacketReceived(const rtc::CopyOnWriteBuffer &data) {
thread->PostTask(RTC_FROM_HERE, [this, data]() {
if (media) {
media->Receive(msg_rtp.data);
UpdateNetworkParams(msg_rtp);
media->Receive(data);
}
});
if (!webrtc::RtpUtility::RtpHeaderParser(msg_rtp.data.data(), msg_rtp.data.size()).RTCP()) {
//printf("rtp received size %d\n", (int)(msg_rtp.data.size()));
last_recv_time = rtc::TimeMillis();
if (state == State::Reconnecting) {
state = State::Established;
SignalNewState(state);
}
void Controller::WriteableStateChanged(bool isWriteable) {
if (isWriteable) {
SignalNewState(State::Established);
} else {
//printf("rtcp received size %d\n", (int)(msg_rtp.data.size()));
SignalNewState(State::Reconnecting);
}
} else if (msg.ID == message::tBufferOverflow ||
msg.ID == message::tPacketIncorrect ||
msg.ID == message::tWrongProtocol) {
SetFail();
thread->PostTask(RTC_FROM_HERE, [this, isWriteable]() {
if (media) {
media->SetCanSendPackets(isWriteable);
}
}
template<class Closure>
void Controller::StartRepeating(Closure&& closure) {
//StopRepeating();
repeatable = webrtc::RepeatingTaskHandle::Start(thread.get(), std::forward<Closure>(closure));
}
void Controller::StopRepeating() {
thread->Invoke<void>(RTC_FROM_HERE, [this]() {
repeatable.Stop();
});
}
void Controller::SetFail() {
thread->PostTask(RTC_FROM_HERE, [this]() {
media = nullptr;
});
if (state != State::Failed) {
state = State::Failed;
SignalNewState(state);
}
StopRepeating();
}
void Controller::SendRtp(rtc::CopyOnWriteBuffer packet) {
message::RtpStream msg;
msg.data = packet;
msg.network_type = local_network_type;
msg.data_saving = local_datasaving;
connector->SendMessage(msg);
connector->SendPacket(packet);
}
void Controller::UpdateNetworkParams(const message::RtpStream& rtp) {
/*void Controller::UpdateNetworkParams(const message::RtpStream& rtp) {
bool new_datasaving = local_datasaving || rtp.data_saving;
if (!new_datasaving) {
final_datasaving = false;
@ -172,17 +91,17 @@ void Controller::UpdateNetworkParams(const message::RtpStream& rtp) {
final_datasaving = true;
media->SetNetworkParams(datasaving_network_params);
}
}
}*/
void Controller::AttachVideoView(VideoMetalView *videoView) {
thread->PostTask(RTC_FROM_HERE, [this, videoView]() {
media->AttachVideoView(videoView);
void Controller::AttachVideoView(rtc::VideoSinkInterface<webrtc::VideoFrame> *sink) {
thread->PostTask(RTC_FROM_HERE, [this, sink]() {
media->AttachVideoView(sink);
});
}
void Controller::SetNetworkType(message::NetworkType network_type) {
/*void Controller::SetNetworkType(message::NetworkType network_type) {
local_network_type = network_type;
}
}*/
void Controller::SetDataSaving(bool data_saving) {
local_datasaving = data_saving;
@ -195,7 +114,13 @@ void Controller::SetMute(bool mute) {
});
}
void Controller::SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username,
const std::string& password) {
connector->SetProxy(type, addr, username, password);
void Controller::SetProxy(rtc::ProxyType type, const rtc::SocketAddress& addr, const std::string& username, const std::string& password) {
}
void Controller::CandidatesGathered(const std::vector<std::string> &candidates) {
SignalCandidatesGathered(candidates);
}
void Controller::AddRemoteCandidates(const std::vector<std::string> &candidates) {
connector->AddRemoteCandidates(candidates);
}

View File

@ -1,126 +0,0 @@
#ifndef DEMO_ENDPOINT_H
#define DEMO_ENDPOINT_H
#include "LayerBase.h"
#include "Message.h"
#include "rtc_base/async_packet_socket.h"
#include "rtc_base/buffer_queue.h"
#include "rtc_base/socket_address.h"
class Connector;
class EndpointBase : public sigslot::has_slots<> {
public:
enum Type {
Unknown,
RelayUdp,
RelayObfuscatedTcp,
P2p,
};
EndpointBase(const EndpointBase&) = delete;
virtual void SendMessage(const message::Base&) = 0;
sigslot::signal2<const message::Base&, EndpointBase *> SignalMessage;
const Type type;
protected:
explicit EndpointBase(LayerBase *layer, Type type);
virtual void RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us);
virtual void SendPacket(const uint8_t *data, size_t size) = 0;
LayerBase *layer;
rtc::PacketOptions packet_options;
std::unique_ptr<rtc::ByteBufferReader> in_buffer;
size_t in_remains;
};
class Relay {
public:
typedef unsigned char PeerTag[16];
virtual ~Relay() = default;
protected:
explicit Relay(const PeerTag& peer_tag);
bool CheckPacket(rtc::ByteBufferReader *packet);
const rtc::Buffer& PreparePacket(const rtc::Buffer& packet);
PeerTag peer_tag; // how to initialize it in initializer list?
private:
rtc::Buffer buffer;
};
class EndpointUdp : public EndpointBase {
public:
const rtc::SocketAddress address;
protected:
friend class Connector;
// friend void Connector::RecvPacket(rtc::AsyncPacketSocket *, const char *, size_t,
// const rtc::SocketAddress&, const int64_t&);
EndpointUdp(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer, Type type);
void SendPacket(const uint8_t *data, size_t size) override;
rtc::AsyncPacketSocket *socket;
};
class EndpointTcp : public EndpointBase {
public:
const rtc::SocketAddress address;
void Reconnect(std::unique_ptr<rtc::AsyncPacketSocket> socket_);
protected:
explicit EndpointTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket, LayerBase *layer, Type type);
void SendPacket(const uint8_t *data, size_t size) override;
virtual void Ready(rtc::AsyncPacketSocket *) = 0;
virtual void Close(rtc::AsyncPacketSocket *, int) = 0;
std::unique_ptr<rtc::AsyncPacketSocket> socket;
};
class EndpointRelayObfuscatedTcp final : public Relay, public EndpointTcp {
public:
EndpointRelayObfuscatedTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket, const PeerTag& peer_tag,
LayerBase *layer);
void SendMessage(const message::Base&) override;
private:
void RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) override;
void Ready(rtc::AsyncPacketSocket *) override;
void Close(rtc::AsyncPacketSocket *, int) override;
void SendPacket(const uint8_t *data, size_t size) override;
TCPO2State recvState;
TCPO2State sendState;
};
class EndpointRelayUdp final : public Relay, public EndpointUdp {
public:
EndpointRelayUdp(const rtc::SocketAddress& addr, const PeerTag& peer_tag,
rtc::AsyncPacketSocket *socket, LayerBase *layer);
void SendMessage(const message::Base&) override;
private:
void RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) override;
};
class EndpointP2p final : public EndpointUdp {
public:
EndpointP2p(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer);
void SendMessage(const message::Base&) override;
private:
void RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) override;
};
#endif //DEMO_ENDPOINT_H

View File

@ -1,205 +0,0 @@
#include "Endpoint.h"
#include "rtc_base/buffer.h"
#include "rtc_base/byte_buffer.h"
#include <memory>
#include <queue>
EndpointBase::EndpointBase(LayerBase *layer, Type type)
: type(type)
, layer(layer)
, in_buffer(std::make_unique<rtc::ByteBufferReader>(nullptr, 0))
, in_remains(0) {}
void EndpointBase::RecvPacket(rtc::AsyncPacketSocket *, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
if (in_buffer && in_buffer->Length() > 0) {
rtc::Buffer tmp(in_buffer->Data(), in_buffer->Length() + len);
memcpy(tmp.data() + in_buffer->Length(), data, len);
in_buffer = std::make_unique<rtc::ByteBufferReader>(reinterpret_cast<const char *>(tmp.data()), tmp.size());
} else
in_buffer = std::make_unique<rtc::ByteBufferReader>(data, len);
}
EndpointUdp::EndpointUdp(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer, Type type)
: EndpointBase(layer, type)
, address(addr)
, socket(socket) {}
void EndpointUdp::SendPacket(const uint8_t *data, size_t size) {
socket->SendTo(data, size, address, packet_options);
}
EndpointTcp::EndpointTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket, LayerBase *layer, Type type)
: EndpointBase(layer, type)
, address(socket->GetRemoteAddress())
, socket(nullptr) {
Reconnect(std::move(socket));
}
void EndpointTcp::Reconnect(std::unique_ptr<rtc::AsyncPacketSocket> socket_) {
socket = std::move(socket_);
socket->SignalReadPacket.connect(dynamic_cast<EndpointBase *>(this), &EndpointTcp::RecvPacket);
socket->SignalReadyToSend.connect(this, &EndpointTcp::Ready);
socket->SignalClose.connect(this, &EndpointTcp::Close);
}
void EndpointTcp::SendPacket(const uint8_t *data, size_t size) {
socket->Send(data, size, packet_options);
}
Relay::Relay(const PeerTag& peer_tag_) : peer_tag() {
memcpy(peer_tag, peer_tag_, sizeof(PeerTag));
}
bool Relay::CheckPacket(rtc::ByteBufferReader *packet) {
if (packet->Length() >= 16 && memcmp(peer_tag, packet->Data(), 16) == 0) {
packet->Consume(16);
return true;
}
return false;
}
const rtc::Buffer& Relay::PreparePacket(const rtc::Buffer& packet) {
buffer.Clear();
if (!packet.empty()) {
buffer.AppendData(peer_tag, 16);
buffer.AppendData(packet);
}
return buffer;
}
EndpointRelayObfuscatedTcp::EndpointRelayObfuscatedTcp(std::unique_ptr<rtc::AsyncPacketSocket> socket,
const PeerTag& peer_tag, LayerBase *layer)
: Relay(peer_tag)
, EndpointTcp(std::move(socket), layer, Type::RelayObfuscatedTcp)
, recvState()
, sendState() {}
void EndpointRelayObfuscatedTcp::Ready(rtc::AsyncPacketSocket *) {
unsigned char buf[64];
layer->GenerateTCPO2States(buf, &recvState, &sendState);
EndpointTcp::SendPacket(buf, 64);
SignalMessage(message::Connected(), this);
}
void EndpointRelayObfuscatedTcp::Close(rtc::AsyncPacketSocket *, int) {
SignalMessage(message::Disconnected(), this);
}
void EndpointRelayObfuscatedTcp::RecvPacket(rtc::AsyncPacketSocket *socket, const char *data, size_t packet_len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
EndpointBase::RecvPacket(socket, data, packet_len, remote_addr, packet_time_us);
do {
if (in_remains > in_buffer->Length())
break;
if (in_remains > 0 && CheckPacket(in_buffer.get())) {
auto msg = layer->DecodePacket(*in_buffer);
if (msg)
SignalMessage(*msg, this);
}
unsigned char len1;
size_t packetLen = 0;
if (!in_buffer->ReadUInt8(&len1))
break;
layer->EncryptForTCPO2(&len1, 1, &recvState);
if (len1 < 0x7F) {
packetLen = (size_t) len1 * 4;
} else {
unsigned char len2[3];
if (!in_buffer->ReadBytes(reinterpret_cast<char *>(&len2), 3)) {
SignalMessage(message::PacketIncorrect(), this);
return;
}
layer->EncryptForTCPO2(len2, 3, &recvState);
packetLen = ((size_t) len2[0] | ((size_t) len2[1] << 8) | ((size_t) len2[2] << 16)) * 4;
}
in_remains = packetLen;
if (packetLen > in_buffer->Length()) {
in_remains = packetLen;
break;
}
} while (true);
}
void EndpointRelayObfuscatedTcp::SendMessage(const message::Base& msg_base) {
if (socket->GetState() == rtc::AsyncPacketSocket::State::STATE_CLOSED)
return;
const rtc::Buffer& out = PreparePacket(layer->EncodePacket(&msg_base));
if (!out.empty())
SendPacket(out.data(), out.size());
}
void EndpointRelayObfuscatedTcp::SendPacket(const uint8_t *data, size_t size) {
rtc::ByteBufferWriter out;
size_t len = size / 4;
if (len < 0x7F) {
out.WriteUInt8(len);
} else {
out.WriteUInt8(0x7F);
out.WriteUInt8(len & 0xFF);
out.WriteUInt8((len >> 8) & 0xFF);
out.WriteUInt8((len >> 16) & 0xFF);
}
out.WriteBytes(reinterpret_cast<const char *>(data), size);
layer->EncryptForTCPO2(reinterpret_cast<unsigned char *>(out.ReserveWriteBuffer(0)),
out.Length(), &sendState);
EndpointTcp::SendPacket(reinterpret_cast<const uint8_t *>(out.Data()), out.Length());
}
EndpointRelayUdp::EndpointRelayUdp(const rtc::SocketAddress& addr, const PeerTag& peer_tag,
rtc::AsyncPacketSocket *socket, LayerBase *layer)
: Relay(peer_tag)
, EndpointUdp(addr, socket, layer, Type::RelayUdp) {}
void EndpointRelayUdp::SendMessage(const message::Base& msg_base) {
const rtc::Buffer& out = PreparePacket(layer->EncodePacket(&msg_base));
if (!out.empty())
SendPacket(out.data(), out.size());
}
void EndpointRelayUdp::RecvPacket(rtc::AsyncPacketSocket *sock, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
bool glued;
bool processed = false;
do {
EndpointBase::RecvPacket(sock, data, len, remote_addr, packet_time_us);
glued = in_buffer->Length() > len;
std::unique_ptr<message::Base> msg;
while (CheckPacket(in_buffer.get()) && (msg = layer->DecodePacket(*in_buffer))) {
processed = true;
SignalMessage(*msg, this);
}
if (!processed)
in_buffer = std::make_unique<rtc::ByteBufferReader>(nullptr, 0);
} while (!processed && glued);
}
EndpointP2p::EndpointP2p(const rtc::SocketAddress& addr, rtc::AsyncPacketSocket *socket, LayerBase *layer)
: EndpointUdp(addr, socket, layer, Type::P2p) {}
void EndpointP2p::SendMessage(const message::Base& msg_base) {
rtc::Buffer out = layer->EncodePacket(&msg_base);
if (!out.empty())
SendPacket(out.data(), out.size());
}
void EndpointP2p::RecvPacket(rtc::AsyncPacketSocket *sock, const char *data, size_t len,
const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us) {
bool glued;
bool processed = false;
do {
EndpointBase::RecvPacket(sock, data, len, remote_addr, packet_time_us);
glued = in_buffer->Length() > len;
while (auto msg = layer->DecodePacket(*in_buffer)) {
processed = true;
SignalMessage(*msg, this);
}
if (!processed)
in_buffer = std::make_unique<rtc::ByteBufferReader>(nullptr, 0);
} while (!processed && glued);
}

View File

@ -1,238 +0,0 @@
#include "Layer92.h"
#include "Message.h"
#include "rtc_base/byte_buffer.h"
#include "rtc_base/byte_order.h"
#include <cstring>
#include <algorithm>
namespace {
#define TLID_UDP_REFLECTOR_SELF_INFO 0xc01572c7
#define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C
#ifdef _MSC_VER
#define MSC_STACK_FALLBACK(a, b) (b)
#else
#define MSC_STACK_FALLBACK(a, b) (a)
#endif
}
Layer92::Layer92(const EncryptionKey& encryptionKey_, bool isOutgoing)
: LayerBase(92)
, encryptionKey()
, isOutgoing(isOutgoing) {
memcpy(encryptionKey, encryptionKey_, sizeof(encryptionKey));
}
void Layer92::EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2State *state) {
crypto.aes_ctr_encrypt(buffer, len, state->key, state->iv, state->ecount, &state->num);
}
void Layer92::GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState) {
memset(recvState, 0, sizeof(TCPO2State));
memset(sendState, 0, sizeof(TCPO2State));
unsigned char nonce[64];
uint32_t *first = reinterpret_cast<uint32_t *>(nonce), *second = first + 1;
uint32_t first1 = 0x44414548U, first2 = 0x54534f50U, first3 = 0x20544547U, first4 = 0x20544547U, first5 = 0xeeeeeeeeU;
uint32_t second1 = 0;
do {
crypto.rand_bytes(nonce, sizeof(nonce));
} while (*first == first1 || *first == first2 || *first == first3 || *first == first4 || *first == first5 ||
*second == second1 || *reinterpret_cast<unsigned char *>(nonce) == 0xef);
// prepare encryption key/iv
memcpy(sendState->key, nonce + 8, 32);
memcpy(sendState->iv, nonce + 8 + 32, 16);
// prepare decryption key/iv
char reversed[48];
memcpy(reversed, nonce + 8, sizeof(reversed));
std::reverse(reversed, reversed + sizeof(reversed));
memcpy(recvState->key, reversed, 32);
memcpy(recvState->iv, reversed + 32, 16);
// write protocol identifier
*reinterpret_cast<uint32_t *>(nonce + 56) = 0xefefefefU;
memcpy(buffer, nonce, 56);
EncryptForTCPO2(nonce, sizeof(nonce), sendState);
memcpy(buffer + 56, nonce + 56, 8);
}
std::unique_ptr<message::Base> Layer92::DecodeRelayPacket(rtc::ByteBufferReader& in) {
if (in.Length() < 12 + 4 + 16)
return nullptr;
if (*reinterpret_cast<const uint64_t *>(in.Data()) != 0xFFFFFFFFFFFFFFFFLL)
return nullptr;
if (*reinterpret_cast<const uint32_t *>(in.Data() + 8) != 0xFFFFFFFF)
return nullptr;
// relay special request response
in.Consume(12);
uint32_t tlid;
if (!in.ReadUInt32(&tlid))
return nullptr;
if (tlid == TLID_UDP_REFLECTOR_SELF_INFO) {
if (in.Length() < 32)
return nullptr;
auto msg = std::make_unique<message::RelayPong>();
in.ReadUInt32(&msg->date);
in.ReadUInt64(&msg->query_id);
in6_addr myIP{};
in.ReadBytes(reinterpret_cast<char *>(&myIP), 16);
uint32_t myPort; // int32_t in src; why not uint16_t?
in.ReadUInt32(&myPort);
msg->my_addr = rtc::SocketAddress(rtc::IPAddress(myIP), myPort);
return msg;
}
if (tlid == TLID_UDP_REFLECTOR_PEER_INFO) {
if (in.Length() < 16)
return nullptr;
auto msg = std::make_unique<message::PeerInfo>();
uint32_t myAddr;
uint32_t myPort;
uint32_t peerAddr;
uint32_t peerPort;
in.ReadUInt32(&myAddr);
in.ReadUInt32(&myPort);
in.ReadUInt32(&peerAddr);
in.ReadUInt32(&peerPort);
msg->my_addr = rtc::SocketAddress(myAddr, myPort);
msg->peer_addr = rtc::SocketAddress(peerAddr, peerPort);
return msg;
}
return nullptr;
}
void Layer92::KDF2(unsigned char *msgKey, size_t x, unsigned char *aesKey, unsigned char *aesIv) {
uint8_t sA[32], sB[32];
uint8_t buf[16 + 36];
memcpy(buf, msgKey, 16);
memcpy(buf + 16, encryptionKey + x, 36);
crypto.sha256(buf, 16 + 36, sA);
memcpy(buf, encryptionKey + 40 + x, 36);
memcpy(buf + 36, msgKey, 16);
crypto.sha256(buf, 36 + 16, sB);
memcpy(aesKey, sA, 8);
memcpy(aesKey + 8, sB + 8, 16);
memcpy(aesKey + 8 + 16, sA + 24, 8);
memcpy(aesIv, sB, 8);
memcpy(aesIv + 8, sA + 8, 16);
memcpy(aesIv + 8 + 16, sB + 24, 8);
}
std::unique_ptr<message::Base> Layer92::DecodeProtocolPacket(rtc::ByteBufferReader& in) {
unsigned char msgKey[16];
memcpy(msgKey, in.Data(), 16);
unsigned char decrypted[1500];
unsigned char aesKey[32], aesIv[32];
KDF2(msgKey, isOutgoing ? 8 : 0, aesKey, aesIv);
size_t decryptedLen = in.Length() - 16;
if (decryptedLen > sizeof(decrypted))
return nullptr;
if (decryptedLen % 16 != 0)
return nullptr; // wrong decrypted length
in.Consume(16);
crypto.aes_ige_decrypt((uint8_t *)in.Data(), decrypted, decryptedLen, aesKey, aesIv);
in.Consume(decryptedLen);
rtc::ByteBufferWriter buf;
size_t x = isOutgoing ? 8 : 0;
buf.WriteBytes((char *)encryptionKey + 88 + x, 32);
buf.WriteBytes((char *)decrypted, decryptedLen);
unsigned char msgKeyLarge[32];
crypto.sha256((uint8_t *)buf.Data(), buf.Length(), msgKeyLarge);
if (memcmp(msgKey, msgKeyLarge + 8, 16) != 0)
return nullptr; // packet has wrong hash
uint16_t innerLen;
memcpy(&innerLen, decrypted, 2);
if (innerLen > decryptedLen)
return nullptr; // packet has wrong inner length
// if (decryptedLen - innerLen < 16)
// return nullptr; // packet has too little padding
return protocol->ReadProtocolPacket(decrypted + 2, innerLen);
}
std::unique_ptr<message::Base> Layer92::DecodePacket(rtc::ByteBufferReader& in) {
auto msg = DecodeRelayPacket(in);
if (msg)
return msg;
return DecodeProtocolPacket(in);
}
rtc::Buffer Layer92::EncodePacket(const message::Base *msg_base) {
auto buf = EncodeRelayPacket(msg_base);
if (!buf.empty())
return buf;
return EncodeProtocolPacket(msg_base);
}
rtc::Buffer Layer92::EncodeRelayPacket(const message::Base *msg_base) {
if (msg_base->ID == message::tRelayPing) {
const auto *msg = dynamic_cast<const message::RelayPing *>(msg_base);
if (!msg)
return rtc::Buffer();
unsigned char buf[16];
memset(buf, 0xFF, 16);
return rtc::Buffer(buf, 16);
}
if (msg_base->ID == message::tGetPeerInfo) {
const auto *msg = dynamic_cast<const message::GetPeerInfo *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt32(-1);
out.WriteUInt32(-1);
out.WriteUInt32(-1);
out.WriteUInt32(-1);
int64_t id;
crypto.rand_bytes(reinterpret_cast<uint8_t*>(&id), 8);
out.WriteUInt64(id);
return rtc::Buffer(out.Data(), out.Length());
}
return rtc::Buffer();
}
rtc::Buffer Layer92::EncodeProtocolPacket(const message::Base *msg_base) {
rtc::Buffer internal = protocol->WriteProtocolPacket(msg_base);
if (internal.empty())
return rtc::Buffer();
rtc::ByteBufferWriter out;
rtc::ByteBufferWriter inner;
uint16_t len = internal.size();
inner.WriteBytes((char *)&len, 2); // for backward compatibility
inner.WriteBytes((char *)internal.data(), internal.size());
size_t padLen = 16 - inner.Length() % 16;
// if (padLen < 16)
// padLen += 16;
uint8_t padding[32];
crypto.rand_bytes(padding, padLen);
inner.WriteBytes((char *)padding, padLen);
assert(inner.Length() % 16 == 0);
unsigned char key[32], iv[32], msgKey[16];
rtc::ByteBufferWriter buf;
size_t x = isOutgoing ? 0 : 8;
buf.WriteBytes((char *)encryptionKey + 88 + x, 32);
buf.WriteBytes(inner.Data(), inner.Length());
unsigned char msgKeyLarge[32];
crypto.sha256((uint8_t *)buf.Data(), buf.Length(), msgKeyLarge);
memcpy(msgKey, msgKeyLarge + 8, 16);
KDF2(msgKey, isOutgoing ? 0 : 8, key, iv);
out.WriteBytes((char *)msgKey, 16);
unsigned char aesOut[MSC_STACK_FALLBACK(inner.Length(), 1500)];
crypto.aes_ige_encrypt((uint8_t *)inner.Data(), aesOut, inner.Length(), key, iv);
out.WriteBytes((char *)aesOut, inner.Length());
return rtc::Buffer(out.Data(), out.Length());
}

View File

@ -1,49 +0,0 @@
#ifndef DEMO_LAYER92_H
#define DEMO_LAYER92_H
#include "LayerBase.h"
#include "Message.h"
#include "Protocol10.h"
#include "rtc_base/byte_buffer.h"
#include <cstdint>
#include <cstddef>
struct CryptoFunctions {
void (*rand_bytes)(uint8_t* buffer, size_t length);
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
};
typedef unsigned char EncryptionKey[256];
class Layer92 : public LayerBase {
public:
static CryptoFunctions crypto;
explicit Layer92(const EncryptionKey& encryptionKey, bool isOutgoing);
void EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2State *state) override;
void GenerateTCPO2States(unsigned char *buffer, TCPO2State *recvState, TCPO2State *sendState) override;
std::unique_ptr<message::Base> DecodePacket(rtc::ByteBufferReader& in) override;
rtc::Buffer EncodePacket(const message::Base *msg_base) override;
private:
void KDF2(unsigned char* msgKey, size_t x, unsigned char *aesKey, unsigned char *aesIv);
std::unique_ptr<message::Base> DecodeRelayPacket(rtc::ByteBufferReader& in);
std::unique_ptr<message::Base> DecodeProtocolPacket(rtc::ByteBufferReader& in);
rtc::Buffer EncodeRelayPacket(const message::Base *msg_base);
rtc::Buffer EncodeProtocolPacket(const message::Base *msg_base);
EncryptionKey encryptionKey;
bool isOutgoing;
};
#endif //DEMO_LAYER92_H

View File

@ -1,17 +0,0 @@
#include "LayerBase.h"
#include "Layer92.h"
bool LayerBase::ChangeProtocol(uint32_t protocol_version) {
if (protocol && protocol->version == protocol_version)
return true;
auto new_protocol = ProtocolBase::CreateProtocol(protocol_version);
if (!new_protocol)
return false;
protocol = std::move(new_protocol);
return true;
}
LayerBase::LayerBase(uint32_t version)
: version(version)
, protocol(ProtocolBase::CreateProtocol(ProtocolBase::actual_version)) {}

View File

@ -1,38 +0,0 @@
#ifndef DEMO_LAYERBASE_H
#define DEMO_LAYERBASE_H
#include "ProtocolBase.h"
#include "rtc_base/buffer.h"
#include "rtc_base/byte_buffer.h"
#include <map>
#include <memory>
struct TCPO2State {
unsigned char key[32];
unsigned char iv[16];
unsigned char ecount[16];
uint32_t num;
};
class LayerBase {
public:
bool ChangeProtocol(uint32_t protocol_version);
virtual ~LayerBase() = default;
virtual void EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2State *state) = 0;
virtual void GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState) = 0;
virtual std::unique_ptr<message::Base> DecodePacket(rtc::ByteBufferReader& in) = 0;
virtual rtc::Buffer EncodePacket(const message::Base *msg_base) = 0;
const uint32_t version;
protected:
explicit LayerBase(uint32_t version);
std::unique_ptr<ProtocolBase> protocol;
};
#endif //DEMO_LAYERBASE_H

View File

@ -12,7 +12,7 @@ public:
MediaEngineBase() = default;
virtual ~MediaEngineBase() = default;
sigslot::signal1<rtc::CopyOnWriteBuffer> Send;
virtual void Receive(rtc::CopyOnWriteBuffer) = 0;
};

View File

@ -1,8 +1,8 @@
#ifndef DEMO_MEDIAENGINEWEBRTC_H
#define DEMO_MEDIAENGINEWEBRTC_H
#include "MediaEngineBase.h"
#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "api/transport/field_trial_based_config.h"
#include "call/call.h"
@ -15,7 +15,7 @@
#import "VideoCameraCapturer.h"
#import "VideoMetalView.h"
class MediaEngineWebrtc : public MediaEngineBase {
class MediaEngineWebrtc : public sigslot::has_slots<> {
public:
struct NetworkParams {
uint8_t min_bitrate_kbps;
@ -27,40 +27,28 @@ public:
bool noise_suppression;
};
explicit MediaEngineWebrtc(bool outgoing, bool send = true, bool recv = true);
~MediaEngineWebrtc() override;
void Receive(rtc::CopyOnWriteBuffer) override;
explicit MediaEngineWebrtc(bool outgoing);
~MediaEngineWebrtc();
void Receive(rtc::CopyOnWriteBuffer);
void OnSentPacket(const rtc::SentPacket& sent_packet);
void SetNetworkParams(const NetworkParams& params);
void SetMute(bool mute);
void AttachVideoView(VideoMetalView *videoView);
void SetCanSendPackets(bool);
void AttachVideoView(rtc::VideoSinkInterface<webrtc::VideoFrame> *sink);
sigslot::signal1<rtc::CopyOnWriteBuffer> Send;
private:
class Sender final : public cricket::MediaChannel::NetworkInterface {
public:
explicit Sender(MediaEngineWebrtc&);
explicit Sender(MediaEngineWebrtc &engine, bool isVideo);
bool SendPacket(rtc::CopyOnWriteBuffer *packet, const rtc::PacketOptions& options) override;
bool SendRtcp(rtc::CopyOnWriteBuffer *packet, const rtc::PacketOptions& options) override;
int SetOption(SocketType type, rtc::Socket::Option opt, int option) override;
private:
MediaEngineWebrtc &engine;
};
class AudioProcessor {
public:
AudioProcessor(webrtc::AudioTransport *transport, webrtc::TaskQueueFactory *task_queue_factory,
MediaEngineBase& engine, bool send, bool recv);
~AudioProcessor();
private:
bool send;
bool recv;
webrtc::AudioTransport *transport;
size_t delay_us;
int16_t *buf_send;
int16_t *buf_recv;
MediaEngineBase& engine;
std::unique_ptr<rtc::TaskQueue> task_queue_send;
std::unique_ptr<rtc::TaskQueue> task_queue_recv;
bool isVideo;
};
const uint32_t ssrc_send;
@ -73,7 +61,8 @@ private:
std::unique_ptr<webrtc::TaskQueueFactory> task_queue_factory;
webrtc::FieldTrialBasedConfig field_trials;
webrtc::LocalAudioSinkAdapter audio_source;
Sender data_sender;
Sender audio_sender;
Sender video_sender;
std::unique_ptr<cricket::VoiceMediaChannel> voice_channel;
std::unique_ptr<cricket::VideoMediaChannel> video_channel;
std::unique_ptr<webrtc::VideoBitrateAllocatorFactory> video_bitrate_allocator_factory;

View File

@ -23,16 +23,11 @@
#include "sdk/objc/native/api/video_encoder_factory.h"
#include "sdk/objc/native/api/video_decoder_factory.h"
#if WEBRTC_ENABLE_PROTOBUF
#include "modules/audio_coding/audio_network_adaptor/config.pb.h"
#endif
#include "PlatformCodecs.h"
#include "sdk/objc/native/src/objc_video_track_source.h"
#include "api/video_track_source_proxy.h"
#include "sdk/objc/api/RTCVideoRendererAdapter.h"
#include "sdk/objc/native/api/video_frame.h"
#include "api/media_types.h"
namespace {
const size_t frame_samples = 480;
@ -45,9 +40,10 @@ const uint8_t sdp_channels = 2;
const uint32_t sdp_bitrate = 0;
const uint32_t caller_ssrc = 1;
const uint32_t called_ssrc = 2;
const uint32_t caller_ssrc_video = 1;
const uint32_t called_ssrc_video = 2;
const uint32_t caller_ssrc_video = 3;
const uint32_t called_ssrc_video = 4;
const int extension_sequence = 1;
const int extension_sequence_video = 1;
}
static void AddDefaultFeedbackParams(cricket::VideoCodec* codec) {
@ -76,7 +72,6 @@ static std::vector<cricket::VideoCodec> AssignPayloadTypesAndDefaultCodecs(std::
static const int kLastDynamicPayloadType = 127;
int payload_type = kFirstDynamicPayloadType;
//input_formats.push_back(webrtc::SdpVideoFormat(cricket::kH264CodecName));
input_formats.push_back(webrtc::SdpVideoFormat(cricket::kRedCodecName));
input_formats.push_back(webrtc::SdpVideoFormat(cricket::kUlpfecCodecName));
@ -90,6 +85,9 @@ static std::vector<cricket::VideoCodec> AssignPayloadTypesAndDefaultCodecs(std::
input_formats.push_back(flexfec_format);
}*/
bool found = false;
bool useVP9 = true;
std::vector<cricket::VideoCodec> output_codecs;
for (const webrtc::SdpVideoFormat& format : input_formats) {
cricket::VideoCodec codec(format);
@ -97,11 +95,17 @@ static std::vector<cricket::VideoCodec> AssignPayloadTypesAndDefaultCodecs(std::
AddDefaultFeedbackParams(&codec);
output_codecs.push_back(codec);
if (codec.name == cricket::kVp9CodecName) {
//outCodecId = codec.id;
}
if (codec.name == cricket::kH264CodecName) {
if (useVP9 && codec.name == cricket::kVp9CodecName) {
if (!found) {
outCodecId = codec.id;
found = true;
}
}
if (!useVP9 && codec.name == cricket::kH264CodecName) {
if (!found) {
outCodecId = codec.id;
found = true;
}
}
// Increment payload type.
@ -128,14 +132,15 @@ static std::vector<cricket::VideoCodec> AssignPayloadTypesAndDefaultCodecs(std::
return output_codecs;
}
MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing)
: ssrc_send(outgoing ? caller_ssrc : called_ssrc)
, ssrc_recv(outgoing ? called_ssrc : caller_ssrc)
, ssrc_send_video(outgoing ? caller_ssrc_video : called_ssrc_video)
, ssrc_recv_video(outgoing ? called_ssrc_video : caller_ssrc_video)
, event_log(std::make_unique<webrtc::RtcEventLogNull>())
, task_queue_factory(webrtc::CreateDefaultTaskQueueFactory())
, data_sender(*this)
, audio_sender(*this, false)
, video_sender(*this, true)
, signaling_thread(rtc::Thread::Create())
, worker_thread(rtc::Thread::Create()) {
signaling_thread->Start();
@ -172,16 +177,14 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
call.get(), cricket::MediaConfig(), cricket::AudioOptions(), webrtc::CryptoOptions::NoGcm()));
video_channel.reset(media_engine->video().CreateMediaChannel(call.get(), cricket::MediaConfig(), cricket::VideoOptions(), webrtc::CryptoOptions::NoGcm(), video_bitrate_allocator_factory.get()));
if (false && send) {
if (true) {
voice_channel->AddSendStream(cricket::StreamParams::CreateLegacy(ssrc_send));
SetNetworkParams({6, 32, 6, 120, false, false, false});
SetMute(false);
voice_channel->SetInterface(&data_sender, webrtc::MediaTransportConfig());
voice_channel->OnReadyToSend(true);
voice_channel->SetSend(true);
voice_channel->SetInterface(&audio_sender, webrtc::MediaTransportConfig());
}
if (send) {
if (true) {
video_channel->AddSendStream(cricket::StreamParams::CreateLegacy(ssrc_send_video));
for (auto codec : videoCodecs) {
@ -189,10 +192,11 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
rtc::scoped_refptr<webrtc::ObjCVideoTrackSource> objCVideoTrackSource(new rtc::RefCountedObject<webrtc::ObjCVideoTrackSource>());
_nativeVideoSource = webrtc::VideoTrackSourceProxy::Create(signaling_thread.get(), worker_thread.get(), objCVideoTrackSource);
codec.SetParam(cricket::kCodecParamMinBitrate, 32);
codec.SetParam(cricket::kCodecParamStartBitrate, 100);
codec.SetParam(cricket::kCodecParamMaxBitrate, 1500);
codec.SetParam(cricket::kCodecParamMinBitrate, 64);
codec.SetParam(cricket::kCodecParamStartBitrate, 256);
codec.SetParam(cricket::kCodecParamMaxBitrate, 2500);
dispatch_async(dispatch_get_main_queue(), ^{
#if TARGET_IPHONE_SIMULATOR
#else
_videoCapturer = [[VideoCameraCapturer alloc] initWithSource:_nativeVideoSource];
@ -245,10 +249,11 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
[_videoCapturer startCaptureWithDevice:frontCamera format:bestFormat fps:27];
#endif
});
cricket::VideoSendParameters send_parameters;
send_parameters.codecs.push_back(codec);
send_parameters.extensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, extension_sequence);
send_parameters.extensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, extension_sequence_video);
//send_parameters.options.echo_cancellation = params.echo_cancellation;
//send_parameters.options.noise_suppression = params.noise_suppression;
//send_parameters.options.auto_gain_control = params.auto_gain_control;
@ -261,15 +266,13 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
video_channel->SetVideoSend(ssrc_send_video, NULL, _nativeVideoSource.get());
video_channel->SetInterface(&data_sender, webrtc::MediaTransportConfig());
video_channel->OnReadyToSend(true);
video_channel->SetSend(true);
video_channel->SetInterface(&video_sender, webrtc::MediaTransportConfig());
break;
}
}
}
if (false && recv) {
if (true) {
cricket::AudioRecvParameters recv_parameters;
recv_parameters.codecs.emplace_back(sdp_payload, sdp_name, clockrate, sdp_bitrate, sdp_channels);
recv_parameters.extensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, extension_sequence);
@ -279,7 +282,7 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
voice_channel->SetRecvParameters(recv_parameters);
voice_channel->SetPlayout(true);
}
if (recv) {
if (true) {
for (auto codec : videoCodecs) {
if (codec.id == outCodecId) {
codec.SetParam(cricket::kCodecParamMinBitrate, 32);
@ -288,7 +291,7 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
cricket::VideoRecvParameters recv_parameters;
recv_parameters.codecs.emplace_back(codec);
recv_parameters.extensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, extension_sequence);
recv_parameters.extensions.emplace_back(webrtc::RtpExtension::kTransportSequenceNumberUri, extension_sequence_video);
//recv_parameters.rtcp.reduced_size = true;
recv_parameters.rtcp.remote_estimate = true;
video_channel->AddRecvStream(cricket::StreamParams::CreateLegacy(ssrc_recv_video));
@ -300,14 +303,35 @@ MediaEngineWebrtc::MediaEngineWebrtc(bool outgoing, bool send, bool recv)
}
}
MediaEngineWebrtc::~MediaEngineWebrtc() = default;
MediaEngineWebrtc::~MediaEngineWebrtc() {
[_videoCapturer stopCapture];
video_channel->SetSink(ssrc_recv_video, nullptr);
video_channel->RemoveSendStream(ssrc_send_video);
video_channel->RemoveRecvStream(ssrc_recv_video);
voice_channel->SetPlayout(false);
voice_channel->RemoveSendStream(ssrc_send);
voice_channel->RemoveRecvStream(ssrc_recv);
};
void MediaEngineWebrtc::Receive(rtc::CopyOnWriteBuffer packet) {
if (voice_channel) {
//voice_channel->OnPacketReceived(packet, -1);
if (packet.size() < 1) {
return;
}
uint8_t header = ((uint8_t *)packet.data())[0];
rtc::CopyOnWriteBuffer unwrappedPacket = packet.Slice(1, packet.size() - 1);
if (header == 0xba) {
if (voice_channel) {
voice_channel->OnPacketReceived(unwrappedPacket, -1);
}
} else if (header == 0xbf) {
if (video_channel) {
video_channel->OnPacketReceived(packet, -1);
video_channel->OnPacketReceived(unwrappedPacket, -1);
}
} else {
printf("----- Unknown packet header");
}
}
@ -336,29 +360,55 @@ void MediaEngineWebrtc::SetNetworkParams(const MediaEngineWebrtc::NetworkParams&
// send_parameters.max_bandwidth_bps = 16000;
send_parameters.rtcp.reduced_size = true;
send_parameters.rtcp.remote_estimate = true;
//voice_channel->SetSendParameters(send_parameters);
voice_channel->SetSendParameters(send_parameters);
}
void MediaEngineWebrtc::SetMute(bool mute) {
//voice_channel->SetAudioSend(ssrc_send, !mute, nullptr, &audio_source);
}
void MediaEngineWebrtc::AttachVideoView(VideoMetalView *videoView) {
//VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 240.0f)];
//remoteRenderer.videoContentMode = UIViewContentModeScaleAspectFill;
void MediaEngineWebrtc::SetCanSendPackets(bool canSendPackets) {
if (canSendPackets) {
call->SignalChannelNetworkState(webrtc::MediaType::AUDIO, webrtc::kNetworkUp);
call->SignalChannelNetworkState(webrtc::MediaType::VIDEO, webrtc::kNetworkUp);
} else {
call->SignalChannelNetworkState(webrtc::MediaType::AUDIO, webrtc::kNetworkDown);
call->SignalChannelNetworkState(webrtc::MediaType::VIDEO, webrtc::kNetworkDown);
}
if (voice_channel) {
voice_channel->OnReadyToSend(canSendPackets);
voice_channel->SetSend(canSendPackets);
voice_channel->SetAudioSend(ssrc_send, true, nullptr, &audio_source);
}
if (video_channel) {
video_channel->OnReadyToSend(canSendPackets);
video_channel->SetSend(canSendPackets);
}
}
video_channel->SetSink(ssrc_recv_video, [videoView getSink]);
void MediaEngineWebrtc::AttachVideoView(rtc::VideoSinkInterface<webrtc::VideoFrame> *sink) {
video_channel->SetSink(ssrc_recv_video, sink);
}
bool MediaEngineWebrtc::Sender::SendPacket(rtc::CopyOnWriteBuffer *packet, const rtc::PacketOptions& options) {
engine.Send(*packet);
rtc::CopyOnWriteBuffer wrappedPacket;
uint8_t header = isVideo ? 0xbf : 0xba;
wrappedPacket.AppendData(&header, 1);
wrappedPacket.AppendData(*packet);
engine.Send(wrappedPacket);
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(), options.info_signaled_after_sent);
engine.OnSentPacket(sent_packet);
return true;
}
bool MediaEngineWebrtc::Sender::SendRtcp(rtc::CopyOnWriteBuffer *packet, const rtc::PacketOptions& options) {
engine.Send(*packet);
rtc::CopyOnWriteBuffer wrappedPacket;
uint8_t header = isVideo ? 0xbf : 0xba;
wrappedPacket.AppendData(&header, 1);
wrappedPacket.AppendData(*packet);
engine.Send(wrappedPacket);
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(), options.info_signaled_after_sent);
engine.OnSentPacket(sent_packet);
return true;
@ -368,4 +418,8 @@ int MediaEngineWebrtc::Sender::SetOption(cricket::MediaChannel::NetworkInterface
return -1; // in general, the result is not important yet
}
MediaEngineWebrtc::Sender::Sender(MediaEngineWebrtc& engine) : engine(engine) {}
MediaEngineWebrtc::Sender::Sender(MediaEngineWebrtc &engine, bool isVideo) :
engine(engine),
isVideo(isVideo) {
}

View File

@ -1,134 +0,0 @@
#ifndef DEMO_MESSAGE_H
#define DEMO_MESSAGE_H
#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/socket_address.h"
namespace message {
enum Type {
tUnknown,
tReady,
tConnected,
tDisconnected,
tRelayPing,
tRelayPong,
tGetPeerInfo,
tPeerInfo,
tSelfIPv6,
tSelfLocalIP,
tInit,
tInitAck,
tPing,
tPong,
tBufferOverflow,
tPacketIncorrect,
tWrongProtocol,
tRtpStream,
};
enum NetworkType {
nGprs,
nEdge,
n3gOrAbove,
nHighSpeed,
nUnknown,
};
struct Base {
virtual ~Base() = default;
explicit Base(Type ID) : ID(ID) {}
const Type ID;
};
struct Unknown : Base {
Unknown() : Base(Type::tUnknown) {}
};
struct Ready : Base {
Ready() : Base(Type::tReady) {}
};
struct Connected : Base {
Connected() : Base(Type::tConnected) {}
};
struct Disconnected : Base {
Disconnected() : Base(Type::tDisconnected) {}
};
struct RelayPing : Base {
RelayPing() : Base(Type::tRelayPing) {}
};
struct RelayPong : Base {
RelayPong() : Base(Type::tRelayPong) {}
uint32_t date{}; // int32_t in src
uint64_t query_id{}; //int64_t in src
rtc::SocketAddress my_addr;
};
struct GetPeerInfo : Base {
GetPeerInfo() : Base(Type::tGetPeerInfo) {}
};
struct PeerInfo : Base {
PeerInfo() : Base(Type::tPeerInfo) {}
rtc::SocketAddress my_addr;
rtc::SocketAddress peer_addr;
};
struct SelfIPv6 : Base {
SelfIPv6() : Base(Type::tSelfIPv6) {}
rtc::SocketAddress my_addr;
};
struct SelfLocalIP : Base {
SelfLocalIP() : Base(Type::tSelfLocalIP) {}
};
struct Init : Base {
Init() : Base(Type::tInit) {}
uint32_t ver{};
uint32_t minVer{};
uint32_t flags{};
};
struct InitAck : Base {
InitAck() : Base(Type::tInitAck) {}
uint32_t ver{};
uint32_t minVer{};
};
struct Ping : Base {
Ping() : Base(Type::tPing) {}
uint32_t id{};
};
struct Pong : Base {
Pong() : Base(Type::tPong) {}
uint32_t id{};
};
struct BufferOverflow : Base {
BufferOverflow() : Base(Type::tBufferOverflow) {}
};
struct PacketIncorrect : Base {
PacketIncorrect() : Base(Type::tPacketIncorrect) {}
};
struct WrongProtocol : Base {
WrongProtocol() : Base(Type::tWrongProtocol) {}
};
struct RtpStream : Base {
RtpStream() : Base(Type::tRtpStream) {}
bool data_saving{false};
NetworkType network_type{NetworkType::nUnknown};
rtc::CopyOnWriteBuffer data;
};
}
#endif //DEMO_MESSAGE_H

View File

@ -1,6 +0,0 @@
#ifndef PLATFORM_CODECS_H
#define PLATFORM_CODECS_H
#endif //PLATFORM_CODECS_H

View File

@ -1,2 +0,0 @@
#include "PlatformCodecs.h"

View File

@ -1,159 +0,0 @@
#include "Protocol10.h"
#include "rtc_base/byte_buffer.h"
#include <functional>
#include <map>
const std::map<uint8_t, Protocol10::Deserializer> Protocol10::decoders = {
{Protocol10::PacketType::tInit, Protocol10::InitDecode}, // back compatibility
{Protocol10::PacketType::tInitAck, Protocol10::InitAckDecode}, // back compatibility
{Protocol10::PacketType::tRtpStream, Protocol10::RtpStreamDecode},
{Protocol10::PacketType::tPing, Protocol10::PingDecode},
{Protocol10::PacketType::tPong, Protocol10::PongDecode},
};
const std::map<uint8_t, Protocol10::Serializer> Protocol10::encoders = {
{message::tInit, Protocol10::InitEncode},
{message::tInitAck, Protocol10::InitAckEncode},
{message::tRtpStream, Protocol10::RtpStreamEncode},
{message::tPing, Protocol10::PingEncode},
{message::tPong, Protocol10::PongEncode},
};
Protocol10::Protocol10() : ProtocolBase(10) {}
std::unique_ptr<message::Base> Protocol10::ReadProtocolPacket(const uint8_t *buffer, size_t size) {
uint8_t type = buffer[0];
auto deserializer = decoders.find(type);
if (deserializer == decoders.end())
return nullptr;
return deserializer->second(buffer + 1, size - 1);
}
rtc::Buffer Protocol10::WriteProtocolPacket(const message::Base *msg) {
auto serializer = encoders.find(msg->ID);
if (serializer == encoders.end())
return rtc::Buffer();
return serializer->second(msg);
}
rtc::Buffer Protocol10::InitEncode(const message::Base *msg_base) {
const auto *msg = dynamic_cast<const message::Init *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt8(PacketType::tInit);
out.Resize(14);
out.WriteUInt32(rtc::NetworkToHost32(msg->ver));
out.WriteUInt32(rtc::NetworkToHost32(msg->minVer));
out.WriteUInt32(rtc::NetworkToHost32(msg->flags));
return rtc::Buffer(out.Data(), out.Length());
}
std::unique_ptr<message::Base> Protocol10::InitDecode(const uint8_t *buffer, size_t size) {
rtc::ByteBufferReader in(reinterpret_cast<const char *>(buffer), size);
uint32_t ackId = 0, pseq = 0, acks = 0;
unsigned char pflags = 0;
in.ReadUInt32(&ackId);
in.ReadUInt32(&pseq);
in.ReadUInt32(&acks);
in.ReadUInt8(&pflags);
auto msg = std::make_unique<message::Init>();
in.ReadUInt32(&msg->ver);
in.ReadUInt32(&msg->minVer);
in.ReadUInt32(&msg->flags);
msg->ver = rtc::HostToNetwork32(msg->ver);
msg->minVer = rtc::HostToNetwork32(msg->minVer);
msg->flags = rtc::HostToNetwork32(msg->flags);
if (ProtocolBase::IsSupported(msg->ver))
return msg;
// TODO: support matching of lower supported versions
return std::make_unique<message::WrongProtocol>();
}
rtc::Buffer Protocol10::InitAckEncode(const message::Base *msg_base) {
const auto *msg = dynamic_cast<const message::InitAck *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt8(PacketType::tInitAck);
out.Resize(14);
out.WriteUInt32(rtc::NetworkToHost32(msg->ver));
out.WriteUInt32(rtc::NetworkToHost32(msg->minVer));
return rtc::Buffer(out.Data(), out.Length());
}
std::unique_ptr<message::Base> Protocol10::InitAckDecode(const uint8_t *buffer, size_t size) {
rtc::ByteBufferReader in(reinterpret_cast<const char *>(buffer), size);
uint32_t ackId = 0, pseq = 0, acks = 0;
unsigned char pflags = 0;
in.ReadUInt32(&ackId);
in.ReadUInt32(&pseq);
in.ReadUInt32(&acks);
in.ReadUInt8(&pflags);
auto msg = std::make_unique<message::InitAck>();
in.ReadUInt32(&msg->ver);
in.ReadUInt32(&msg->minVer);
msg->ver = rtc::HostToNetwork32(msg->ver);
msg->minVer = rtc::HostToNetwork32(msg->minVer);
if (ProtocolBase::IsSupported(msg->ver))
return msg;
// TODO: support matching of lower supported versions
return std::make_unique<message::WrongProtocol>();
}
rtc::Buffer Protocol10::RtpStreamEncode(const message::Base *msg_base) {
const auto *msg = dynamic_cast<const message::RtpStream *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt8(PacketType::tRtpStream);
uint8_t meta = (msg->network_type & 0b111) | (msg->data_saving << 3);
out.WriteUInt8(meta);
out.WriteBytes(reinterpret_cast<const char *>(msg->data.data()), msg->data.size());
return rtc::Buffer(out.Data(), out.Length());
}
std::unique_ptr<message::Base> Protocol10::RtpStreamDecode(const uint8_t *buffer, size_t size) {
auto msg = std::make_unique<message::RtpStream>();
uint8_t meta = buffer[0];
msg->network_type = (message::NetworkType) (meta & 0b111);
msg->data_saving = (meta >> 3) & 0b1;
msg->data = rtc::CopyOnWriteBuffer(buffer + 1, size - 1);
return msg;
}
rtc::Buffer Protocol10::PingEncode(const message::Base *msg_base) {
const auto *msg = dynamic_cast<const message::Ping *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt8(PacketType::tPing);
out.WriteUInt32(msg->id);
return rtc::Buffer(out.Data(), out.Length());
}
std::unique_ptr<message::Base> Protocol10::PingDecode(const uint8_t *buffer, size_t size) {
rtc::ByteBufferReader in(reinterpret_cast<const char *>(buffer), size);
auto msg = std::make_unique<message::Ping>();
in.ReadUInt32(&msg->id);
return msg;
}
rtc::Buffer Protocol10::PongEncode(const message::Base *msg_base) {
const auto *msg = dynamic_cast<const message::Pong *>(msg_base);
if (!msg)
return rtc::Buffer();
rtc::ByteBufferWriter out;
out.WriteUInt8(PacketType::tPong);
out.WriteUInt32(msg->id);
return rtc::Buffer(out.Data(), out.Length());
}
std::unique_ptr<message::Base> Protocol10::PongDecode(const uint8_t *buffer, size_t size) {
rtc::ByteBufferReader in(reinterpret_cast<const char *>(buffer), size);
auto msg = std::make_unique<message::Pong>();
in.ReadUInt32(&msg->id);
return msg;
}

View File

@ -1,44 +0,0 @@
#ifndef DEMO_PROTOCOL10_H
#define DEMO_PROTOCOL10_H
#include "Message.h"
#include "ProtocolBase.h"
#include <memory>
class Protocol10 : public ProtocolBase {
public:
enum PacketType {
tInit = 1,
tInitAck,
tRtpStream,
tPing,
tPong,
};
Protocol10();
std::unique_ptr<message::Base> ReadProtocolPacket(const uint8_t *buffer, size_t size) override;
rtc::Buffer WriteProtocolPacket(const message::Base *msg) override;
private:
typedef std::function<std::unique_ptr<message::Base>(const uint8_t *, size_t)> Deserializer;
typedef std::function<rtc::Buffer(const message::Base *)> Serializer;
static const std::map<uint8_t, Deserializer> decoders;
static const std::map<uint8_t, Serializer> encoders;
static rtc::Buffer InitEncode(const message::Base *msg_base);
static std::unique_ptr<message::Base> InitDecode(const uint8_t *buffer, size_t size);
static rtc::Buffer InitAckEncode(const message::Base *msg_base);
static std::unique_ptr<message::Base> InitAckDecode(const uint8_t *buffer, size_t size);
static rtc::Buffer RtpStreamEncode(const message::Base *msg_base);
static std::unique_ptr<message::Base> RtpStreamDecode(const uint8_t *buffer, size_t size);
static rtc::Buffer PingEncode(const message::Base *msg_base);
static std::unique_ptr<message::Base> PingDecode(const uint8_t *buffer, size_t size);
static rtc::Buffer PongEncode(const message::Base *msg_base);
static std::unique_ptr<message::Base> PongDecode(const uint8_t *buffer, size_t size);
};
#endif //DEMO_PROTOCOL10_H

View File

@ -1,23 +0,0 @@
#include "ProtocolBase.h"
#include "Protocol10.h"
const std::map<uint8_t, ProtocolBase::Constructor> ProtocolBase::constructors = {
{10, std::make_unique<Protocol10>},
};
const uint32_t ProtocolBase::actual_version = 10;
const uint32_t ProtocolBase::minimal_version = 10;
std::unique_ptr<ProtocolBase> ProtocolBase::CreateProtocol(uint32_t version) {
auto protocol = constructors.find(version);
if (protocol == constructors.end())
return nullptr;
return protocol->second();
}
bool ProtocolBase::IsSupported(uint32_t version) {
return constructors.find(version) != constructors.end();
}
ProtocolBase::ProtocolBase(uint32_t version) : version(version) {}

View File

@ -1,33 +0,0 @@
#ifndef DEMO_PROTOCOLBASE_H
#define DEMO_PROTOCOLBASE_H
#include "Message.h"
#include <map>
#include <memory>
#include <functional>
class ProtocolBase {
public:
static const uint32_t actual_version;
static const uint32_t minimal_version;
static std::unique_ptr<ProtocolBase> CreateProtocol(uint32_t version);
static bool IsSupported(uint32_t version);
virtual ~ProtocolBase() = default;
virtual std::unique_ptr<message::Base> ReadProtocolPacket(const uint8_t *buffer, size_t size) = 0;
virtual rtc::Buffer WriteProtocolPacket(const message::Base *msg) = 0;
const uint32_t version;
protected:
explicit ProtocolBase(uint32_t version);
private:
typedef std::function<std::unique_ptr<ProtocolBase>()> Constructor;
static const std::map<uint8_t, Constructor> constructors;
};
#endif //DEMO_PROTOCOLBASE_H

View File

@ -66,19 +66,6 @@ struct TgVoipPersistentState {
std::vector<uint8_t> value;
};
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
struct TgVoipCrypto {
void (*rand_bytes)(uint8_t* buffer, size_t length);
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
};
#endif
struct TgVoipConfig {
double initializationTimeout;
double receiveTimeout;
@ -145,14 +132,6 @@ public:
std::unique_ptr<TgVoipProxy> const &proxy,
TgVoipNetworkType initialNetworkType,
TgVoipEncryptionKey const &encryptionKey
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
,
TgVoipCrypto const &crypto
#endif
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
,
TgVoipAudioDataCallbacks const &audioDataCallbacks
#endif
);
virtual ~TgVoip();
@ -172,6 +151,9 @@ public:
virtual void setOnStateUpdated(std::function<void(TgVoipState)> onStateUpdated) = 0;
virtual void setOnSignalBarsUpdated(std::function<void(int)> onSignalBarsUpdated) = 0;
virtual void setOnCandidatesGathered(std::function<void(const std::vector<std::string> &)> onCandidatesGathered) = 0;
virtual void addRemoteCandidates(const std::vector<std::string> &candidates) = 0;
virtual TgVoipFinalState stop() = 0;
};

View File

@ -3,14 +3,12 @@
#include "TgVoip.h"
#include "Controller.h"
#include "Layer92.h"
#include "Message.h"
#include <stdarg.h>
#include <iostream>
#ifndef TGVOIP_USE_CUSTOM_CRYPTO
extern "C" {
/*extern "C" {
#include <openssl/sha.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
@ -18,52 +16,48 @@ extern "C" {
#include <openssl/crypto.h>
}
void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
static void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_encrypt_key(key, 32*8, &akey);
AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
}
void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
static void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_decrypt_key(key, 32*8, &akey);
AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
}
void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
static void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
RAND_bytes(buffer, (int)len);
}
void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
static void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
SHA1(msg, len, output);
}
void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
static void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
SHA256(msg, len, output);
}
void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
static void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
AES_KEY akey;
AES_set_encrypt_key(key, 32*8, &akey);
CRYPTO_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num, (block128_f) AES_encrypt);
}
void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
static void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_encrypt_key(key, 256, &akey);
AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
}
void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
static void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_decrypt_key(key, 256, &akey);
AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
}
const char * openssl_version() {
return SSLeay_version(SSLEAY_VERSION);
}
CryptoFunctions Layer92::crypto={
tgvoip_openssl_rand_bytes,
tgvoip_openssl_sha1,
@ -73,7 +67,7 @@ CryptoFunctions Layer92::crypto={
tgvoip_openssl_aes_ctr_encrypt,
tgvoip_openssl_aes_cbc_encrypt,
tgvoip_openssl_aes_cbc_decrypt
};
};*/
#endif
@ -82,6 +76,9 @@ namespace TGVOIP_NAMESPACE {
#endif
class TgVoipImpl : public TgVoip, public sigslot::has_slots<> {
private:
public:
TgVoipImpl(
std::vector<TgVoipEndpoint> const &endpoints,
@ -90,38 +87,17 @@ public:
TgVoipConfig const &config,
TgVoipEncryptionKey const &encryptionKey,
TgVoipNetworkType initialNetworkType
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
,
TgVoipCrypto const &crypto
#endif
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
,
TgVoipAudioDataCallbacks const &audioDataCallbacks
#endif
) {
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
tgvoip::VoIPController::crypto.sha1 = crypto.sha1;
tgvoip::VoIPController::crypto.sha256 = crypto.sha256;
tgvoip::VoIPController::crypto.rand_bytes = crypto.rand_bytes;
tgvoip::VoIPController::crypto.aes_ige_encrypt = crypto.aes_ige_encrypt;
tgvoip::VoIPController::crypto.aes_ige_decrypt = crypto.aes_ige_decrypt;
tgvoip::VoIPController::crypto.aes_ctr_encrypt = crypto.aes_ctr_encrypt;
#endif
// std::cerr << "OpenSSL version: " << openssl_version() << std::endl; // to verify because of WebRTC BoringSSL
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
rtc::LogMessage::LogToDebug(rtc::LS_INFO);
rtc::LogMessage::SetLogToStderr(true);
});
EncryptionKey encryptionKeyValue;
memcpy(encryptionKeyValue, encryptionKey.value.data(), 256);
controller_ = new Controller(encryptionKey.isOutgoing, encryptionKeyValue, 5, 3);
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
audioCallbacks = audioDataCallbacks;
controller_->SignalRecord.connect(this, &TgVoipImpl::record);
controller_->SignalPlay.connect(this, &TgVoipImpl::play);
#ifdef TGVOIP_PREPROCESSED_OUTPUT
controller_->SignalPreprocessed.connect(this, &TgVoipImpl::preprocessed);
#endif
#endif
/*EncryptionKey encryptionKeyValue;
memcpy(encryptionKeyValue, encryptionKey.value.data(), 256);*/
controller_ = new Controller(encryptionKey.isOutgoing, 5, 3);
if (proxy != nullptr) {
controller_->SetProxy(rtc::ProxyType::PROXY_SOCKS5, rtc::SocketAddress(proxy->host, proxy->port),
@ -129,6 +105,7 @@ public:
}
controller_->SignalNewState.connect(this, &TgVoipImpl::controllerStateCallback);
controller_->SignalCandidatesGathered.connect(this, &TgVoipImpl::candidatesGathered);
controller_->Start();
for (const auto &endpoint : endpoints) {
@ -149,7 +126,7 @@ public:
type = Controller::EndpointType::UDP;
break;
}
controller_->AddEndpoint(addr, endpoint.peerTag, type);
//controller_->AddEndpoint(addr, endpoint.peerTag, type);
}
/*rtc::SocketAddress addr("192.168.8.118", 7325);
unsigned char peerTag[16];
@ -184,8 +161,16 @@ public:
onSignalBarsUpdated_ = onSignalBarsUpdated;
}
void setOnCandidatesGathered(std::function<void(const std::vector<std::string> &)> onCandidatesGathered) override {
onCandidatesGathered_ = onCandidatesGathered;
}
void addRemoteCandidates(const std::vector<std::string> &candidates) override {
controller_->AddRemoteCandidates(candidates);
}
void setNetworkType(TgVoipNetworkType networkType) override {
message::NetworkType mappedType;
/*message::NetworkType mappedType;
switch (networkType) {
case TgVoipNetworkType::Unknown:
@ -229,7 +214,7 @@ public:
break;
}
controller_->SetNetworkType(mappedType);
controller_->SetNetworkType(mappedType);*/
}
void setMuteMicrophone(bool muteMicrophone) override {
@ -237,7 +222,7 @@ public:
}
void AttachVideoView(VideoMetalView *videoView) override {
controller_->AttachVideoView(videoView);
controller_->AttachVideoView([videoView getSink]);
}
void setAudioOutputGainControlEnabled(bool enabled) override {
@ -304,6 +289,10 @@ public:
}
}
void candidatesGathered(const std::vector<std::string> &candidates) {
onCandidatesGathered_(candidates);
}
private:
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
TgVoipAudioDataCallbacks audioCallbacks;
@ -334,6 +323,7 @@ private:
Controller *controller_;
std::function<void(TgVoipState)> onStateUpdated_;
std::function<void(int)> onSignalBarsUpdated_;
std::function<void(const std::vector<std::string> &)> onCandidatesGathered_;
std::mutex m_onStateUpdated, m_onSignalBarsUpdated;
};
@ -379,14 +369,6 @@ TgVoip *TgVoip::makeInstance(
std::unique_ptr<TgVoipProxy> const &proxy,
TgVoipNetworkType initialNetworkType,
TgVoipEncryptionKey const &encryptionKey
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
,
TgVoipCrypto const &crypto
#endif
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
,
TgVoipAudioDataCallbacks const &audioDataCallbacks
#endif
) {
return new TgVoipImpl(
endpoints,
@ -395,14 +377,6 @@ TgVoip *TgVoip::makeInstance(
config,
encryptionKey,
initialNetworkType
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
,
crypto
#endif
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
,
audioDataCallbacks
#endif
);
}

View File

@ -65,7 +65,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallStateWebrtc);
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData;
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
- (bool)needRate;
@ -77,6 +77,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
- (void)setIsMuted:(bool)isMuted;
- (void)setNetworkType:(OngoingCallNetworkTypeWebrtc)networkType;
- (void)getRemoteCameraView:(void (^_Nonnull)(UIView * _Nullable))completion;
- (void)addSignalingData:(NSData * _Nonnull)data;
@end

View File

@ -35,6 +35,8 @@ using namespace TGVOIP_NAMESPACE;
OngoingCallStateWebrtc _state;
int32_t _signalBars;
NSData *_lastDerivedState;
void (^_sendSignalingData)(NSData *);
}
- (void)controllerStateChanged:(TgVoipState)state;
@ -112,7 +114,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
return @"2.7.7";
}
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData; {
self = [super init];
if (self != nil) {
_queue = queue;
@ -123,6 +125,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
_callConnectTimeout = 30.0;
_callPacketTimeout = 10.0;
_networkType = networkType;
_sendSignalingData = [sendSignalingData copy];
std::vector<uint8_t> derivedStateValue;
derivedStateValue.resize(derivedState.length);
@ -211,6 +214,16 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
[strongSelf signalBarsChanged:signalBars];
}
});
_tgVoip->setOnCandidatesGathered([weakSelf](const std::vector<std::string> &candidates) {
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
if (strongSelf) {
NSMutableArray *mappedCandidates = [[NSMutableArray alloc] init];
for (auto &candidate : candidates) {
[mappedCandidates addObject:[[NSString alloc] initWithCString:candidate.c_str() encoding:NSUTF8StringEncoding]];
}
[strongSelf candidatesGathered:mappedCandidates];
}
});
}
return self;
}
@ -307,6 +320,30 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
}
}
- (void)candidatesGathered:(NSArray<NSString *> *)candidates {
if (_sendSignalingData) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:@{
@"type": @"candidates",
@"data": candidates
}];
_sendSignalingData(data);
}
}
- (void)addSignalingData:(NSData *)data {
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSString *type = dict[@"type"];
if ([type isEqualToString:@"candidates"]) {
if (_tgVoip) {
std::vector<std::string> candidates;
for (NSString *string in dict[@"data"]) {
candidates.push_back([string UTF8String]);
}
_tgVoip->addRemoteCandidates(candidates);
}
}
}
- (void)setIsMuted:(bool)isMuted {
if (_tgVoip) {
_tgVoip->setMuteMicrophone(isMuted);
@ -324,7 +361,8 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
- (void)getRemoteCameraView:(void (^_Nonnull)(UIView * _Nullable))completion {
if (_tgVoip) {
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 240.0f)];
dispatch_async(dispatch_get_main_queue(), ^{
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectZero];
remoteRenderer.videoContentMode = UIViewContentModeScaleAspectFill;
_tgVoip->AttachVideoView(remoteRenderer);
@ -332,6 +370,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
completion(remoteRenderer);
});
});
}
}

View File

@ -23,7 +23,7 @@ if [ "$ARCH" == "x64" ]; then
OUT_DIR="ios_sim"
fi
gn gen out/$OUT_DIR --args="use_xcode_clang=true "" target_cpu=\"$ARCH\""' target_os="ios" is_debug=true is_component_build=false rtc_include_tests=false use_rtti=true rtc_use_x11=false use_custom_libcxx=false use_custom_libcxx_for_host=false rtc_build_ssl=false rtc_build_examples=false rtc_build_tools=false ios_deployment_target="9.0" ios_enable_code_signing=false is_unsafe_developer_build=false rtc_enable_protobuf=false rtc_include_builtin_video_codecs=true rtc_build_libvpx=true rtc_libvpx_build_vp9=true rtc_use_gtk=false rtc_use_metal_rendering=true rtc_ssl_root="//openssl"'
gn gen out/$OUT_DIR --args="use_xcode_clang=true "" target_cpu=\"$ARCH\""' target_os="ios" is_debug=false is_component_build=false rtc_include_tests=false use_rtti=true rtc_use_x11=false use_custom_libcxx=false use_custom_libcxx_for_host=false rtc_build_ssl=false rtc_build_examples=false rtc_build_tools=false ios_deployment_target="9.0" ios_enable_code_signing=false is_unsafe_developer_build=false rtc_enable_protobuf=false rtc_include_builtin_video_codecs=true rtc_build_libvpx=true rtc_libvpx_build_vp9=true rtc_use_gtk=false rtc_use_metal_rendering=true rtc_ssl_root="//openssl"'
ninja -C out/$OUT_DIR framework_objc_static
popd