1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-11-26 20:24:38 +01:00
libtgvoip/VoIPController.h
Grishka 5caaaafa42 Updated WebRTC APM
I'm now using the entire audio processing module from WebRTC as opposed to individual DSP algorithms pulled from there before. Seems to work better this way.
2018-11-23 04:02:53 +03:00

794 lines
22 KiB
C++
Executable File

//
// libtgvoip is free and unencumbered public domain software.
// For more information, see http://unlicense.org or the UNLICENSE file
// you should have received with this source code distribution.
//
#ifndef __VOIPCONTROLLER_H
#define __VOIPCONTROLLER_H
#ifndef _WIN32
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#ifdef __APPLE__
#include <TargetConditionals.h>
#include "os/darwin/AudioUnitIO.h"
#endif
#include <stdint.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <map>
#include <memory>
#include "video/VideoSource.h"
#include "video/VideoRenderer.h"
#include <atomic>
#include "audio/AudioInput.h"
#include "BlockingQueue.h"
#include "audio/AudioOutput.h"
#include "audio/AudioIO.h"
#include "JitterBuffer.h"
#include "OpusDecoder.h"
#include "OpusEncoder.h"
#include "EchoCanceller.h"
#include "CongestionControl.h"
#include "NetworkSocket.h"
#include "Buffers.h"
#include "PacketReassembler.h"
#include "MessageThread.h"
#include "utils.h"
#define LIBTGVOIP_VERSION "2.4"
#ifdef _WIN32
#undef GetCurrentTime
#undef ERROR_TIMEOUT
#endif
#define TGVOIP_PEER_CAP_GROUP_CALLS 1
#define TGVOIP_PEER_CAP_VIDEO_CAPTURE 2
#define TGVOIP_PEER_CAP_VIDEO_DISPLAY 4
namespace tgvoip{
enum{
PROXY_NONE=0,
PROXY_SOCKS5,
//PROXY_HTTP
};
enum{
STATE_WAIT_INIT=1,
STATE_WAIT_INIT_ACK,
STATE_ESTABLISHED,
STATE_FAILED,
STATE_RECONNECTING
};
enum{
ERROR_UNKNOWN=0,
ERROR_INCOMPATIBLE,
ERROR_TIMEOUT,
ERROR_AUDIO_IO,
ERROR_PROXY
};
enum{
NET_TYPE_UNKNOWN=0,
NET_TYPE_GPRS,
NET_TYPE_EDGE,
NET_TYPE_3G,
NET_TYPE_HSPA,
NET_TYPE_LTE,
NET_TYPE_WIFI,
NET_TYPE_ETHERNET,
NET_TYPE_OTHER_HIGH_SPEED,
NET_TYPE_OTHER_LOW_SPEED,
NET_TYPE_DIALUP,
NET_TYPE_OTHER_MOBILE
};
enum{
DATA_SAVING_NEVER=0,
DATA_SAVING_MOBILE,
DATA_SAVING_ALWAYS
};
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);
};
struct CellularCarrierInfo{
std::string name;
std::string mcc;
std::string mnc;
std::string countryCode;
};
class Endpoint{
friend class VoIPController;
friend class VoIPGroupController;
public:
enum Type{
UDP_P2P_INET=1,
UDP_P2P_LAN,
UDP_RELAY,
TCP_RELAY
};
Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, Type type, unsigned char* peerTag);
Endpoint();
~Endpoint();
const NetworkAddress& GetAddress() const;
NetworkAddress& GetAddress();
bool IsIPv6Only() const;
int64_t id;
uint16_t port;
IPv4Address address;
IPv6Address v6address;
Type type;
unsigned char peerTag[16];
private:
double lastPingTime;
uint32_t lastPingSeq;
HistoricBuffer<double, 6> rtts;
double averageRTT;
NetworkSocket* socket;
int udpPongCount;
};
class AudioDevice{
public:
std::string id;
std::string displayName;
};
class AudioOutputDevice : public AudioDevice{
};
class AudioInputDevice : public AudioDevice{
};
struct EncodedVideoFrame{
unsigned char* data;
size_t size;
uint32_t flags;
EncodedVideoFrame(size_t size){
this->size=size;
data=(unsigned char*)malloc(size);
}
~EncodedVideoFrame(){
free(data);
}
};
class VoIPController{
friend class VoIPGroupController;
public:
TGVOIP_DISALLOW_COPY_AND_ASSIGN(VoIPController);
struct Config{
Config(double initTimeout=30.0, double recvTimeout=20.0, int dataSaving=DATA_SAVING_NEVER, bool enableAEC=false, bool enableNS=false, bool enableAGC=false, bool enableCallUpgrade=false){
this->initTimeout=initTimeout;
this->recvTimeout=recvTimeout;
this->dataSaving=dataSaving;
this->enableAEC=enableAEC;
this->enableNS=enableNS;
this->enableAGC=enableAGC;
this->enableCallUpgrade=enableCallUpgrade;
}
double initTimeout;
double recvTimeout;
int dataSaving;
#ifndef _WIN32
std::string logFilePath="";
std::string statsDumpFilePath="";
#else
std::wstring logFilePath=L"";
std::wstring statsDumpFilePath=L"";
#endif
bool enableAEC;
bool enableNS;
bool enableAGC;
bool enableCallUpgrade;
};
struct TrafficStats{
uint64_t bytesSentWifi;
uint64_t bytesRecvdWifi;
uint64_t bytesSentMobile;
uint64_t bytesRecvdMobile;
};
VoIPController();
virtual ~VoIPController();
/**
* Set the initial endpoints (relays)
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
* @param allowP2p Whether p2p connectivity is allowed
* @param connectionMaxLayer The max_layer field from the phoneCallProtocol object returned by Telegram server.
* DO NOT HARDCODE THIS VALUE, it's extremely important for backwards compatibility.
*/
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p, int32_t connectionMaxLayer);
/**
* Initialize and start all the internal threads
*/
void Start();
/**
* Stop any internal threads. Don't call any other methods after this.
*/
void Stop();
/**
* Initiate connection
*/
void Connect();
Endpoint& GetRemoteEndpoint();
/**
* Get the debug info string to be displayed in client UI
*/
virtual std::string GetDebugString();
/**
* Notify the library of network type change
* @param type The new network type
*/
virtual void SetNetworkType(int type);
/**
* Get the average round-trip time for network packets
* @return
*/
double GetAverageRTT();
static double GetCurrentTime();
/**
* Use this field to store any of your context data associated with this call
*/
void* implData;
/**
*
* @param mute
*/
virtual void SetMicMute(bool mute);
/**
*
* @param key
* @param isOutgoing
*/
void SetEncryptionKey(char* key, bool isOutgoing);
/**
*
* @param cfg
*/
void SetConfig(const Config& cfg);
void DebugCtl(int request, int param);
/**
*
* @param stats
*/
void GetStats(TrafficStats* stats);
/**
*
* @return
*/
int64_t GetPreferredRelayID();
/**
*
* @return
*/
int GetLastError();
/**
*
*/
static CryptoFunctions crypto;
/**
*
* @return
*/
static const char* GetVersion();
/**
*
* @return
*/
std::string GetDebugLog();
/**
*
* @param buffer
*/
void GetDebugLog(char* buffer);
size_t GetDebugLogLength();
/**
*
* @return
*/
static std::vector<AudioInputDevice> EnumerateAudioInputs();
/**
*
* @return
*/
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
/**
*
* @param id
*/
void SetCurrentAudioInput(std::string id);
/**
*
* @param id
*/
void SetCurrentAudioOutput(std::string id);
/**
*
* @return
*/
std::string GetCurrentAudioInputID();
/**
*
* @return
*/
std::string GetCurrentAudioOutputID();
/**
* Set the proxy server to route the data through. Call this before connecting.
* @param protocol PROXY_NONE or PROXY_SOCKS5
* @param address IP address or domain name of the server
* @param port Port of the server
* @param username Username; empty string for anonymous
* @param password Password; empty string if none
*/
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
/**
* Get the number of signal bars to display in the client UI.
* @return the number of signal bars, from 1 to 4
*/
int GetSignalBarsCount();
/**
* Enable or disable AGC (automatic gain control) on audio output. Should only be enabled on phones when the earpiece speaker is being used.
* The audio output will be louder with this on.
* AGC with speakerphone or other kinds of loud speakers has detrimental effects on some echo cancellation implementations.
* @param enabled I usually pick argument names to be self-explanatory
*/
void SetAudioOutputGainControlEnabled(bool enabled);
/**
* Get the additional capabilities of the peer client app
* @return corresponding TGVOIP_PEER_CAP_* flags OR'ed together
*/
uint32_t GetPeerCapabilities();
/**
* Send the peer the key for the group call to prepare this private call to an upgrade to a E2E group call.
* The peer must have the TGVOIP_PEER_CAP_GROUP_CALLS capability. After the peer acknowledges the key, Callbacks::groupCallKeySent will be called.
* @param key newly-generated group call key, must be exactly 265 bytes long
*/
void SendGroupCallKey(unsigned char* key);
/**
* In an incoming call, request the peer to generate a new encryption key, send it to you and upgrade this call to a E2E group call.
*/
void RequestCallUpgrade();
void SetEchoCancellationStrength(int strength);
int GetConnectionState();
bool NeedRate();
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
void SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output);
#endif
void SetVideoCodecSpecificData(const std::vector<Buffer>& data);
struct Callbacks{
void (*connectionStateChanged)(VoIPController*, int);
void (*signalBarCountChanged)(VoIPController*, int);
void (*groupCallKeySent)(VoIPController*);
void (*groupCallKeyReceived)(VoIPController*, const unsigned char*);
void (*upgradeToGroupCallRequested)(VoIPController*);
};
void SetCallbacks(Callbacks callbacks);
float GetOutputLevel(){
return 0.0f;
};
void SetVideoSource(video::VideoSource* source);
void SetVideoRenderer(video::VideoRenderer* renderer);
private:
struct Stream;
struct UnacknowledgedExtraData;
protected:
struct RecentOutgoingPacket{
uint32_t seq;
uint16_t id; // for group calls only
double sendTime;
double ackTime;
};
struct PendingOutgoingPacket{
#if defined(_MSC_VER) && _MSC_VER <= 1800 // VS2013 doesn't support auto-generating move constructors
//TGVOIP_DISALLOW_COPY_AND_ASSIGN(PendingOutgoingPacket);
PendingOutgoingPacket(uint32_t seq, unsigned char type, size_t len, Buffer&& data, int64_t endpoint){
this->seq=seq;
this->type=type;
this->len=len;
this->data=data;
this->endpoint=endpoint;
}
PendingOutgoingPacket(PendingOutgoingPacket&& other){
seq=other.seq;
type=other.type;
len=other.len;
data=std::move(other.data);
endpoint=other.endpoint;
}
#endif
uint32_t seq;
unsigned char type;
size_t len;
Buffer data;
int64_t endpoint;
};
struct QueuedPacket{
#if defined(_MSC_VER) && _MSC_VER <= 1800 // VS2013 doesn't support auto-generating move constructors
//TGVOIP_DISALLOW_COPY_AND_ASSIGN(QueuedPacket);
QueuedPacket(QueuedPacket&& other){
data=std::move(other.data);
type=other.type;
seqs=other.seqs;
firstSentTime=other.firstSentTime;
lastSentTime=other.lastSentTime;
retryInterval=other.retryInterval;
timeout=other.timeout;
}
QueuedPacket(){
}
#endif
Buffer data;
unsigned char type;
HistoricBuffer<uint32_t, 16> seqs;
double firstSentTime;
double lastSentTime;
double retryInterval;
double timeout;
};
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint& srcEndpoint);
virtual void ProcessExtraData(Buffer& data);
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
virtual void SendPacket(unsigned char* data, size_t len, Endpoint& ep, PendingOutgoingPacket& srcPacket);
virtual void SendInit();
virtual void SendUdpPing(Endpoint& endpoint);
virtual void SendRelayPings();
virtual void OnAudioOutputReady();
virtual void SendExtra(Buffer& data, unsigned char type);
void SendStreamFlags(Stream& stream);
void SendStreamCSD(Stream& stream);
void InitializeTimers();
void ResetEndpointPingStats();
void SendVideoFrame(const Buffer& frame, int32_t flags);
void ProcessIncomingVideoFrame(Buffer frame, uint32_t pts);
std::shared_ptr<Stream> GetStreamByType(int type, bool outgoing);
Endpoint* GetEndpointForPacket(const PendingOutgoingPacket& pkt);
bool SendOrEnqueuePacket(PendingOutgoingPacket pkt, bool enqueue=true);
static std::string NetworkTypeToString(int type);
private:
struct Stream{
int32_t userID;
unsigned char id;
unsigned char type;
uint32_t codec;
bool enabled;
bool extraECEnabled;
uint16_t frameDuration;
std::shared_ptr<JitterBuffer> jitterBuffer;
std::shared_ptr<OpusDecoder> decoder;
std::shared_ptr<PacketReassembler> packetReassembler;
std::shared_ptr<CallbackWrapper> callbackWrapper;
std::vector<Buffer> codecSpecificData;
bool csdIsValid=false;
unsigned int width=0;
unsigned int height=0;
uint16_t rotation=0;
};
struct UnacknowledgedExtraData{
#if defined(_MSC_VER) && _MSC_VER <= 1800 // VS2013 doesn't support auto-generating move constructors
UnacknowledgedExtraData(UnacknowledgedExtraData&& other){
type=other.type;
data=std::move(other.data);
firstContainingSeq=other.firstContainingSeq;
}
UnacknowledgedExtraData(unsigned char _type, Buffer&& _data, uint32_t _firstContainingSeq){
type=_type;
data=_data;
firstContainingSeq=_firstContainingSeq;
}
#endif
unsigned char type;
Buffer data;
uint32_t firstContainingSeq;
};
enum{
UDP_UNKNOWN=0,
UDP_PING_PENDING,
UDP_PING_SENT,
UDP_AVAILABLE,
UDP_NOT_AVAILABLE,
UDP_BAD
};
void RunRecvThread();
void RunSendThread();
void HandleAudioInput(unsigned char* data, size_t len, unsigned char* secondaryData, size_t secondaryLen);
void UpdateAudioBitrateLimit();
void SetState(int state);
void UpdateAudioOutputState();
void InitUDPProxy();
void UpdateDataSavingState();
void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
void KDF2(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
static void AudioInputCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength, void* param);
void SendPublicEndpointsRequest();
void SendPublicEndpointsRequest(const Endpoint& relay);
Endpoint& GetEndpointByType(int type);
void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout);
uint32_t GenerateOutSeq();
void LogDebugInfo();
void ActuallySendPacket(NetworkPacket& pkt, Endpoint& ep);
void InitializeAudio();
void StartAudio();
void ProcessAcknowledgedOutgoingExtra(UnacknowledgedExtraData& extra);
void AddIPv6Relays();
void AddTCPRelays();
void SendUdpPings();
void EvaluateUdpPingResults();
void UpdateRTT();
void UpdateCongestion();
void UpdateAudioBitrate();
void UpdateSignalBars();
void UpdateQueuedPackets();
void SendNopPacket();
void TickJitterBufferAngCongestionControl();
void ResetUdpAvailability();
int state;
std::map<int64_t, Endpoint> endpoints;
int64_t currentEndpoint=0;
int64_t preferredRelay=0;
int64_t peerPreferredRelay=0;
bool runReceiver;
uint32_t seq;
uint32_t lastRemoteSeq;
uint32_t lastRemoteAckSeq;
uint32_t lastSentSeq;
std::vector<RecentOutgoingPacket> recentOutgoingPackets;
double recvPacketTimes[32];
HistoricBuffer<uint32_t, 10, double> sendLossCountHistory;
uint32_t audioTimestampIn;
uint32_t audioTimestampOut;
tgvoip::audio::AudioIO* audioIO=NULL;
tgvoip::audio::AudioInput* audioInput=NULL;
tgvoip::audio::AudioOutput* audioOutput=NULL;
OpusEncoder* encoder;
std::vector<PendingOutgoingPacket> sendQueue;
EchoCanceller* echoCanceller;
Mutex sendBufferMutex;
Mutex endpointsMutex;
Mutex socketSelectMutex;
bool stopping;
bool audioOutStarted;
Thread* recvThread;
Thread* sendThread;
uint32_t packetsReceived;
uint32_t recvLossCount;
uint32_t prevSendLossCount;
uint32_t firstSentPing;
HistoricBuffer<double, 32> rttHistory;
bool waitingForAcks;
int networkType;
int dontSendPackets;
int lastError;
bool micMuted;
uint32_t maxBitrate;
std::vector<std::shared_ptr<Stream>> outgoingStreams;
std::vector<std::shared_ptr<Stream>> incomingStreams;
unsigned char encryptionKey[256];
unsigned char keyFingerprint[8];
unsigned char callID[16];
double stateChangeTime;
bool waitingForRelayPeerInfo;
bool allowP2p;
bool dataSavingMode;
bool dataSavingRequestedByPeer;
std::string activeNetItfName;
double publicEndpointsReqTime;
std::vector<QueuedPacket> queuedPackets;
Mutex audioIOMutex;
Mutex queuedPacketsMutex;
double connectionInitTime;
double lastRecvPacketTime;
Config config;
int32_t peerVersion;
CongestionControl* conctl;
TrafficStats stats;
bool receivedInit;
bool receivedInitAck;
std::vector<std::string> debugLogs;
bool isOutgoing;
NetworkSocket* udpSocket;
NetworkSocket* realUdpSocket;
FILE* statsDump;
std::string currentAudioInput;
std::string currentAudioOutput;
bool useTCP;
bool useUDP;
bool didAddTcpRelays;
SocketSelectCanceller* selectCanceller;
HistoricBuffer<unsigned char, 4, int> signalBarsHistory;
bool audioStarted=false;
int udpConnectivityState;
double lastUdpPingTime;
int udpPingCount;
int echoCancellationStrength;
int proxyProtocol;
std::string proxyAddress;
uint16_t proxyPort;
std::string proxyUsername;
std::string proxyPassword;
IPv4Address* resolvedProxyAddress;
AutomaticGainControl* outputAGC;
bool outputAGCEnabled;
uint32_t peerCapabilities;
Callbacks callbacks;
bool didReceiveGroupCallKey;
bool didReceiveGroupCallKeyAck;
bool didSendGroupCallKey;
bool didSendUpgradeRequest;
bool didInvokeUpgradeCallback;
int32_t connectionMaxLayer;
bool useMTProto2;
bool setCurrentEndpointToTCP;
std::vector<UnacknowledgedExtraData> currentExtras;
std::unordered_map<uint8_t, uint64_t> lastReceivedExtrasByType;
bool useIPv6;
bool peerIPv6Available;
IPv6Address myIPv6;
bool shittyInternetMode;
int extraEcLevel=0;
std::vector<Buffer> ecAudioPackets;
bool didAddIPv6Relays;
bool didSendIPv6Endpoint;
int publicEndpointsReqCount=0;
MessageThread messageThread;
bool wasEstablished=false;
bool receivedFirstStreamPacket=false;
std::atomic<unsigned int> unsentStreamPackets;
HistoricBuffer<unsigned int, 5> unsentStreamPacketsHistory;
bool needReInitUdpProxy=true;
bool needRate=false;
uint32_t initTimeoutID=MessageThread::INVALID_ID;
uint32_t noStreamsNopID=MessageThread::INVALID_ID;
uint32_t udpPingTimeoutID=MessageThread::INVALID_ID;
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
std::function<void(int16_t*, size_t)> audioInputDataCallback;
std::function<void(int16_t*, size_t)> audioOutputDataCallback;
#endif
video::VideoSource* videoSource=NULL;
video::VideoRenderer* videoRenderer=NULL;
double firstVideoFrameTime=0.0;
/*** server config values ***/
uint32_t maxAudioBitrate;
uint32_t maxAudioBitrateEDGE;
uint32_t maxAudioBitrateGPRS;
uint32_t maxAudioBitrateSaving;
uint32_t initAudioBitrate;
uint32_t initAudioBitrateEDGE;
uint32_t initAudioBitrateGPRS;
uint32_t initAudioBitrateSaving;
uint32_t minAudioBitrate;
uint32_t audioBitrateStepIncr;
uint32_t audioBitrateStepDecr;
double relaySwitchThreshold;
double p2pToRelaySwitchThreshold;
double relayToP2pSwitchThreshold;
double reconnectingTimeout;
uint32_t needRateFlags;
double rateMaxAcceptableRTT;
double rateMaxAcceptableSendLoss;
double packetLossToEnableExtraEC;
public:
#ifdef __APPLE__
static double machTimebase;
static uint64_t machTimestart;
#endif
#ifdef _WIN32
static int64_t win32TimeScale;
static bool didInitWin32TimeScale;
#endif
};
class VoIPGroupController : public VoIPController{
public:
VoIPGroupController(int32_t timeDifference);
virtual ~VoIPGroupController();
void SetGroupCallInfo(unsigned char* encryptionKey, unsigned char* reflectorGroupTag, unsigned char* reflectorSelfTag, unsigned char* reflectorSelfSecret, unsigned char* reflectorSelfTagHash, int32_t selfUserID, IPv4Address reflectorAddress, IPv6Address reflectorAddressV6, uint16_t reflectorPort);
void AddGroupCallParticipant(int32_t userID, unsigned char* memberTagHash, unsigned char* serializedStreams, size_t streamsLength);
void RemoveGroupCallParticipant(int32_t userID);
float GetParticipantAudioLevel(int32_t userID);
virtual void SetMicMute(bool mute);
void SetParticipantVolume(int32_t userID, float volume);
void SetParticipantStreams(int32_t userID, unsigned char* serializedStreams, size_t length);
static size_t GetInitialStreams(unsigned char* buf, size_t size);
struct Callbacks : public VoIPController::Callbacks{
void (*updateStreams)(VoIPGroupController*, unsigned char*, size_t);
void (*participantAudioStateChanged)(VoIPGroupController*, int32_t, bool);
};
void SetCallbacks(Callbacks callbacks);
virtual std::string GetDebugString();
virtual void SetNetworkType(int type);
protected:
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint& srcEndpoint);
virtual void SendInit();
virtual void SendUdpPing(Endpoint& endpoint);
virtual void SendRelayPings();
virtual void SendPacket(unsigned char* data, size_t len, Endpoint& ep, PendingOutgoingPacket& srcPacket);
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
virtual void OnAudioOutputReady();
private:
int32_t GetCurrentUnixtime();
std::vector<std::shared_ptr<Stream>> DeserializeStreams(BufferInputStream& in);
void SendRecentPacketsRequest();
void SendSpecialReflectorRequest(unsigned char* data, size_t len);
void SerializeAndUpdateOutgoingStreams();
struct GroupCallParticipant{
int32_t userID;
unsigned char memberTagHash[32];
std::vector<std::shared_ptr<Stream>> streams;
AudioLevelMeter* levelMeter;
};
std::vector<GroupCallParticipant> participants;
unsigned char reflectorSelfTag[16];
unsigned char reflectorSelfSecret[16];
unsigned char reflectorSelfTagHash[32];
int32_t userSelfID;
Endpoint groupReflector;
AudioMixer* audioMixer;
AudioLevelMeter selfLevelMeter;
Callbacks groupCallbacks;
struct PacketIdMapping{
uint32_t seq;
uint16_t id;
double ackTime;
};
std::vector<PacketIdMapping> recentSentPackets;
Mutex sentPacketsMutex;
Mutex participantsMutex;
int32_t timeDifference;
};
};
#endif