mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
4b40d20e96
@ -1943,23 +1943,6 @@ ios_application(
|
||||
],
|
||||
)
|
||||
|
||||
swift_library(
|
||||
name = "UITestsLib",
|
||||
module_name = "UITestsLib",
|
||||
srcs = glob(["UITests/**/*.swift"]),
|
||||
deps = [
|
||||
"//submodules/TelegramUI:TelegramUI",
|
||||
],
|
||||
)
|
||||
|
||||
ios_ui_test(
|
||||
name = "UITests",
|
||||
minimum_os_version = "9.0",
|
||||
deps = [":UITestsLib"],
|
||||
infoplists = [":UITestsLib/Info.plist"],
|
||||
test_host = ":Telegram",
|
||||
)
|
||||
|
||||
# Temporary targets used to simplify webrtc build tests
|
||||
|
||||
ios_application(
|
||||
|
||||
10
Tests/AllTests/BUILD
Normal file
10
Tests/AllTests/BUILD
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
test_suite(
|
||||
name = "AllTests",
|
||||
tests = [
|
||||
"//submodules/TgVoipWebrtc:TgCallsTests",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
@ -144,6 +144,17 @@ class BazelCommandLine:
|
||||
# Build single-architecture binaries. It is almost 2 times faster is 32-bit support is not required.
|
||||
'--ios_multi_cpus=arm64',
|
||||
|
||||
# Always build universal Watch binaries.
|
||||
'--watchos_cpus=armv7k,arm64_32'
|
||||
] + self.common_debug_args
|
||||
elif configuration == 'debug_sim_arm64':
|
||||
self.configuration_args = [
|
||||
# bazel debug build configuration
|
||||
'-c', 'dbg',
|
||||
|
||||
# Build single-architecture binaries. It is almost 2 times faster is 32-bit support is not required.
|
||||
'--ios_multi_cpus=sim_arm64',
|
||||
|
||||
# Always build universal Watch binaries.
|
||||
'--watchos_cpus=armv7k,arm64_32'
|
||||
] + self.common_debug_args
|
||||
@ -317,6 +328,47 @@ class BazelCommandLine:
|
||||
call_executable(combined_arguments)
|
||||
|
||||
|
||||
def invoke_test(self):
|
||||
combined_arguments = [
|
||||
self.build_environment.bazel_path
|
||||
]
|
||||
combined_arguments += self.get_startup_bazel_arguments()
|
||||
combined_arguments += ['test']
|
||||
|
||||
combined_arguments += ['--cache_test_results=no']
|
||||
combined_arguments += ['--test_output=errors']
|
||||
|
||||
combined_arguments += ['Tests/AllTests']
|
||||
|
||||
if self.configuration_path is None:
|
||||
raise Exception('configuration_path is not defined')
|
||||
|
||||
combined_arguments += [
|
||||
'--override_repository=build_configuration={}'.format(self.configuration_path)
|
||||
]
|
||||
|
||||
combined_arguments += self.common_args
|
||||
combined_arguments += self.common_build_args
|
||||
combined_arguments += self.get_define_arguments()
|
||||
combined_arguments += self.get_additional_build_arguments()
|
||||
|
||||
if self.remote_cache is not None:
|
||||
combined_arguments += [
|
||||
'--remote_cache={}'.format(self.remote_cache),
|
||||
'--experimental_remote_downloader={}'.format(self.remote_cache)
|
||||
]
|
||||
elif self.cache_dir is not None:
|
||||
combined_arguments += [
|
||||
'--disk_cache={path}'.format(path=self.cache_dir)
|
||||
]
|
||||
|
||||
combined_arguments += self.configuration_args
|
||||
|
||||
print('TelegramBuild: running')
|
||||
print(subprocess.list2cmdline(combined_arguments))
|
||||
call_executable(combined_arguments)
|
||||
|
||||
|
||||
def clean(bazel, arguments):
|
||||
bazel_command_line = BazelCommandLine(
|
||||
bazel=bazel,
|
||||
@ -430,6 +482,27 @@ def build(bazel, arguments):
|
||||
bazel_command_line.invoke_build()
|
||||
|
||||
|
||||
def test(bazel, arguments):
|
||||
bazel_command_line = BazelCommandLine(
|
||||
bazel=bazel,
|
||||
override_bazel_version=arguments.overrideBazelVersion,
|
||||
override_xcode_version=arguments.overrideXcodeVersion,
|
||||
bazel_user_root=arguments.bazelUserRoot
|
||||
)
|
||||
|
||||
if arguments.cacheDir is not None:
|
||||
bazel_command_line.add_cache_dir(arguments.cacheDir)
|
||||
elif arguments.cacheHost is not None:
|
||||
bazel_command_line.add_remote_cache(arguments.cacheHost)
|
||||
|
||||
resolve_configuration(bazel_command_line, arguments)
|
||||
|
||||
bazel_command_line.set_configuration('debug_sim_arm64')
|
||||
bazel_command_line.set_build_number('10000')
|
||||
|
||||
bazel_command_line.invoke_test()
|
||||
|
||||
|
||||
def add_project_and_build_common_arguments(current_parser: argparse.ArgumentParser):
|
||||
group = current_parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument(
|
||||
@ -520,6 +593,13 @@ if __name__ == '__main__':
|
||||
'''
|
||||
)
|
||||
|
||||
testParser = subparsers.add_parser(
|
||||
'test', help='''
|
||||
Run all tests.
|
||||
'''
|
||||
)
|
||||
add_project_and_build_common_arguments(testParser)
|
||||
|
||||
generateProjectParser = subparsers.add_parser('generateProject', help='Generate Xcode project')
|
||||
generateProjectParser.add_argument(
|
||||
'--buildNumber',
|
||||
@ -646,6 +726,8 @@ if __name__ == '__main__':
|
||||
generate_project(bazel=bazel_path, arguments=args)
|
||||
elif args.commandName == 'build':
|
||||
build(bazel=bazel_path, arguments=args)
|
||||
elif args.commandName == 'test':
|
||||
test(bazel=bazel_path, arguments=args)
|
||||
else:
|
||||
raise Exception('Unknown command')
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@ -92,7 +92,7 @@ def generate(build_environment: BuildEnvironment, disable_extensions, disable_pr
|
||||
bazel_build_arguments += ['--//{}:disableProvisioningProfiles'.format(app_target)]
|
||||
if generate_dsym:
|
||||
bazel_build_arguments += ['--apple_generate_dsym']
|
||||
bazel_build_arguments += ['--//{}:disableStripping'.format(app_target)]
|
||||
bazel_build_arguments += ['--//{}:disableStripping'.format('Telegram')]
|
||||
bazel_build_arguments += ['--strip=never']
|
||||
|
||||
call_executable([
|
||||
|
||||
@ -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