mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Update tgcalls
This commit is contained in:
parent
a7061c651a
commit
84f9f6f24e
@ -728,6 +728,18 @@ public final class OngoingCallContext {
|
||||
filteredConnections.append(contentsOf: callConnectionDescriptionsWebrtc(connection))
|
||||
}
|
||||
|
||||
/*#if DEBUG
|
||||
filteredConnections.removeAll()
|
||||
filteredConnections.append(OngoingCallConnectionDescriptionWebrtc(
|
||||
connectionId: 1,
|
||||
hasStun: true,
|
||||
hasTurn: true, ip: "178.62.7.192",
|
||||
port: 1400,
|
||||
username: "user",
|
||||
password: "user")
|
||||
)
|
||||
#endif*/
|
||||
|
||||
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, allowTCP: enableTCP, enableStunMarking: enableStunMarking, logPath: tempLogPath, statsLogPath: tempStatsLogPath, sendSignalingData: { [weak callSessionManager] data in
|
||||
callSessionManager?.sendSignalingData(internalId: internalId, data: data)
|
||||
}, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec, audioInputDeviceId: "")
|
||||
|
@ -1,3 +1,4 @@
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
|
||||
|
||||
config_setting(
|
||||
name = "debug_build",
|
||||
@ -92,9 +93,52 @@ objc_library(
|
||||
"VideoToolbox",
|
||||
"CoreTelephony",
|
||||
"CoreMedia",
|
||||
"GLKit",
|
||||
"AVFoundation",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "TgCallsTestsLib",
|
||||
copts = [
|
||||
"-I{}/tgcalls/tgcalls".format(package_name()),
|
||||
"-Ithird-party/webrtc/webrtc",
|
||||
"-Ithird-party/webrtc/dependencies",
|
||||
"-Ithird-party/webrtc/dependencies/third_party/abseil-cpp",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc/base",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc/components/renderer/metal",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc/components/renderer/opengl",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc/components/video_codec",
|
||||
"-Ithird-party/libyuv/third_party/libyuv/include",
|
||||
"-Ithird-party/libyuv",
|
||||
"-Ithird-party/webrtc/webrtc/sdk/objc/api/video_codec",
|
||||
"-DWEBRTC_IOS",
|
||||
"-DWEBRTC_MAC",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DRTC_ENABLE_VP9",
|
||||
"-DTGVOIP_NAMESPACE=tgvoip_webrtc",
|
||||
"-std=c++14",
|
||||
],
|
||||
srcs = glob([
|
||||
"tests/*.m",
|
||||
"tests/*.mm",
|
||||
]),
|
||||
deps = [
|
||||
":TgVoipWebrtc"
|
||||
],
|
||||
)
|
||||
|
||||
ios_unit_test(
|
||||
name = "TgCallsTests",
|
||||
minimum_os_version = "9.0",
|
||||
deps = [
|
||||
":TgCallsTestsLib",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
705
submodules/TgVoipWebrtc/tests/TestNegotiation.mm
Normal file
705
submodules/TgVoipWebrtc/tests/TestNegotiation.mm
Normal file
@ -0,0 +1,705 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "api/task_queue/default_task_queue_factory.h"
|
||||
#include "media/engine/webrtc_media_engine.h"
|
||||
#include "api/audio_codecs/audio_encoder_factory_template.h"
|
||||
#include "api/audio_codecs/audio_decoder_factory_template.h"
|
||||
#include "api/audio_codecs/opus/audio_decoder_opus.h"
|
||||
#include "api/audio_codecs/opus/audio_decoder_multi_channel_opus.h"
|
||||
#include "api/audio_codecs/opus/audio_encoder_opus.h"
|
||||
#include "api/audio_codecs/L16/audio_decoder_L16.h"
|
||||
#include "api/audio_codecs/L16/audio_encoder_L16.h"
|
||||
|
||||
#include "StaticThreads.h"
|
||||
#include "FakeAudioDeviceModule.h"
|
||||
#include "platform/PlatformInterface.h"
|
||||
|
||||
#include "v2/ContentNegotiation.h"
|
||||
|
||||
namespace {
|
||||
class Context {
|
||||
public:
|
||||
Context(bool isOutgoing) :
|
||||
_isOutgoing(isOutgoing),
|
||||
_threads(tgcalls::StaticThreads::getThreads()),
|
||||
_taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()),
|
||||
_uniqueRandomIdGenerator(std::make_unique<rtc::UniqueRandomIdGenerator>()) {
|
||||
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [&]() {
|
||||
cricket::MediaEngineDependencies mediaDeps;
|
||||
mediaDeps.task_queue_factory = _taskQueueFactory.get();
|
||||
mediaDeps.audio_encoder_factory = webrtc::CreateAudioEncoderFactory<webrtc::AudioEncoderOpus, webrtc::AudioEncoderL16>();
|
||||
mediaDeps.audio_decoder_factory = webrtc::CreateAudioDecoderFactory<webrtc::AudioDecoderOpus, webrtc::AudioDecoderL16>();
|
||||
|
||||
mediaDeps.video_encoder_factory = tgcalls::PlatformInterface::SharedInstance()->makeVideoEncoderFactory(true);
|
||||
mediaDeps.video_decoder_factory = tgcalls::PlatformInterface::SharedInstance()->makeVideoDecoderFactory();
|
||||
|
||||
tgcalls::FakeAudioDeviceModule::Options options;
|
||||
options.num_channels = 1;
|
||||
_audioDeviceModule = tgcalls::FakeAudioDeviceModule::Creator(nullptr, nullptr, options)(_taskQueueFactory.get());
|
||||
|
||||
mediaDeps.adm = _audioDeviceModule;
|
||||
|
||||
_mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps));
|
||||
|
||||
_channelManager = cricket::ChannelManager::Create(
|
||||
std::move(_mediaEngine),
|
||||
true,
|
||||
_threads->getWorkerThread(),
|
||||
_threads->getNetworkThread()
|
||||
);
|
||||
});
|
||||
|
||||
_contentNegotiationContext = std::make_unique<tgcalls::ContentNegotiationContext>(isOutgoing, _uniqueRandomIdGenerator.get());
|
||||
_contentNegotiationContext->copyCodecsFromChannelManager(_channelManager.get(), isOutgoing);
|
||||
}
|
||||
|
||||
~Context() {
|
||||
_contentNegotiationContext.reset();
|
||||
|
||||
_threads->getWorkerThread()->Invoke<void>(RTC_FROM_HERE, [&]() {
|
||||
_channelManager.reset();
|
||||
_mediaEngine.reset();
|
||||
_audioDeviceModule = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
tgcalls::ContentNegotiationContext *contentNegotiationContext() const {
|
||||
return _contentNegotiationContext.get();
|
||||
}
|
||||
|
||||
void assertSsrcs(std::vector<uint32_t> const &outgoingSsrcs, std::vector<uint32_t> const &incomingSsrcs) {
|
||||
std::set<uint32_t> incomingSsrcsSet;
|
||||
for (auto ssrc : incomingSsrcs) {
|
||||
incomingSsrcsSet.insert(ssrc);
|
||||
}
|
||||
|
||||
std::set<uint32_t> outgoingSsrcsSet;
|
||||
for (auto ssrc : outgoingSsrcs) {
|
||||
outgoingSsrcsSet.insert(ssrc);
|
||||
}
|
||||
|
||||
std::set<uint32_t> actualIncomingSsrcs;
|
||||
std::set<uint32_t> actualOutgoingSsrcs;
|
||||
|
||||
auto coordinatedState = _contentNegotiationContext->coordinatedState();
|
||||
XCTAssert(coordinatedState != nullptr);
|
||||
|
||||
for (const auto &content : coordinatedState->incomingContents) {
|
||||
actualIncomingSsrcs.insert(content.ssrc);
|
||||
}
|
||||
for (const auto &content : coordinatedState->outgoingContents) {
|
||||
actualOutgoingSsrcs.insert(content.ssrc);
|
||||
}
|
||||
|
||||
XCTAssert(incomingSsrcsSet == actualIncomingSsrcs);
|
||||
XCTAssert(outgoingSsrcsSet == actualOutgoingSsrcs);
|
||||
}
|
||||
|
||||
bool isContentsEqualToRemote(Context &remoteContext) {
|
||||
auto localCoordinatedState = _contentNegotiationContext->coordinatedState();
|
||||
auto remoteCoordinatedState = remoteContext.contentNegotiationContext()->coordinatedState();
|
||||
|
||||
auto mediaContentComparator = [](tgcalls::signaling::MediaContent const &lhs, tgcalls::signaling::MediaContent const &rhs) -> bool {
|
||||
return lhs.ssrc < rhs.ssrc;
|
||||
};
|
||||
|
||||
auto localIncomingContents = localCoordinatedState->incomingContents;
|
||||
std::sort(localIncomingContents.begin(), localIncomingContents.end(), mediaContentComparator);
|
||||
|
||||
auto localOutgoingContents = localCoordinatedState->outgoingContents;
|
||||
std::sort(localOutgoingContents.begin(), localOutgoingContents.end(), mediaContentComparator);
|
||||
|
||||
auto remoteIncomingContents = remoteCoordinatedState->incomingContents;
|
||||
std::sort(remoteIncomingContents.begin(), remoteIncomingContents.end(), mediaContentComparator);
|
||||
|
||||
auto remoteOutgoingContents = remoteCoordinatedState->outgoingContents;
|
||||
std::sort(remoteOutgoingContents.begin(), remoteOutgoingContents.end(), mediaContentComparator);
|
||||
|
||||
if (localIncomingContents != remoteOutgoingContents) {
|
||||
return false;
|
||||
}
|
||||
if (localOutgoingContents != remoteIncomingContents) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
__unused bool _isOutgoing = false;
|
||||
std::shared_ptr<tgcalls::Threads> _threads;
|
||||
std::unique_ptr<webrtc::TaskQueueFactory> _taskQueueFactory;
|
||||
std::unique_ptr<rtc::UniqueRandomIdGenerator> _uniqueRandomIdGenerator;
|
||||
rtc::scoped_refptr<webrtc::AudioDeviceModule> _audioDeviceModule;
|
||||
std::unique_ptr<cricket::MediaEngineInterface> _mediaEngine;
|
||||
std::unique_ptr<cricket::ChannelManager> _channelManager;
|
||||
std::unique_ptr<tgcalls::ContentNegotiationContext> _contentNegotiationContext;
|
||||
};
|
||||
|
||||
std::unique_ptr<tgcalls::ContentNegotiationContext::NegotiationContents> copyNegotiationContents(tgcalls::ContentNegotiationContext::NegotiationContents *value) {
|
||||
if (!value) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = std::make_unique<tgcalls::ContentNegotiationContext::NegotiationContents>();
|
||||
result->exchangeId = value->exchangeId;
|
||||
result->contents = value->contents;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void runUntilStableSequential(Context &localContext, Context &remoteContext) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
auto localOffer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
if (localOffer) {
|
||||
auto remoteAnswer = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(localOffer.get()));
|
||||
XCTAssert(remoteAnswer != nullptr);
|
||||
|
||||
auto localResponse = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(remoteAnswer.get()));
|
||||
XCTAssert(localResponse == nullptr);
|
||||
} else {
|
||||
auto remoteOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
if (remoteOffer) {
|
||||
auto localAnswer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(remoteOffer.get()));
|
||||
XCTAssert(localAnswer != nullptr);
|
||||
|
||||
auto remoteResponse = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(localAnswer.get()));
|
||||
XCTAssert(remoteResponse == nullptr);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XCTFail(@"Did not complete");
|
||||
}
|
||||
|
||||
void runUntilStableConcurrent(Context &localContext, Context &remoteContext) {
|
||||
std::vector<std::unique_ptr<tgcalls::ContentNegotiationContext::NegotiationContents>> localNegotiationContent;
|
||||
std::vector<std::unique_ptr<tgcalls::ContentNegotiationContext::NegotiationContents>> remoteNegotiationContent;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
std::unique_ptr<tgcalls::ContentNegotiationContext::NegotiationContents> nextLocalNegotiationContent;
|
||||
std::unique_ptr<tgcalls::ContentNegotiationContext::NegotiationContents> nextRemoteNegotiationContent;
|
||||
|
||||
while (!localNegotiationContent.empty()) {
|
||||
auto content = std::move(localNegotiationContent[0]);
|
||||
localNegotiationContent.erase(localNegotiationContent.begin());
|
||||
|
||||
nextRemoteNegotiationContent = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(content.get()));
|
||||
}
|
||||
while (!remoteNegotiationContent.empty()) {
|
||||
auto content = std::move(remoteNegotiationContent[0]);
|
||||
remoteNegotiationContent.erase(remoteNegotiationContent.begin());
|
||||
|
||||
nextLocalNegotiationContent = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(content.get()));
|
||||
}
|
||||
|
||||
if (nextLocalNegotiationContent) {
|
||||
localNegotiationContent.push_back(std::move(nextLocalNegotiationContent));
|
||||
}
|
||||
if (nextRemoteNegotiationContent) {
|
||||
remoteNegotiationContent.push_back(std::move(nextRemoteNegotiationContent));
|
||||
}
|
||||
|
||||
auto localOffer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
if (localOffer) {
|
||||
localNegotiationContent.push_back(std::move(localOffer));
|
||||
}
|
||||
|
||||
auto remoteOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
if (remoteOffer) {
|
||||
remoteNegotiationContent.push_back(std::move(remoteOffer));
|
||||
}
|
||||
|
||||
if (localNegotiationContent.empty() && remoteNegotiationContent.empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
XCTFail(@"Did not complete");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@interface NegotiationTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation NegotiationTests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.continueAfterFailure = false;
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testNegotiateEmpty {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() != nullptr);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->getPendingOffer() != nullptr);
|
||||
}
|
||||
|
||||
- (void)testNegotiateAudioOnewayOutgoing {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto offer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(offer != nullptr);
|
||||
XCTAssert(offer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto response = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(offer.get()));
|
||||
XCTAssert(response != nullptr);
|
||||
XCTAssert(response->contents.size() == offer->contents.size());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto backOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(backOffer != nullptr);
|
||||
XCTAssert(backOffer->contents.size() == 0);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToAnswer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(response.get()));
|
||||
XCTAssert(responseToAnswer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto nextOffer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(nextOffer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
}
|
||||
|
||||
- (void)testNegotiateAudioOnewayIncoming {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto offer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(offer != nullptr);
|
||||
XCTAssert(offer->contents.empty());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto response = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(offer.get()));
|
||||
XCTAssert(response != nullptr);
|
||||
XCTAssert(response->contents.size() == offer->contents.size());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto backOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(backOffer != nullptr);
|
||||
XCTAssert(backOffer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToAnswer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(response.get()));
|
||||
XCTAssert(responseToAnswer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToBackOffer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(backOffer.get()));
|
||||
XCTAssert(responseToBackOffer != nullptr);
|
||||
XCTAssert(responseToBackOffer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToBackOfferAnswer = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(responseToBackOffer.get()));
|
||||
XCTAssert(responseToBackOfferAnswer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
}
|
||||
|
||||
- (void)testNegotiateAudioTwoway {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto offer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(offer != nullptr);
|
||||
XCTAssert(offer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto response = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(offer.get()));
|
||||
XCTAssert(response != nullptr);
|
||||
XCTAssert(response->contents.size() == offer->contents.size());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto backOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(backOffer != nullptr);
|
||||
XCTAssert(backOffer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToAnswer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(response.get()));
|
||||
XCTAssert(responseToAnswer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.empty());
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
auto responseToBackOffer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(backOffer.get()));
|
||||
XCTAssert(responseToBackOffer != nullptr);
|
||||
XCTAssert(responseToBackOffer->contents.size() == 1);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.empty());
|
||||
|
||||
auto responseToBackOfferAnswer = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(responseToBackOffer.get()));
|
||||
XCTAssert(responseToBackOfferAnswer == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->getPendingOffer() == nullptr);
|
||||
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(localContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->incomingContents[0].ssrc == offer->contents[0].ssrc);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents.size() == 1);
|
||||
XCTAssert(remoteContext.contentNegotiationContext()->coordinatedState()->outgoingContents[0].ssrc == backOffer->contents[0].ssrc);
|
||||
}
|
||||
|
||||
- (void)testConcurrentOffers {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
auto localOffer = localContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(localOffer != nullptr);
|
||||
|
||||
auto remoteOffer = remoteContext.contentNegotiationContext()->getPendingOffer();
|
||||
XCTAssert(remoteOffer != nullptr);
|
||||
|
||||
auto localAnswer = remoteContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(localOffer.get()));
|
||||
XCTAssert(localAnswer != nullptr);
|
||||
XCTAssert(localAnswer->exchangeId == localOffer->exchangeId);
|
||||
|
||||
auto remoteAnswer = localContext.contentNegotiationContext()->setRemoteNegotiationContent(copyNegotiationContents(remoteOffer.get()));
|
||||
XCTAssert(remoteAnswer == nullptr);
|
||||
}
|
||||
|
||||
- (void)service_runUntilStable1Using:(std::function<void(Context &localContext, Context &remoteContext)>)runUntilStable {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localContext.assertSsrcs({}, {});
|
||||
remoteContext.assertSsrcs({}, {});
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto localAudioId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto localAudioSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localAudioId);
|
||||
XCTAssert(localAudioSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, {});
|
||||
remoteContext.assertSsrcs({}, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto remoteAudioId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto remoteAudioSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteAudioId);
|
||||
XCTAssert(remoteAudioSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value() }, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto remoteVideoId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto remoteVideoSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteVideoId);
|
||||
XCTAssert(remoteVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value() }, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto localVideoId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto remoteScreencastId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto remoteScreencastSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteScreencastId);
|
||||
XCTAssert(remoteScreencastSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
localContext.contentNegotiationContext()->removeOutgoingChannel(localVideoId);
|
||||
|
||||
// local removal is reflected right away
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(!localVideoSsrc);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(!localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
localVideoId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
}
|
||||
|
||||
- (void)service_runUntilStable2Using:(std::function<void(Context &localContext, Context &remoteContext)>)runUntilStable {
|
||||
Context localContext(true);
|
||||
Context remoteContext(false);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localContext.assertSsrcs({}, {});
|
||||
remoteContext.assertSsrcs({}, {});
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto localAudioId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
auto remoteAudioId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Audio);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto localAudioSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localAudioId);
|
||||
XCTAssert(localAudioSsrc);
|
||||
|
||||
auto remoteAudioSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteAudioId);
|
||||
XCTAssert(remoteAudioSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value() }, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto remoteVideoId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
auto localVideoId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto remoteVideoSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteVideoId);
|
||||
XCTAssert(remoteVideoSsrc);
|
||||
|
||||
auto localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
auto remoteScreencastId = remoteContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
auto remoteScreencastSsrc = remoteContext.contentNegotiationContext()->outgoingChannelSsrc(remoteScreencastId);
|
||||
XCTAssert(remoteScreencastSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
localContext.contentNegotiationContext()->removeOutgoingChannel(localVideoId);
|
||||
|
||||
// local removal is reflected right away
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(!localVideoSsrc);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(!localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
|
||||
localVideoId = localContext.contentNegotiationContext()->addOutgoingChannel(tgcalls::signaling::MediaContent::Type::Video);
|
||||
|
||||
runUntilStable(localContext, remoteContext);
|
||||
|
||||
localVideoSsrc = localContext.contentNegotiationContext()->outgoingChannelSsrc(localVideoId);
|
||||
XCTAssert(localVideoSsrc);
|
||||
|
||||
localContext.assertSsrcs({ localAudioSsrc.value(), localVideoSsrc.value() }, { remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() });
|
||||
remoteContext.assertSsrcs({ remoteAudioSsrc.value(), remoteVideoSsrc.value(), remoteScreencastSsrc.value() }, { localAudioSsrc.value(), localVideoSsrc.value() });
|
||||
localContext.isContentsEqualToRemote(remoteContext);
|
||||
}
|
||||
- (void)testConvergenceSequential1 {
|
||||
[self service_runUntilStable1Using:&runUntilStableSequential];
|
||||
}
|
||||
|
||||
- (void)testConvergenceSequential2 {
|
||||
[self service_runUntilStable2Using:&runUntilStableSequential];
|
||||
}
|
||||
|
||||
- (void)testConvergenceConcurrent1 {
|
||||
[self service_runUntilStable1Using:&runUntilStableConcurrent];
|
||||
}
|
||||
|
||||
- (void)testConvergenceConcurrent2 {
|
||||
[self service_runUntilStable2Using:&runUntilStableConcurrent];
|
||||
}
|
||||
|
||||
@end
|
@ -1 +1 @@
|
||||
Subproject commit 33af0208111e5994e33c7fbb8872cd08bf38edd7
|
||||
Subproject commit 95369c01dfc8639b89dd91c4bc6e9da2ae2ed223
|
Loading…
x
Reference in New Issue
Block a user