302 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop application for the Telegram messaging service.
 | 
						|
 | 
						|
For license and copyright information please follow this link:
 | 
						|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
						|
*/
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include "base/weak_ptr.h"
 | 
						|
#include "base/timer.h"
 | 
						|
#include "base/bytes.h"
 | 
						|
#include "mtproto/sender.h"
 | 
						|
#include "mtproto/mtproto_auth_key.h"
 | 
						|
 | 
						|
namespace Media {
 | 
						|
namespace Audio {
 | 
						|
class Track;
 | 
						|
} // namespace Audio
 | 
						|
} // namespace Media
 | 
						|
 | 
						|
namespace tgcalls {
 | 
						|
class Instance;
 | 
						|
class VideoCaptureInterface;
 | 
						|
enum class State;
 | 
						|
enum class VideoState;
 | 
						|
enum class AudioState;
 | 
						|
} // namespace tgcalls
 | 
						|
 | 
						|
namespace Webrtc {
 | 
						|
enum class VideoState;
 | 
						|
class VideoTrack;
 | 
						|
} // namespace Webrtc
 | 
						|
 | 
						|
namespace Calls {
 | 
						|
 | 
						|
struct DhConfig {
 | 
						|
	int32 version = 0;
 | 
						|
	int32 g = 0;
 | 
						|
	bytes::vector p;
 | 
						|
};
 | 
						|
 | 
						|
enum class ErrorType {
 | 
						|
	NoCamera,
 | 
						|
	NoMicrophone,
 | 
						|
	NotStartedCall,
 | 
						|
	NotVideoCall,
 | 
						|
	Unknown,
 | 
						|
};
 | 
						|
 | 
						|
struct Error {
 | 
						|
	ErrorType type = ErrorType::Unknown;
 | 
						|
	QString details;
 | 
						|
};
 | 
						|
 | 
						|
enum class CallType {
 | 
						|
	Incoming,
 | 
						|
	Outgoing,
 | 
						|
};
 | 
						|
 | 
						|
class Call : public base::has_weak_ptr {
 | 
						|
public:
 | 
						|
	class Delegate {
 | 
						|
	public:
 | 
						|
		virtual DhConfig getDhConfig() const = 0;
 | 
						|
		virtual void callFinished(not_null<Call*> call) = 0;
 | 
						|
		virtual void callFailed(not_null<Call*> call) = 0;
 | 
						|
		virtual void callRedial(not_null<Call*> call) = 0;
 | 
						|
 | 
						|
		enum class CallSound {
 | 
						|
			Connecting,
 | 
						|
			Busy,
 | 
						|
			Ended,
 | 
						|
		};
 | 
						|
		virtual void callPlaySound(CallSound sound) = 0;
 | 
						|
		virtual void callRequestPermissionsOrFail(
 | 
						|
			Fn<void()> onSuccess,
 | 
						|
			bool video) = 0;
 | 
						|
 | 
						|
		virtual auto callGetVideoCapture(
 | 
						|
			const QString &deviceId,
 | 
						|
			bool isScreenCapture)
 | 
						|
		-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;
 | 
						|
 | 
						|
		virtual ~Delegate() = default;
 | 
						|
 | 
						|
	};
 | 
						|
 | 
						|
	static constexpr auto kSoundSampleMs = 100;
 | 
						|
 | 
						|
	using Type = CallType;
 | 
						|
	Call(
 | 
						|
		not_null<Delegate*> delegate,
 | 
						|
		not_null<UserData*> user,
 | 
						|
		Type type,
 | 
						|
		bool video);
 | 
						|
 | 
						|
	[[nodiscard]] Type type() const {
 | 
						|
		return _type;
 | 
						|
	}
 | 
						|
	[[nodiscard]] not_null<UserData*> user() const {
 | 
						|
		return _user;
 | 
						|
	}
 | 
						|
	[[nodiscard]] CallId id() const {
 | 
						|
		return _id;
 | 
						|
	}
 | 
						|
	[[nodiscard]] bool isIncomingWaiting() const;
 | 
						|
 | 
						|
	void start(bytes::const_span random);
 | 
						|
	bool handleUpdate(const MTPPhoneCall &call);
 | 
						|
	bool handleSignalingData(const MTPDupdatePhoneCallSignalingData &data);
 | 
						|
 | 
						|
	enum State {
 | 
						|
		Starting,
 | 
						|
		WaitingInit,
 | 
						|
		WaitingInitAck,
 | 
						|
		Established,
 | 
						|
		FailedHangingUp,
 | 
						|
		Failed,
 | 
						|
		HangingUp,
 | 
						|
		Ended,
 | 
						|
		EndedByOtherDevice,
 | 
						|
		ExchangingKeys,
 | 
						|
		Waiting,
 | 
						|
		Requesting,
 | 
						|
		WaitingIncoming,
 | 
						|
		Ringing,
 | 
						|
		Busy,
 | 
						|
		WaitingUserConfirmation,
 | 
						|
	};
 | 
						|
	[[nodiscard]] State state() const {
 | 
						|
		return _state.current();
 | 
						|
	}
 | 
						|
	[[nodiscard]] rpl::producer<State> stateValue() const {
 | 
						|
		return _state.value();
 | 
						|
	}
 | 
						|
 | 
						|
	[[nodiscard]] rpl::producer<Error> errors() const {
 | 
						|
		return _errors.events();
 | 
						|
	}
 | 
						|
 | 
						|
	enum class RemoteAudioState {
 | 
						|
		Muted,
 | 
						|
		Active,
 | 
						|
	};
 | 
						|
	[[nodiscard]] RemoteAudioState remoteAudioState() const {
 | 
						|
		return _remoteAudioState.current();
 | 
						|
	}
 | 
						|
	[[nodiscard]] auto remoteAudioStateValue() const
 | 
						|
	-> rpl::producer<RemoteAudioState> {
 | 
						|
		return _remoteAudioState.value();
 | 
						|
	}
 | 
						|
 | 
						|
	[[nodiscard]] Webrtc::VideoState remoteVideoState() const {
 | 
						|
		return _remoteVideoState.current();
 | 
						|
	}
 | 
						|
	[[nodiscard]] auto remoteVideoStateValue() const
 | 
						|
	-> rpl::producer<Webrtc::VideoState> {
 | 
						|
		return _remoteVideoState.value();
 | 
						|
	}
 | 
						|
 | 
						|
	static constexpr auto kSignalBarStarting = -1;
 | 
						|
	static constexpr auto kSignalBarFinished = -2;
 | 
						|
	static constexpr auto kSignalBarCount = 4;
 | 
						|
	[[nodiscard]] rpl::producer<int> signalBarCountValue() const {
 | 
						|
		return _signalBarCount.value();
 | 
						|
	}
 | 
						|
 | 
						|
	void setMuted(bool mute);
 | 
						|
	[[nodiscard]] bool muted() const {
 | 
						|
		return _muted.current();
 | 
						|
	}
 | 
						|
	[[nodiscard]] rpl::producer<bool> mutedValue() const {
 | 
						|
		return _muted.value();
 | 
						|
	}
 | 
						|
 | 
						|
	[[nodiscard]] not_null<Webrtc::VideoTrack*> videoIncoming() const;
 | 
						|
	[[nodiscard]] not_null<Webrtc::VideoTrack*> videoOutgoing() const;
 | 
						|
 | 
						|
	crl::time getDurationMs() const;
 | 
						|
	float64 getWaitingSoundPeakValue() const;
 | 
						|
 | 
						|
	void applyUserConfirmation();
 | 
						|
	void answer();
 | 
						|
	void hangup();
 | 
						|
	void redial();
 | 
						|
 | 
						|
	bool isKeyShaForFingerprintReady() const;
 | 
						|
	bytes::vector getKeyShaForFingerprint() const;
 | 
						|
 | 
						|
	QString getDebugLog() const;
 | 
						|
 | 
						|
	void setCurrentAudioDevice(bool input, const QString &deviceId);
 | 
						|
	//void setAudioVolume(bool input, float level);
 | 
						|
	void setAudioDuckingEnabled(bool enabled);
 | 
						|
 | 
						|
	void setCurrentCameraDevice(const QString &deviceId);
 | 
						|
	[[nodiscard]] QString videoDeviceId() const {
 | 
						|
		return _videoCaptureDeviceId;
 | 
						|
	}
 | 
						|
 | 
						|
	[[nodiscard]] bool isSharingVideo() const;
 | 
						|
	[[nodiscard]] bool isSharingCamera() const;
 | 
						|
	[[nodiscard]] bool isSharingScreen() const;
 | 
						|
	[[nodiscard]] QString cameraSharingDeviceId() const;
 | 
						|
	[[nodiscard]] QString screenSharingDeviceId() const;
 | 
						|
	void toggleCameraSharing(bool enabled);
 | 
						|
	void toggleScreenSharing(std::optional<QString> uniqueId);
 | 
						|
 | 
						|
	[[nodiscard]] rpl::lifetime &lifetime() {
 | 
						|
		return _lifetime;
 | 
						|
	}
 | 
						|
 | 
						|
	~Call();
 | 
						|
 | 
						|
private:
 | 
						|
	enum class FinishType {
 | 
						|
		None,
 | 
						|
		Ended,
 | 
						|
		Failed,
 | 
						|
	};
 | 
						|
 | 
						|
	void handleRequestError(const QString &error);
 | 
						|
	void handleControllerError(const QString &error);
 | 
						|
	void finish(
 | 
						|
		FinishType type,
 | 
						|
		const MTPPhoneCallDiscardReason &reason
 | 
						|
			= MTP_phoneCallDiscardReasonDisconnect());
 | 
						|
	void startOutgoing();
 | 
						|
	void startIncoming();
 | 
						|
	void startWaitingTrack();
 | 
						|
	void sendSignalingData(const QByteArray &data);
 | 
						|
 | 
						|
	void generateModExpFirst(bytes::const_span randomSeed);
 | 
						|
	void handleControllerStateChange(tgcalls::State state);
 | 
						|
	void handleControllerBarCountChange(int count);
 | 
						|
	void createAndStartController(const MTPDphoneCall &call);
 | 
						|
 | 
						|
	template <typename T>
 | 
						|
	bool checkCallCommonFields(const T &call);
 | 
						|
	bool checkCallFields(const MTPDphoneCall &call);
 | 
						|
	bool checkCallFields(const MTPDphoneCallAccepted &call);
 | 
						|
 | 
						|
	void actuallyAnswer();
 | 
						|
	void confirmAcceptedCall(const MTPDphoneCallAccepted &call);
 | 
						|
	void startConfirmedCall(const MTPDphoneCall &call);
 | 
						|
	void setState(State state);
 | 
						|
	void setStateQueued(State state);
 | 
						|
	void setFailedQueued(const QString &error);
 | 
						|
	void setSignalBarCount(int count);
 | 
						|
	void destroyController();
 | 
						|
 | 
						|
	void setupOutgoingVideo();
 | 
						|
	void updateRemoteMediaState(
 | 
						|
		tgcalls::AudioState audio,
 | 
						|
		tgcalls::VideoState video);
 | 
						|
 | 
						|
	const not_null<Delegate*> _delegate;
 | 
						|
	const not_null<UserData*> _user;
 | 
						|
	MTP::Sender _api;
 | 
						|
	Type _type = Type::Outgoing;
 | 
						|
	rpl::variable<State> _state = State::Starting;
 | 
						|
	rpl::variable<RemoteAudioState> _remoteAudioState =
 | 
						|
		RemoteAudioState::Active;
 | 
						|
	rpl::variable<Webrtc::VideoState> _remoteVideoState;
 | 
						|
	rpl::event_stream<Error> _errors;
 | 
						|
	FinishType _finishAfterRequestingCall = FinishType::None;
 | 
						|
	bool _answerAfterDhConfigReceived = false;
 | 
						|
	rpl::variable<int> _signalBarCount = kSignalBarStarting;
 | 
						|
	crl::time _startTime = 0;
 | 
						|
	base::DelayedCallTimer _finishByTimeoutTimer;
 | 
						|
	base::Timer _discardByTimeoutTimer;
 | 
						|
 | 
						|
	rpl::variable<bool> _muted = false;
 | 
						|
 | 
						|
	DhConfig _dhConfig;
 | 
						|
	bytes::vector _ga;
 | 
						|
	bytes::vector _gb;
 | 
						|
	bytes::vector _gaHash;
 | 
						|
	bytes::vector _randomPower;
 | 
						|
	MTP::AuthKey::Data _authKey;
 | 
						|
 | 
						|
	CallId _id = 0;
 | 
						|
	uint64 _accessHash = 0;
 | 
						|
	uint64 _keyFingerprint = 0;
 | 
						|
 | 
						|
	std::unique_ptr<tgcalls::Instance> _instance;
 | 
						|
	std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;
 | 
						|
	QString _videoCaptureDeviceId;
 | 
						|
	bool _videoCaptureIsScreencast = false;
 | 
						|
	const std::unique_ptr<Webrtc::VideoTrack> _videoIncoming;
 | 
						|
	const std::unique_ptr<Webrtc::VideoTrack> _videoOutgoing;
 | 
						|
 | 
						|
	std::unique_ptr<Media::Audio::Track> _waitingTrack;
 | 
						|
 | 
						|
	rpl::lifetime _lifetime;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
void UpdateConfig(const std::string &data);
 | 
						|
 | 
						|
} // namespace Calls
 |