From 0ed78b263b687386549e17d7aa54d49f0d12345c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 5 Aug 2015 16:57:44 +0200 Subject: [PATCH 01/46] submodules: update belle-sip and linphone --- submodules/belle-sip | 2 +- submodules/linphone | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/belle-sip b/submodules/belle-sip index 3cf82aaf9..91ae7c164 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 3cf82aaf9e1a84a8438341b026abd8c13520e005 +Subproject commit 91ae7c164d9d20fd36657943a0aba807b4dfeb4f diff --git a/submodules/linphone b/submodules/linphone index 441696255..b2284a34d 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 4416962557c9cd90c6cb22efd06f73d9155a4f8a +Subproject commit b2284a34dfdce1b6a1bdecf07c8d3c75ad8e6e8e From 793d80b3d63f1b342cebdb2ce1f1ea1c7579d8cd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Aug 2015 11:19:55 +0200 Subject: [PATCH 02/46] update linphone submodule to fix crash in tests --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index b2284a34d..63b1c6196 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit b2284a34dfdce1b6a1bdecf07c8d3c75ad8e6e8e +Subproject commit 63b1c6196d9bf19d1542d2d0113af6c8cd41b990 From 61929cb27abc6d5b283537faf9998d6c95c4c67d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 6 Aug 2015 14:08:54 +0200 Subject: [PATCH 03/46] prepare.py: add --tunnel option and fix dummy libraries --- .gitignore | 2 + linphone.xcodeproj/project.pbxproj | 11 ++++-- prepare.py | 57 ++++++++++++++++------------ submodules/binaries/dummy.c | 7 +--- submodules/binaries/libdummy.a | Bin 33420 -> 33276 bytes submodules/binaries/libvpx-armv7.a | Bin 591568 -> 0 bytes submodules/binaries/libvpx-armv7s.a | Bin 371016 -> 0 bytes submodules/binaries/libvpx-i386.a | Bin 566800 -> 0 bytes submodules/binaries/why.txt | 18 +++------ 9 files changed, 48 insertions(+), 47 deletions(-) delete mode 100644 submodules/binaries/libvpx-armv7.a delete mode 100644 submodules/binaries/libvpx-armv7s.a delete mode 100644 submodules/binaries/libvpx-i386.a diff --git a/.gitignore b/.gitignore index fc80e3d8f..45d7cad61 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ WORK Makefile OUTPUT git-clang-format.diff +submodules/tunnel +submodules/binaries/dummy-*.a diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index ed3299a3d..938ab0151 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -10,7 +10,7 @@ 045B5CB318D72E9A0088350C /* libbzrtp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 045B5CB218D72E9A0088350C /* libbzrtp.a */; }; 152F22341B15E83B008C0621 /* libilbcrfc3951.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 152F22331B15E83B008C0621 /* libilbcrfc3951.a */; }; 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 152F22351B15E889008C0621 /* libxml2.dylib */; }; - 1560821F18EEF26100765332 /* libmsopenh264.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1560821E18EEF26100765332 /* libmsopenh264.a */; }; + 1560821F18EEF26100765332 /* libmsopenh264.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1560821E18EEF26100765332 /* libmsopenh264.a */; settings = {ATTRIBUTES = (Weak, ); }; }; 1599105316F746B2007BF52B /* route_bluetooth_off_default_landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 1599104316F746B2007BF52B /* route_bluetooth_off_default_landscape.png */; }; 1599105516F746B2007BF52B /* route_bluetooth_off_disabled_landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 1599104416F746B2007BF52B /* route_bluetooth_off_disabled_landscape.png */; }; 1599105716F746B2007BF52B /* route_bluetooth_off_over_landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = 1599104516F746B2007BF52B /* route_bluetooth_off_over_landscape.png */; }; @@ -162,7 +162,6 @@ 639CEB031A1DF4EB004DE38F /* UICompositeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB051A1DF4EB004DE38F /* UICompositeViewController.xib */; }; 639CEB061A1DF4F1004DE38F /* UIChatRoomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB081A1DF4F1004DE38F /* UIChatRoomCell.xib */; }; 639CEB091A1DF4FA004DE38F /* UIChatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB0B1A1DF4FA004DE38F /* UIChatCell.xib */; }; - 63A4280A1B26F576000DAB93 /* libSKP_SILK_SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226183AA1472527D0037138E /* libSKP_SILK_SDK.a */; }; 63B81A0C1B57DA33009604A6 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 63B81A031B57DA33009604A6 /* LICENSE.txt */; }; 63B81A0D1B57DA33009604A6 /* TPKeyboardAvoidingCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A051B57DA33009604A6 /* TPKeyboardAvoidingCollectionView.m */; }; 63B81A0E1B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A071B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m */; }; @@ -172,6 +171,9 @@ 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; 63D2680F1B174A5E00A2CC11 /* numpad_one_voicemail_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */; }; 63D268101B174A5E00A2CC11 /* numpad_one_voicemail_over.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680E1B174A5E00A2CC11 /* numpad_one_voicemail_over.png */; }; + 63D7215D1B7394D200D70E65 /* libtunnel.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D30BF33216A427BC00AF0026 /* libtunnel.a */; settings = {ATTRIBUTES = (Weak, ); }; }; + 63D7216C1B73973D00D70E65 /* libx264.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22AA8AFB13D7125500B30535 /* libx264.a */; settings = {ATTRIBUTES = (Weak, ); }; }; + 63D7216D1B73975900D70E65 /* libmsx264.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22AA8AFC13D7125500B30535 /* libmsx264.a */; settings = {ATTRIBUTES = (Weak, ); }; }; 63E59A3F1ADE70D900646FB3 /* InAppProductsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E59A3E1ADE70D900646FB3 /* InAppProductsManager.m */; }; 63FB30351A680E73008CA393 /* UIRoundedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63FB30341A680E73008CA393 /* UIRoundedImageView.m */; }; 70571E1A13FABCB000CDD3C2 /* rootca.pem in Resources */ = {isa = PBXBuildFile; fileRef = 70571E1913FABCB000CDD3C2 /* rootca.pem */; }; @@ -963,7 +965,6 @@ 22276E8213C73D3100210156 /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswscale.a; path = "liblinphone-sdk/apple-darwin/lib/libswscale.a"; sourceTree = ""; }; 22276E8613C73D8A00210156 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; 22276E8813C73DC000210156 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; - 223148E31178A08200637D6A /* libilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbc.a; path = "liblinphone-sdk/apple-darwin/lib/libilbc.a"; sourceTree = ""; }; 223148E51178A09900637D6A /* libmsilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsilbc.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsilbc.a"; sourceTree = ""; }; 2234C8E715EE2F7F00E18E83 /* chat_message_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_delivered.png; path = Resources/chat_message_delivered.png; sourceTree = ""; }; 2234C8E815EE2F7F00E18E83 /* chat_message_not_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_not_delivered.png; path = Resources/chat_message_not_delivered.png; sourceTree = ""; }; @@ -1879,7 +1880,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 63A4280A1B26F576000DAB93 /* libSKP_SILK_SDK.a in Frameworks */, + 63D7216D1B73975900D70E65 /* libmsx264.a in Frameworks */, + 63D7215D1B7394D200D70E65 /* libtunnel.a in Frameworks */, + 63D7216C1B73973D00D70E65 /* libx264.a in Frameworks */, 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */, 152F22341B15E83B008C0621 /* libilbcrfc3951.a in Frameworks */, F0B026F31AA710AF00FF49F7 /* libiconv.dylib in Frameworks */, diff --git a/prepare.py b/prepare.py index 7a7089c38..f27c065b1 100755 --- a/prepare.py +++ b/prepare.py @@ -153,31 +153,31 @@ def extract_libs_list(): return list(set(l)) -def check_installed(binary, prog=None, warn=True): +def check_is_installed(binary, prog=None, warn=True): if not find_executable(binary): if warn: print("Could not find {}. Please install {}.".format(binary, prog)) - return 1 - return 0 + return False + return True def check_tools(): - ret = 0 + reterr = 0 if " " in os.path.dirname(os.path.realpath(__file__)): print("Invalid location: linphone-iphone path should not contain any spaces.") - ret = 1 + reterr = 1 for prog in ["autoconf", "automake", "pkg-config", "doxygen", "java", "nasm", "cmake", "wget", "yasm", "optipng"]: - ret |= check_installed(prog, "it") - ret |= check_installed("ginstall", "coreutils") - ret |= check_installed("intltoolize", "intltool") - ret |= check_installed("convert", "imagemagick") + reterr |= not check_is_installed(prog, "it") + reterr |= not check_is_installed("ginstall", "coreutils") + reterr |= not check_is_installed("intltoolize", "intltool") + reterr |= not check_is_installed("convert", "imagemagick") - if not check_installed("libtoolize", warn=False): - if check_installed("glibtoolize", "libtool"): + if check_is_installed("libtoolize", warn=False): + if not check_is_installed("glibtoolize", "libtool"): glibtoolize_path = find_executable(glibtoolize) - ret = 1 + reterr = 1 error = "Please do a symbolic link from glibtoolize to libtoolize: 'ln -s {} ${}'." print(error.format(glibtoolize_path, glibtoolize_path.replace("glibtoolize", "libtoolize"))) @@ -188,10 +188,10 @@ def check_tools(): if p.returncode != 0: print(p.returncode) print("Please install Java JDK (not just JRE).") - ret = 1 + reterr = 1 # needed by x264 - check_installed("gas-preprocessor.pl", """it: + check_is_installed("gas-preprocessor.pl", """it: wget --no-check-certificate https://raw.github.com/yuvi/gas-preprocessor/master/gas-preprocessor.pl chmod +x gas-preprocessor.pl sudo mv gas-preprocessor.pl /usr/local/bin/""") @@ -200,28 +200,28 @@ def check_tools(): if "fatal: unrecognised output format" in nasm_output: print( "Invalid version of nasm: your version does not support elf32 output format. If you have installed nasm, please check that your PATH env variable is set correctly.") - ret = 1 + reterr = 1 if not os.path.isdir("submodules/linphone/mediastreamer2") or not os.path.isdir("submodules/linphone/oRTP"): print("Missing some git submodules. Did you run 'git submodule update --init --recursive'?") - ret = 1 + reterr = 1 p = Popen("xcrun --sdk iphoneos --show-sdk-path".split(" "), stdout=devnull, stderr=devnull) p.wait() if p.returncode != 0: print("iOS SDK not found, please install Xcode from AppStore or equivalent.") - ret = 1 + reterr = 1 else: sdk_platform_path = Popen("xcrun --sdk iphonesimulator --show-sdk-platform-path".split(" "), stdout=PIPE, stderr=devnull).stdout.read()[:-1] sdk_strings_path = "{}/{}".format(sdk_platform_path, "Developer/usr/bin/strings") if not os.path.isfile(sdk_strings_path): strings_path = find_executable("strings") print("strings binary missing, please run 'sudo ln -s {} {}'.".format(strings_path, sdk_strings_path)) - ret = 1 + reterr = 1 - if ret == 1: + if reterr == 1: print("Failed to detect required tools, aborting.") - return ret + return reterr def install_git_hook(): @@ -467,6 +467,8 @@ def main(argv=None): '-G' '--generator', help="CMake build system generator (default: Unix Makefiles).", default='Unix Makefiles', choices=['Unix Makefiles', 'Ninja']) argparser.add_argument( '-L', '--list-cmake-variables', help="List non-advanced CMake cache variables.", action='store_true', dest='list_cmake_variables') + argparser.add_argument( + '-t', '--tunnel', help="Enable Tunnel.", action='store_true') argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ 'x86_64', 'devices'], help="The platform to build for (default is 'x86_64 devices'). Space separated architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) @@ -475,10 +477,6 @@ def main(argv=None): if args.debug_verbose: additional_args += ["-DENABLE_DEBUG_LOGS=YES"] - if os.path.isdir("submodules/tunnel"): - print("Enabling tunnel") - additional_args += ["-DENABLE_TUNNEL=YES"] - if check_tools() != 0: return 1 @@ -486,12 +484,21 @@ def main(argv=None): additional_args += ["-G", args.G__generator] if args.G__generator == 'Ninja': - if check_installed("ninja", "it") != 0: + if not check_is_installed("ninja", "it"): return 1 generator = 'ninja -C' else: generator = '$(MAKE) -C' + if args.tunnel: + if not os.path.isdir("submodules/tunnel"): + print("Tunnel enabled but not found, trying to clone it...") + if check_is_installed("git", "it", True): + Popen("git clone gitosis@git.linphone.org:tunnel.git submodules/tunnel".split(" ")).wait() + additional_args += ["-DENABLE_TUNNEL=YES"] + else: + return 1 + selected_platforms = [] for platform in args.platform: if platform == 'all': diff --git a/submodules/binaries/dummy.c b/submodules/binaries/dummy.c index bf722ecc4..8b1378917 100644 --- a/submodules/binaries/dummy.c +++ b/submodules/binaries/dummy.c @@ -1,6 +1 @@ -//regenerate libdummy.a using: -// for arch in arm64 armv7 i386 x86_64; do -// clang -c dummy.c -o dummy-$arch.a -arch $arch -// done -// lipo -create -output libdummy.a dummy-*.a -void dummy_does_nothing() {} + diff --git a/submodules/binaries/libdummy.a b/submodules/binaries/libdummy.a index 7f9f9467f00ebfab864746992397cd43ed1b64f1..86589a6625676a66d41066dd423b9ae18cd1918b 100644 GIT binary patch delta 396 zcmeBaW%|?1G(pUXVFd#N0}mqu13QprW?)bNQVb`6mp$Gp%5l+}9{Id4_<%#^A&lLqH7O0DXBtRa3gPfAw0t2Ay`(-ybC^Z1> zSj{}C0phX;jFZJ0lqMFiu>Jw*nC#eK&IZ!=2V|Gb literal 33420 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 tabBar -When the app is started, the phoneMainView gets asked to transition to the Dialer view or the Wizard view. +When the application is started, the phoneMainView gets asked to transition to the Dialer view or the Wizard view. PhoneMainView exposes the -changeCurrentView: method, which will setup its Any Linphone view is actually presented in the UICompositeViewController, with or without a stateBar and tabBar. diff --git a/prepare.py b/prepare.py index 53a2ad9db..dac333e16 100755 --- a/prepare.py +++ b/prepare.py @@ -26,6 +26,7 @@ import argparse import os import re import shutil +import tempfile import sys from distutils.spawn import find_executable from subprocess import Popen, PIPE @@ -467,6 +468,8 @@ def main(argv=None): '-G' '--generator', help="CMake build system generator (default: Unix Makefiles).", default='Unix Makefiles', choices=['Unix Makefiles', 'Ninja']) argparser.add_argument( '-L', '--list-cmake-variables', help="List non-advanced CMake cache variables.", action='store_true', dest='list_cmake_variables') + argparser.add_argument( + '-lf', '--list-features', help="List optional features and their default values.", action='store_true', dest='list_features') argparser.add_argument( '-t', '--tunnel', help="Enable Tunnel.", action='store_true') argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ @@ -474,13 +477,11 @@ def main(argv=None): args, additional_args = argparser.parse_known_args() - if args.debug_verbose: - additional_args += ["-DENABLE_DEBUG_LOGS=YES"] - if check_tools() != 0: return 1 - install_git_hook() + if args.debug_verbose: + additional_args += ["-DENABLE_DEBUG_LOGS=YES"] additional_args += ["-G", args.G__generator] if args.G__generator == 'Ninja': @@ -491,13 +492,26 @@ def main(argv=None): generator = '$(MAKE) -C' if args.tunnel: + additional_args += ["-DENABLE_TUNNEL=YES"] if not os.path.isdir("submodules/tunnel"): print("Tunnel enabled but not found, trying to clone it...") if check_is_installed("git", "it", True): Popen("git clone gitosis@git.linphone.org:tunnel.git submodules/tunnel".split(" ")).wait() else: return 1 - additional_args += ["-DENABLE_TUNNEL=YES"] + + if args.list_features: + tmpdir = tempfile.mkdtemp(prefix="linphone-iphone") + tmptarget = IOSarm64Target() + + option_regex = re.compile("ENABLE_(.*):(.*)=(.*)") + for line in Popen(tmptarget.cmake_command("Debug", False, True, additional_args), + cwd=tmpdir, shell=False, stdout=PIPE).stdout.readlines(): + match = option_regex.match(line) + if match is not None: + print("ENABLE_{} (is currently {})".format(match.groups()[0], match.groups()[2])) + shutil.rmtree(tmpdir) + return 0 selected_platforms = [] for platform in args.platform: @@ -528,6 +542,7 @@ def main(argv=None): if os.path.isfile('Makefile'): os.remove('Makefile') elif selected_platforms: + install_git_hook() generate_makefile(selected_platforms, generator) return 0 From 3d858f0a0cfdbc562cfe2ab0d5ec1e0a548fafe6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 24 Aug 2015 17:28:22 +0200 Subject: [PATCH 14/46] Updated linphone submodule --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 91d5a217c..e7dd35efa 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 91d5a217cbfd9951dbf0cc67f8a3114565993404 +Subproject commit e7dd35efa0f0d250db66fadb11994b4f48e088b1 From 5dfc4d2d1305734eeca982abc633c6c7a3414e75 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 25 Aug 2015 10:11:14 +0200 Subject: [PATCH 15/46] LinphoneUITester: add some call tests and fix crash when entering invalid caracters in address field --- Classes/Base.lproj/DialerViewController.xib | 2 +- .../Base.lproj/DialerViewController~ipad.xib | 2 +- Classes/LinphoneManager.h | 2 + Classes/LinphoneManager.m | 137 +++++++++--------- Classes/LinphoneUI/UIStateBar.m | 1 + Classes/PhoneMainView.m | 23 ++- Classes/WizardViewController.m | 22 +-- TestsUI/CallTester.h | 13 ++ TestsUI/CallTester.m | 62 ++++++++ TestsUI/ContactsTester.m | 4 +- TestsUI/LinphoneTestCase.m | 61 +++++--- TestsUI/WizardTester.m | 11 +- linphone.xcodeproj/project.pbxproj | 11 +- submodules/linphone | 2 +- 14 files changed, 230 insertions(+), 123 deletions(-) create mode 100644 TestsUI/CallTester.h create mode 100644 TestsUI/CallTester.m diff --git a/Classes/Base.lproj/DialerViewController.xib b/Classes/Base.lproj/DialerViewController.xib index 2d9708781..1216e2588 100644 --- a/Classes/Base.lproj/DialerViewController.xib +++ b/Classes/Base.lproj/DialerViewController.xib @@ -47,7 +47,7 @@ - + diff --git a/Classes/Base.lproj/DialerViewController~ipad.xib b/Classes/Base.lproj/DialerViewController~ipad.xib index e900e3419..23e0ed78e 100644 --- a/Classes/Base.lproj/DialerViewController~ipad.xib +++ b/Classes/Base.lproj/DialerViewController~ipad.xib @@ -77,7 +77,7 @@ - + diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 5ad82797f..9c25127dc 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -191,6 +191,8 @@ typedef struct _LinphoneManagerSounds { - (void)silentPushFailed:(NSTimer*)timer; +- (void)removeAllAccounts; + @property (readonly) BOOL isTesting; @property (readonly, strong) FastAddressBook* fastAddressBook; @property Connectivity connectivity; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index a73ce1cf3..764125f2c 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1885,6 +1885,7 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1 } - (void)call:(NSString *)address displayName:(NSString *)displayName transfer:(BOOL)transfer { + // First verify that network is available, abort otherwise. if (!linphone_core_is_network_reachable(theLinphoneCore)) { UIAlertView *error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Network Error", nil) @@ -1893,96 +1894,92 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1 @"There is no network connection available, enable WIFI or WWAN prior to place a call", nil) delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:nil]; [error show]; return; } + // Then check that no GSM calls are in progress, abort otherwise. CTCallCenter *callCenter = [[CTCallCenter alloc] init]; if ([callCenter currentCalls] != nil) { LOGE(@"GSM call in progress, cancelling outgoing SIP call request"); - UIAlertView *error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cannot make call", nil) - message:NSLocalizedString(@"Please terminate GSM call", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil]; + UIAlertView *error = + [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cannot make call", nil) + message:NSLocalizedString(@"Please terminate GSM call first.", nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) + otherButtonTitles:nil]; [error show]; return; } - LinphoneProxyConfig *proxyCfg; - // get default proxy - linphone_core_get_default_proxy(theLinphoneCore, &proxyCfg); - LinphoneCallParams *lcallParams = linphone_core_create_default_call_parameters(theLinphoneCore); - if ([self lpConfigBoolForKey:@"edge_opt_preference"]) { - bool low_bandwidth = self.network == network_2g; - if (low_bandwidth) { - LOGI(@"Low bandwidth mode"); - } - linphone_call_params_enable_low_bandwidth(lcallParams, low_bandwidth); - } - LinphoneCall *call = NULL; - - BOOL addressIsASCII = [address canBeConvertedToEncoding:[NSString defaultCStringEncoding]]; - - if ([address length] == 0) - return; // just return - if (!addressIsASCII) { - UIAlertView *error = - [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address", nil) - message:NSLocalizedString(@"The address should only contain ASCII data", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil]; + LinphoneAddress *addr = NULL; + // Continue by checking that the provided address is a valid SIP address, abort otherwise. + if ([address length] == 0) { + // no address provided... nothing to do + } else if (![address canBeConvertedToEncoding:[NSString defaultCStringEncoding]]) { + UIAlertView *error = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Invalid SIP address", nil) + message:NSLocalizedString( + @"Some invalid characters where found in the given SIP address. Please correct it.", + nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) + otherButtonTitles:nil]; [error show]; - } - LinphoneAddress *linphoneAddress = - linphone_core_interpret_url(theLinphoneCore, [address cStringUsingEncoding:[NSString defaultCStringEncoding]]); - - if (linphoneAddress) { - - if (displayName != nil) { - linphone_address_set_display_name(linphoneAddress, - [displayName cStringUsingEncoding:[NSString defaultCStringEncoding]]); - } - if ([[LinphoneManager instance] lpConfigBoolForKey:@"override_domain_with_default_one"]) - linphone_address_set_domain( - linphoneAddress, [[[LinphoneManager instance] lpConfigStringForKey:@"domain" forSection:@"wizard"] - cStringUsingEncoding:[NSString defaultCStringEncoding]]); - if (transfer) { - linphone_core_transfer_call(theLinphoneCore, linphone_core_get_current_call(theLinphoneCore), - [address cStringUsingEncoding:[NSString defaultCStringEncoding]]); - } else { - call = linphone_core_invite_address_with_params(theLinphoneCore, linphoneAddress, lcallParams); - } - linphone_address_destroy(linphoneAddress); - - } else { - + } else if ((addr = linphone_core_interpret_url( + theLinphoneCore, [address cStringUsingEncoding:[NSString defaultCStringEncoding]])) == NULL) { UIAlertView *error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address", nil) message:NSLocalizedString(@"Either configure a SIP proxy server from settings prior to place a " @"call or use a valid SIP address (I.E sip:john@example.net)", nil) delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:nil]; [error show]; - } + } else { + // Finally we can make the call + LinphoneProxyConfig *proxyCfg; + linphone_core_get_default_proxy(theLinphoneCore, &proxyCfg); + LinphoneCallParams *lcallParams = linphone_core_create_default_call_parameters(theLinphoneCore); + if ([self lpConfigBoolForKey:@"edge_opt_preference"] && (self.network == network_2g)) { + LOGI(@"Enabling low bandwidth mode"); + linphone_call_params_enable_low_bandwidth(lcallParams, YES); + } + if (displayName != nil) { + linphone_address_set_display_name(addr, + [displayName cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } + if ([[LinphoneManager instance] lpConfigBoolForKey:@"override_domain_with_default_one"]) { + linphone_address_set_domain( + addr, [[[LinphoneManager instance] lpConfigStringForKey:@"domain" forSection:@"wizard"] + cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } - if (call) { - // The LinphoneCallAppData object should be set on call creation with callback - // - (void)onCall:StateChanged:withMessage:. If not, we are in big trouble and expect it to crash - // We are NOT responsible for creating the AppData. - LinphoneCallAppData *data = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call); - if (data == nil) - LOGE(@"New call instanciated but app data was not set. Expect it to crash."); - /* will be used later to notify user if video was not activated because of the linphone core*/ - else - data->videoRequested = linphone_call_params_video_enabled(lcallParams); + if (transfer) { + char *caddr = linphone_address_as_string(addr); + linphone_core_transfer_call(theLinphoneCore, linphone_core_get_current_call(theLinphoneCore), caddr); + ms_free(caddr); + } else { + LinphoneCall *call = linphone_core_invite_address_with_params(theLinphoneCore, addr, lcallParams); + if (call) { + // The LinphoneCallAppData object should be set on call creation with callback + // - (void)onCall:StateChanged:withMessage:. If not, we are in big trouble and expect it to crash + // We are NOT responsible for creating the AppData. + LinphoneCallAppData *data = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call); + if (data == nil) { + LOGE(@"New call instanciated but app data was not set. Expect it to crash."); + /* will be used later to notify user if video was not activated because of the linphone core*/ + } else { + data->videoRequested = linphone_call_params_video_enabled(lcallParams); + } + } + } + linphone_address_destroy(addr); + linphone_call_params_destroy(lcallParams); } - linphone_call_params_destroy(lcallParams); } #pragma mark - Property Functions @@ -2331,4 +2328,10 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1 // Query our in-app server to retrieve InApp purchases [_iapManager retrievePurchases]; } + +- (void)removeAllAccounts { + linphone_core_clear_proxy_config([LinphoneManager getLc]); + linphone_core_clear_all_auth_info([LinphoneManager getLc]); +} + @end diff --git a/Classes/LinphoneUI/UIStateBar.m b/Classes/LinphoneUI/UIStateBar.m index 375dc4fd9..d7a261d0b 100644 --- a/Classes/LinphoneUI/UIStateBar.m +++ b/Classes/LinphoneUI/UIStateBar.m @@ -235,6 +235,7 @@ break; } [registrationStateLabel setText:message]; + registrationStateLabel.accessibilityValue = registrationStateImage.accessibilityValue = message; [registrationStateImage setImage:image]; } diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 389fb5907..407e5b599 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -608,21 +608,28 @@ static RootViewManager *rootViewManagerInstance = nil; @"SIP account configuration in the settings.", nil); } else { - lMessage = [NSString stringWithFormat:NSLocalizedString(@"Cannot call %@", nil), lUserName]; + lMessage = [NSString stringWithFormat:NSLocalizedString(@"Cannot call %@.", nil), lUserName]; } - if (linphone_call_get_reason(call) == LinphoneReasonNotFound) { - lMessage = [NSString stringWithFormat:NSLocalizedString(@"%@ not registered", nil), lUserName]; - } else { - if (message != nil) { - lMessage = [NSString stringWithFormat:NSLocalizedString(@"%@\nReason was: %@", nil), lMessage, message]; - } + switch (linphone_call_get_reason(call)) { + case LinphoneReasonNotFound: + lMessage = [NSString stringWithFormat:NSLocalizedString(@"%@ is not registered.", nil), lUserName]; + break; + case LinphoneReasonBusy: + lMessage = [NSString stringWithFormat:NSLocalizedString(@"%@ is busy.", nil), lUserName]; + break; + default: + if (message != nil) { + lMessage = [NSString stringWithFormat:NSLocalizedString(@"%@\nReason was: %@", nil), lMessage, message]; + } + break; } + lTitle = NSLocalizedString(@"Call failed", nil); UIAlertView *error = [[UIAlertView alloc] initWithTitle:lTitle message:lMessage delegate:nil - cancelButtonTitle:NSLocalizedString(@"Dismiss", nil) + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) otherButtonTitles:nil]; [error show]; } diff --git a/Classes/WizardViewController.m b/Classes/WizardViewController.m index d7e007e7d..7802a23da 100644 --- a/Classes/WizardViewController.m +++ b/Classes/WizardViewController.m @@ -228,7 +228,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (void)reset { - [self clearProxyConfig]; + [[LinphoneManager instance] removeAllAccounts]; [[LinphoneManager instance] lpConfigSetBool:FALSE forKey:@"pushnotification_preference"]; LinphoneCore *lc = [LinphoneManager getLc]; @@ -372,17 +372,6 @@ static UICompositeViewDescription *compositeDescription = nil; [contentView setContentSize:[view bounds].size]; } -- (void)clearProxyConfig { - linphone_core_clear_proxy_config([LinphoneManager getLc]); - linphone_core_clear_all_auth_info([LinphoneManager getLc]); -} - -- (void)setDefaultSettings:(LinphoneProxyConfig *)proxyCfg { - LinphoneManager *lm = [LinphoneManager instance]; - - [lm configurePushTokenForProxyConfig:proxyCfg]; -} - - (BOOL)addProxyConfig:(NSString *)username password:(NSString *)password domain:(NSString *)domain @@ -440,9 +429,9 @@ static UICompositeViewDescription *compositeDescription = nil; LinphoneAuthInfo *info = linphone_auth_info_new([username UTF8String], NULL, [password UTF8String], NULL, NULL, linphone_proxy_config_get_domain(proxyCfg)); - [self setDefaultSettings:proxyCfg]; - - [self clearProxyConfig]; + LinphoneManager *lm = [LinphoneManager instance]; + [lm configurePushTokenForProxyConfig:proxyCfg]; + [lm removeAllAccounts]; linphone_proxy_config_enable_register(proxyCfg, true); linphone_core_add_auth_info(lc, info); @@ -454,8 +443,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (void)addProvisionedProxy:(NSString *)username withPassword:(NSString *)password withDomain:(NSString *)domain { - [self clearProxyConfig]; - + [[LinphoneManager instance] removeAllAccounts]; LinphoneProxyConfig *proxyCfg = linphone_core_create_proxy_config([LinphoneManager getLc]); const char *addr = linphone_proxy_config_get_domain(proxyCfg); diff --git a/TestsUI/CallTester.h b/TestsUI/CallTester.h new file mode 100644 index 000000000..9f89b98e3 --- /dev/null +++ b/TestsUI/CallTester.h @@ -0,0 +1,13 @@ +// +// CallTester.h +// linphone +// +// Created by Gautier Pelloux-Prayer on 24/08/15. +// +// + +#import "LinphoneTestCase.h" + +@interface CallTester : LinphoneTestCase + +@end diff --git a/TestsUI/CallTester.m b/TestsUI/CallTester.m new file mode 100644 index 000000000..a6e2e2825 --- /dev/null +++ b/TestsUI/CallTester.m @@ -0,0 +1,62 @@ +// +// CallTester.m +// linphone +// +// Created by Gautier Pelloux-Prayer on 24/08/15. +// +// + +#import "CallTester.h" +#include "LinphoneManager.h" + +@implementation CallTester + +- (void)beforeAll { + [super beforeAll]; + [self switchToValidAccountIfNeeded]; +} + +- (void)beforeEach { + [super beforeEach]; + if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) { + [tester tapViewWithAccessibilityLabel:@"Back"]; + } + [tester tapViewWithAccessibilityLabel:@"Dialer"]; +} + +- (void)afterEach { + if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Hangup" error:nil]) { + [tester tapViewWithAccessibilityLabel:@"Hangup"]; + } + [super afterEach]; +} +#pragma mark - Tools + +- (void)callURI:(NSString *)address { + [tester enterText:address intoViewWithAccessibilityLabel:@"Enter an address"]; + [tester tapViewWithAccessibilityLabel:@"Call" traits:UIAccessibilityTraitButton]; +} + +#pragma mark - Tests + +- (void)testCallMeBusy { + [self callURI:[self me]]; + [tester waitForViewWithAccessibilityLabel:[NSString stringWithFormat:@"%@ is busy.", [self me]]]; + [tester tapViewWithAccessibilityLabel:@"Cancel" traits:UIAccessibilityTraitButton]; +} + +- (void)testCallUnregisteredUser { + NSString *unregisteredUser = [self getUUID]; + [self callURI:unregisteredUser]; + [tester waitForViewWithAccessibilityLabel:[NSString stringWithFormat:@"%@ is not registered.", unregisteredUser]]; + [tester tapViewWithAccessibilityLabel:@"Cancel" traits:UIAccessibilityTraitButton]; +} + +- (void)testDialInvalidSIPURI { + [self callURI:@"🎆123"]; + [tester waitForViewWithAccessibilityLabel: + @"Some invalid characters where found in the given SIP address. Please correct it."]; + [tester tapViewWithAccessibilityLabel:@"Cancel" traits:UIAccessibilityTraitButton]; +} + +@end diff --git a/TestsUI/ContactsTester.m b/TestsUI/ContactsTester.m index 974364600..4335236c8 100644 --- a/TestsUI/ContactsTester.m +++ b/TestsUI/ContactsTester.m @@ -75,8 +75,8 @@ NSString *phone = @"+5 15 #0664;447*46"; [self createContact:contactName lastName:@"dummy" phoneNumber:phone SIPAddress:nil]; [tester tapViewWithAccessibilityLabel:[@"Linphone, " stringByAppendingString:phone]]; - [tester waitForViewWithAccessibilityLabel:[phone stringByAppendingString:@" not registered"]]; - [tester tapViewWithAccessibilityLabel:@"Dismiss"]; + [tester waitForViewWithAccessibilityLabel:[phone stringByAppendingString:@" is not registered."]]; + [tester tapViewWithAccessibilityLabel:@"Cancel"]; } - (void)testDeleteContact { diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index 2812779c9..647e35024 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -23,7 +23,11 @@ if (!([language isEqualToString:@"en"] || [language containsString:@"en-"])) { LOGF(@"Language must be 'en' (English) instead of %@", language); } +#if DEBUG + linphone_core_set_log_level(ORTP_MESSAGE); +#else linphone_core_set_log_level(ORTP_WARNING); +#endif } - (void)beforeAll { @@ -34,7 +38,7 @@ }; #endif // go to dialer - for (NSString *button in @[ @"Cancel", @"Back", @"Dialer" ]) { + for (NSString *button in @[ @"Cancel", @"Back", @"Hangup", @"Dialer" ]) { if ([tester tryFindingTappableViewWithAccessibilityLabel:button error:nil]) { [tester tapViewWithAccessibilityLabel:button traits:UIAccessibilityTraitButton]; } @@ -42,11 +46,12 @@ } - (NSString *)me { - return @"testios"; + return [NSString + stringWithFormat:@"testios-%@", [[UIDevice currentDevice].identifierForVendor.UUIDString substringToIndex:6]]; } - (NSString *)accountDomain { - return @"sip.linphone.org"; + return @"test.linphone.org"; } - (NSString *)getUUID { @@ -101,26 +106,48 @@ static bool invalidAccount = true; [UIView setAnimationsEnabled:false]; if (invalidAccount && ![self hasValidProxyConfig]) { + LOGI(@"Switching to a test account..."); - [tester tapViewWithAccessibilityLabel:@"Settings"]; - [tester tapViewWithAccessibilityLabel:@"Run assistant"]; - [tester waitForTimeInterval:0.5]; - if ([tester tryFindingViewWithAccessibilityLabel:@"Launch Wizard" error:nil]) { - [tester tapViewWithAccessibilityLabel:@"Launch Wizard"]; - [tester waitForTimeInterval:0.5]; - } + LinphoneCore *lc = [LinphoneManager getLc]; + linphone_core_clear_proxy_config(lc); + linphone_core_clear_all_auth_info(lc); - LOGI(@"Switching to a valid account"); + LinphoneAddress *testAddr = linphone_address_new( + [[NSString stringWithFormat:@"sip:%@@%@", [self me], [self accountDomain]] UTF8String]); + linphone_address_set_header(testAddr, "X-Create-Account", "yes"); + linphone_address_set_transport(testAddr, LinphoneTransportTcp); + linphone_address_set_port(testAddr, 0); - [tester tapViewWithAccessibilityLabel:@"Start"]; - [tester tapViewWithAccessibilityLabel:@"Sign in linphone.org account"]; + LinphoneProxyConfig *testProxy = linphone_proxy_config_new(); + linphone_proxy_config_set_identity_address(testProxy, testAddr); + char *server_addr = ms_strdup_printf("%s;transport=tcp", linphone_address_get_domain(testAddr)); + linphone_proxy_config_set_server_addr(testProxy, server_addr); + linphone_proxy_config_set_route(testProxy, server_addr); + ms_free(server_addr); - [tester enterText:[self me] intoViewWithAccessibilityLabel:@"Username"]; - [tester enterText:@"testtest" intoViewWithAccessibilityLabel:@"Password"]; + LinphoneAuthInfo *testAuth = linphone_auth_info_new(linphone_address_get_username(testAddr), NULL, + linphone_address_get_password(testAddr), NULL, NULL, + linphone_address_get_domain(testAddr)); - [tester tapViewWithAccessibilityLabel:@"Sign in"]; + [[LinphoneManager instance] configurePushTokenForProxyConfig:testProxy]; + [[LinphoneManager instance] removeAllAccounts]; + + linphone_proxy_config_enable_register(testProxy, true); + linphone_core_add_auth_info(lc, testAuth); + linphone_core_add_proxy_config(lc, testProxy); + linphone_core_set_default_proxy_config(lc, testProxy); + + linphone_proxy_config_unref(testProxy); + linphone_auth_info_destroy(testAuth); + linphone_address_destroy(testAddr); + + // reload address book to prepend proxy config domain to contacts' phone number + [[[LinphoneManager instance] fastAddressBook] reload]; + + [tester waitForViewWithAccessibilityLabel:@"Registration state" + value:@"Registered" + traits:UIAccessibilityTraitStaticText]; - [tester waitForViewWithAccessibilityLabel:@"Dialer"]; invalidAccount = false; } } diff --git a/TestsUI/WizardTester.m b/TestsUI/WizardTester.m index 03fe024a2..313564fa7 100644 --- a/TestsUI/WizardTester.m +++ b/TestsUI/WizardTester.m @@ -100,17 +100,16 @@ } - (void)testLinphoneLogin { - - [self _linphoneLogin:[self me] withPW:@"testtest"]; + [self _linphoneLogin:@"testios" withPW:@"testtest"]; // check the registration state - UIView *regState = [tester waitForViewWithAccessibilityLabel:@"Registration state"]; - [tester waitForTimeInterval:1]; - [tester expectView:regState toContainText:@"Registered"]; + [tester waitForViewWithAccessibilityLabel:@"Registration state" + value:@"Registered" + traits:UIAccessibilityTraitStaticText]; } - (void)testLinphoneLoginWithBadPassword { - [self _linphoneLogin:[self me] withPW:@"badPass"]; + [self _linphoneLogin:@"testios" withPW:@"badPass"]; [self setInvalidAccountSet:true]; diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 938ab0151..4ff6d14af 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -167,6 +167,7 @@ 63B81A0E1B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A071B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m */; }; 63B81A0F1B57DA33009604A6 /* TPKeyboardAvoidingTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A091B57DA33009604A6 /* TPKeyboardAvoidingTableView.m */; }; 63B81A101B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A0B1B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m */; }; + 63B910C21B8B5368004641C9 /* CallTester.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B910BA1B8B5356004641C9 /* CallTester.m */; }; 63C458261B5680AC009F2D7E /* ring.wav in Resources */ = {isa = PBXBuildFile; fileRef = 2237D4081084D7A9001383EE /* ring.wav */; }; 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; 63D2680F1B174A5E00A2CC11 /* numpad_one_voicemail_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */; }; @@ -1108,6 +1109,8 @@ 63B81A091B57DA33009604A6 /* TPKeyboardAvoidingTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPKeyboardAvoidingTableView.m; sourceTree = ""; }; 63B81A0A1B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+TPKeyboardAvoidingAdditions.h"; sourceTree = ""; }; 63B81A0B1B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+TPKeyboardAvoidingAdditions.m"; sourceTree = ""; }; + 63B910B91B8B5356004641C9 /* CallTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallTester.h; sourceTree = ""; }; + 63B910BA1B8B5356004641C9 /* CallTester.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallTester.m; sourceTree = ""; }; 63CD4B4D1A5AAC8C00B84282 /* DTAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTAlertView.h; sourceTree = ""; }; 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTAlertView.m; sourceTree = ""; }; 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = numpad_one_voicemail_default.png; path = Resources/numpad_one_voicemail_default.png; sourceTree = ""; }; @@ -2297,7 +2300,6 @@ F03A9B9718C0DB6F00C4D7FE /* libc++.dylib */, F0BB8C111936240300974404 /* libcunit.a */, 220FAD2910765B400068D98F /* libgsm.a */, - 223148E31178A08200637D6A /* libilbc.a */, 2211DB911475562600DEE054 /* liblinphone.a */, F0BB8C0F193623F200974404 /* liblinphonetester.a */, 22405EE916006F0700B92522 /* libmediastreamer_base.a */, @@ -2345,12 +2347,14 @@ 630589DD1B4E810900EFAE36 /* TestsUI */ = { isa = PBXGroup; children = ( - 63058A0A1B4E81B700EFAE36 /* Info.plist */, - 630589F21B4E816900EFAE36 /* KIF.xcodeproj */, + 63B910B91B8B5356004641C9 /* CallTester.h */, + 63B910BA1B8B5356004641C9 /* CallTester.m */, 630589DE1B4E810900EFAE36 /* ChatTester.h */, 630589DF1B4E810900EFAE36 /* ChatTester.m */, 630589E01B4E810900EFAE36 /* ContactsTester.h */, 630589E11B4E810900EFAE36 /* ContactsTester.m */, + 63058A0A1B4E81B700EFAE36 /* Info.plist */, + 630589F21B4E816900EFAE36 /* KIF.xcodeproj */, 630589E31B4E810900EFAE36 /* LinphoneTestCase.h */, 630589E41B4E810900EFAE36 /* LinphoneTestCase.m */, 630589E51B4E810900EFAE36 /* WizardTester.h */, @@ -4118,6 +4122,7 @@ 630589EA1B4E810900EFAE36 /* LinphoneTestCase.m in Sources */, 630589EB1B4E810900EFAE36 /* WizardTester.m in Sources */, 630589E71B4E810900EFAE36 /* ChatTester.m in Sources */, + 63B910C21B8B5368004641C9 /* CallTester.m in Sources */, 630589E81B4E810900EFAE36 /* ContactsTester.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/submodules/linphone b/submodules/linphone index e7dd35efa..af43ad896 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit e7dd35efa0f0d250db66fadb11994b4f48e088b1 +Subproject commit af43ad89650f70ce5e2fb4a45287aabbdd9b63d6 From ece470a704774b1b8d5a731db404074caadcda02 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 25 Aug 2015 15:57:18 +0200 Subject: [PATCH 16/46] prepare.py: automatically enable tunnel if directory is present and use logging module --- prepare.py | 97 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/prepare.py b/prepare.py index dac333e16..6d8752bf3 100755 --- a/prepare.py +++ b/prepare.py @@ -28,6 +28,7 @@ import re import shutil import tempfile import sys +from logging import * from distutils.spawn import find_executable from subprocess import Popen, PIPE sys.dont_write_bytecode = True @@ -35,7 +36,8 @@ sys.path.insert(0, 'submodules/cmake-builder') try: import prepare except: - print("Could not find prepare module, probably missing submodules/cmake-builder? Try running git submodule update --init --recursive") + error( + "Could not find prepare module, probably missing submodules/cmake-builder? Try running git submodule update --init --recursive") exit(1) @@ -108,36 +110,29 @@ class PlatformListAction(argparse.Action): setattr(namespace, self.dest, values) -def warning(platforms): - gpl_third_parties_enabled = False - regex = re.compile("^ENABLE_GPL_THIRD_PARTIES:BOOL=ON") - f = open( - 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]), 'r') - for line in f: - if regex.match(line): - gpl_third_parties_enabled = True - break - f.close() +def gpl_disclaimer(platforms): + cmakecache = 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]) + gpl_third_parties_enabled = ("ENABLE_GPL_THIRD_PARTIES:BOOL=ON" in open(cmakecache).read()) if gpl_third_parties_enabled: - print("***************************************************************************\n" - "***************************************************************************\n" - "***** CAUTION, this liblinphone SDK is built using 3rd party GPL code *****\n" - "***** Even if you acquired a proprietary license from Belledonne *****\n" - "***** Communications, this SDK is GPL and GPL only. *****\n" - "***** To disable 3rd party gpl code, please use: *****\n" - "***** $ ./prepare.py -DENABLE_GPL_THIRD_PARTIES=NO *****\n" - "***************************************************************************\n" - "***************************************************************************\n") + warning("***************************************************************************\n" + "***************************************************************************\n" + "***** CAUTION, this liblinphone SDK is built using 3rd party GPL code *****\n" + "***** Even if you acquired a proprietary license from Belledonne *****\n" + "***** Communications, this SDK is GPL and GPL only. *****\n" + "***** To disable 3rd party gpl code, please use: *****\n" + "***** $ ./prepare.py -DENABLE_GPL_THIRD_PARTIES=NO *****\n" + "***************************************************************************\n" + "***************************************************************************\n") else: - print("*****************************************************************\n" - "*****************************************************************\n" - "***** Linphone SDK without 3rd party GPL software *****\n" - "***** If you acquired a proprietary license from Belledonne *****\n" - "***** Communications, this SDK can be used to create *****\n" - "***** a proprietary linphone-based application. *****\n" - "*****************************************************************\n" - "*****************************************************************\n") + warning("*****************************************************************\n" + "*****************************************************************\n" + "***** Linphone SDK without 3rd party GPL software *****\n" + "***** If you acquired a proprietary license from Belledonne *****\n" + "***** Communications, this SDK can be used to create *****\n" + "***** a proprietary linphone-based application. *****\n" + "*****************************************************************\n" + "*****************************************************************\n") def extract_libs_list(): @@ -157,7 +152,7 @@ def extract_libs_list(): def check_is_installed(binary, prog=None, warn=True): if not find_executable(binary): if warn: - print("Could not find {}. Please install {}.".format(binary, prog)) + error("Could not find {}. Please install {}.".format(binary, prog)) return False return True @@ -166,7 +161,7 @@ def check_tools(): reterr = 0 if " " in os.path.dirname(os.path.realpath(__file__)): - print("Invalid location: linphone-iphone path should not contain any spaces.") + error("Invalid location: linphone-iphone path should not contain any spaces.") reterr = 1 for prog in ["autoconf", "automake", "pkg-config", "doxygen", "java", "nasm", "cmake", "wget", "yasm", "optipng"]: @@ -180,15 +175,14 @@ def check_tools(): glibtoolize_path = find_executable(glibtoolize) reterr = 1 error = "Please do a symbolic link from glibtoolize to libtoolize: 'ln -s {} ${}'." - print(error.format(glibtoolize_path, glibtoolize_path.replace("glibtoolize", "libtoolize"))) + error(error.format(glibtoolize_path, glibtoolize_path.replace("glibtoolize", "libtoolize"))) devnull = open(os.devnull, 'wb') # just ensure that JDK is installed - if not, it will automatiaclyl display a popup to user p = Popen("java -version".split(" "), stderr=devnull, stdout=devnull) p.wait() if p.returncode != 0: - print(p.returncode) - print("Please install Java JDK (not just JRE).") + error("Please install Java JDK (not just JRE).") reterr = 1 # needed by x264 @@ -199,28 +193,29 @@ def check_tools(): nasm_output = Popen("nasm -f elf32".split(" "), stderr=PIPE, stdout=PIPE).stderr.read() if "fatal: unrecognised output format" in nasm_output: - print( + error( "Invalid version of nasm: your version does not support elf32 output format. If you have installed nasm, please check that your PATH env variable is set correctly.") reterr = 1 if not os.path.isdir("submodules/linphone/mediastreamer2") or not os.path.isdir("submodules/linphone/oRTP"): - print("Missing some git submodules. Did you run 'git submodule update --init --recursive'?") + error("Missing some git submodules. Did you run 'git submodule update --init --recursive'?") reterr = 1 p = Popen("xcrun --sdk iphoneos --show-sdk-path".split(" "), stdout=devnull, stderr=devnull) p.wait() if p.returncode != 0: - print("iOS SDK not found, please install Xcode from AppStore or equivalent.") + error("iOS SDK not found, please install Xcode from AppStore or equivalent.") reterr = 1 else: - sdk_platform_path = Popen("xcrun --sdk iphonesimulator --show-sdk-platform-path".split(" "), stdout=PIPE, stderr=devnull).stdout.read()[:-1] + sdk_platform_path = Popen( + "xcrun --sdk iphonesimulator --show-sdk-platform-path".split(" "), stdout=PIPE, stderr=devnull).stdout.read()[:-1] sdk_strings_path = "{}/{}".format(sdk_platform_path, "Developer/usr/bin/strings") if not os.path.isfile(sdk_strings_path): strings_path = find_executable("strings") - print("strings binary missing, please run 'sudo ln -s {} {}'.".format(strings_path, sdk_strings_path)) + error("strings binary missing, please run 'sudo ln -s {} {}'.".format(strings_path, sdk_strings_path)) reterr = 1 if reterr == 1: - print("Failed to detect required tools, aborting.") + error("Failed to detect required tools, aborting.") return reterr @@ -228,7 +223,7 @@ def check_tools(): def install_git_hook(): git_hook_path = ".git{sep}hooks{sep}pre-commit".format(sep=os.sep) if os.path.isdir(".git{sep}hooks".format(sep=os.sep)) and not os.path.isfile(git_hook_path): - print("Installing Git pre-commit hook") + info("Installing Git pre-commit hook") shutil.copyfile(".git-pre-commit", git_hook_path) os.chmod(git_hook_path, 0755) @@ -302,7 +297,7 @@ def generate_makefile(platforms, generator): multiarch = "" for arch in platforms[1:]: multiarch += \ -"""\tif test -f "$${arch}_path"; then \\ + """\tif test -f "$${arch}_path"; then \\ \t\tall_paths=`echo $$all_paths $${arch}_path`; \\ \t\tall_archs="$$all_archs,{arch}" ; \\ \telse \\ @@ -448,10 +443,12 @@ help: help-prepare-options f = open('Makefile', 'w') f.write(makefile) f.close() - warning(platforms) + gpl_disclaimer(platforms) def main(argv=None): + basicConfig(format="%(levelname)s: %(message)s", level=INFO) + if argv is None: argv = sys.argv argparser = argparse.ArgumentParser( @@ -481,7 +478,7 @@ def main(argv=None): return 1 if args.debug_verbose: - additional_args += ["-DENABLE_DEBUG_LOGS=YES"] + additional_args += ["-DENABLE_DEBUG_LOGS=ON"] additional_args += ["-G", args.G__generator] if args.G__generator == 'Ninja': @@ -491,25 +488,31 @@ def main(argv=None): else: generator = '$(MAKE) -C' - if args.tunnel: - additional_args += ["-DENABLE_TUNNEL=YES"] + if args.tunnel or os.path.isdir("submodules/tunnel"): if not os.path.isdir("submodules/tunnel"): - print("Tunnel enabled but not found, trying to clone it...") + info("Tunnel wanted but not found yet, trying to clone it...") if check_is_installed("git", "it", True): Popen("git clone gitosis@git.linphone.org:tunnel.git submodules/tunnel".split(" ")).wait() else: + error("Could not clone tunnel. Please see http://www.belledonne-communications.com/voiptunnel.html") return 1 + warning("Tunnel enabled, disabling GPL third parties.") + additional_args += ["-DENABLE_TUNNEL=ON", "-DENABLE_GPL_THIRD_PARTIES=OFF"] if args.list_features: tmpdir = tempfile.mkdtemp(prefix="linphone-iphone") tmptarget = IOSarm64Target() option_regex = re.compile("ENABLE_(.*):(.*)=(.*)") + option_list = [ "" ] for line in Popen(tmptarget.cmake_command("Debug", False, True, additional_args), cwd=tmpdir, shell=False, stdout=PIPE).stdout.readlines(): match = option_regex.match(line) if match is not None: - print("ENABLE_{} (is currently {})".format(match.groups()[0], match.groups()[2])) + option_list.append("ENABLE_{} (is currently {})".format(match.groups()[0], match.groups()[2])) + info("Here is the list of available features: {}".format("\n\t".join(option_list))) + info("To enable some feature, please use -DENABLE_SOMEOPTION=ON") + info("Similarly, to disable some feature, please use -DENABLE_SOMEOPTION=OFF") shutil.rmtree(tmpdir) return 0 From f8f739711381c4fdd75a3f92383fe63665710a26 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 25 Aug 2015 17:20:53 +0200 Subject: [PATCH 17/46] CallTester.m: use something more standard as Emoji, so that KIF manages to enter the text on travis --- TestsUI/CallTester.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestsUI/CallTester.m b/TestsUI/CallTester.m index a6e2e2825..b51398e24 100644 --- a/TestsUI/CallTester.m +++ b/TestsUI/CallTester.m @@ -53,7 +53,7 @@ } - (void)testDialInvalidSIPURI { - [self callURI:@"🎆123"]; + [self callURI:@"123 😀"]; [tester waitForViewWithAccessibilityLabel: @"Some invalid characters where found in the given SIP address. Please correct it."]; [tester tapViewWithAccessibilityLabel:@"Cancel" traits:UIAccessibilityTraitButton]; From d1d85f0554e3cbcc7cbde72ccbfab354a2403907 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 25 Aug 2015 10:10:32 +0200 Subject: [PATCH 18/46] README: add getting started instructions --- README.md | 42 +++++++++++++------- prepare.py | 112 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 100 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 93ecf6360..d0827d0c8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,22 @@ [![Build Status](https://travis-ci.org/BelledonneCommunications/linphone-iphone.svg?branch=master)](https://travis-ci.org/BelledonneCommunications/linphone-iphone) +Linphone is a free VoIP and video softphone based on the SIP protocol. + +![Dialer screenshot](http://www.linphone.org/img/slideshow-phone.png) + +# Getting started + +Here's how to launch Linphone for iPhone (more details below): + +1. Install [Xcode from AppStore](https://itunes.apple.com/us/app/Xcode/id497799835?mt=12#). +2. Install [HomeBrew, a package manager for OS X](http://brew.sh) (MacPorts is supported but deprecated). +3. Install Linphone dependencies: open iTerm.app in the current directory and list dependencies to install using: + `./prepare.py` +4. Build SDK (see below for options and explanations): + `./prepare.py -c && ./prepare.py && make` +5. Open linphone.xcodeproj in Xcode: `open linphone.xcodeproj` +6. Press `⌘R` and voilà! + # Building the SDK Linphone for iPhone depends on liblinphone SDK. This SDK is generated from makefiles and shell scripts. @@ -12,19 +29,18 @@ Linphone for iPhone depends on liblinphone SDK. This SDK is generated from makef ## Licensing: GPL third parties versus non GPL third parties -This SDK can be generated in 2 flavors. +This SDK can be generated in 2 flavors: -* When choosing using GPL third parties, it means liblinphone includes GPL third parties like FFmpeg or X264. If you choose this flavor, your final application must comply with GPL in any case. This is the default mode. +* GPL third parties enabled means that liblinphone includes GPL third parties like FFmpeg or X264. If you choose this flavor, your final application **must comply with GPL in any case**. This is the default mode. -* When choosing NOT using GPL third parties, Linphone will only use non GPL code except for `liblinphone`, `mediastreamer2`, `oRTP` and `belle-sip`. - If you choose this flavor, your final application is still subject to GPL except if you have a commercial license for liblinphone, mediastreamer2, oRTP, belle-sip. - To generate the liblinphone multi arch SDK in non GPL mode, do: +* NO GPL third parties means that Linphone will only use non GPL code except for `liblinphone`, `mediastreamer2`, `oRTP` and `belle-sip`. If you choose this flavor, your final application is **still subject to GPL except if you have a [commercial license for the mentioned libraries](http://www.belledonne-communications.com/products.html)**. + To generate the liblinphone multi arch SDK without GPL third parties, invoke: - ./prepare.py -DENABLE_GPL_THIRD_PARTIES=NO [other options] && make + ./prepare.py -DENABLE_GPL_THIRD_PARTIES=OFF [other options] && make ## Customizing features -You can choose to enable / disable features such as custom audio / video codecs, media encryption, etc. To get a list of all features, the simplest way is to invoke `prepare.py` with `--list-features`: +You can choose to enable/disable features such as custom audio/video codecs, media encryption, etc. To get a list of all features, the simplest way is to invoke `prepare.py` with `--list-features`: ./prepare.py --list-features @@ -41,7 +57,7 @@ You can for instance enable X264 by using: - 64 bits x86_64 for simulator for all ARM64 devices. - 32 bits i386 for simulator for all ARMv7 older devices. - Note: We are not compiling for the 32 bits i386 simulator by default because xCode default device (iPhone 6) runs in 64 bits. If you want to enable it, you should invoke `prepare.py` with `i386` argument: `./prepare.py i386 [other options]`. + Note: We are not compiling for the 32 bits i386 simulator by default because Xcode default device (iPhone 6) runs in 64 bits. If you want to enable it, you should invoke `prepare.py` with `i386` argument: `./prepare.py i386 [other options]`. ## Upgrading your iOS SDK @@ -55,24 +71,24 @@ After the SDK is built, just open the Linphone Xcode project with Xcode, and pre ## Note regarding third party components subject to license - The liblinphone-sdk is compiled with third parties code that are subject to patent license, specially: AMR, SILK G729 and H264 codecs. + The liblinphone SDK is compiled with third parties code that are subject to patent license, specially: AMR, SILK G729 and H264 codecs. Linphone controls the embedding of these codecs thanks to the preprocessor macros HAVE_SILK, HAVE_AMR, HAVE_G729 HAVE_OPENH264 positioned in Xcode project. - Before embedding these 4 codecs in the final application, make sure to have the right to do so. + Before embedding these 4 codecs in the final application, **make sure to have the right to do so**. # Testing the application We are using the KIF framework to test the UI of Linphone. It is used as a submodule (instead of CocoaPods) for ease. -Simply press `Command + U` and the default simulator / device will launch and try to pass all the tests. +Simply press `⌘U` and the default simulator / device will launch and try to pass all the tests. # Limitations and known bugs -* Video capture will not work in simulator (not implemented in simulator). +* Video capture will not work in simulator (not implemented in it). # Debugging the SDK -Sometime it can be useful to step into liblinphone SDK functions. To allow XCode to enable breakpoint within liblinphone, SDK must be built with debug symbols by using option `--debug`: +Sometime it can be useful to step into liblinphone SDK functions. To allow Xcode to enable breakpoint within liblinphone, SDK must be built with debug symbols by using option `--debug`: ./prepare.py --debug [other options] && make diff --git a/prepare.py b/prepare.py index 6d8752bf3..3d1919f43 100755 --- a/prepare.py +++ b/prepare.py @@ -37,7 +37,7 @@ try: import prepare except: error( - "Could not find prepare module, probably missing submodules/cmake-builder? Try running git submodule update --init --recursive") + "Could not find prepare module, probably missing submodules/cmake-builder? Try running:\ngit submodule update --init --recursive") exit(1) @@ -115,24 +115,24 @@ def gpl_disclaimer(platforms): gpl_third_parties_enabled = ("ENABLE_GPL_THIRD_PARTIES:BOOL=ON" in open(cmakecache).read()) if gpl_third_parties_enabled: - warning("***************************************************************************\n" - "***************************************************************************\n" - "***** CAUTION, this liblinphone SDK is built using 3rd party GPL code *****\n" - "***** Even if you acquired a proprietary license from Belledonne *****\n" - "***** Communications, this SDK is GPL and GPL only. *****\n" - "***** To disable 3rd party gpl code, please use: *****\n" - "***** $ ./prepare.py -DENABLE_GPL_THIRD_PARTIES=NO *****\n" - "***************************************************************************\n" - "***************************************************************************\n") + warning("\n***************************************************************************" + "\n***************************************************************************" + "\n***** CAUTION, this liblinphone SDK is built using 3rd party GPL code *****" + "\n***** Even if you acquired a proprietary license from Belledonne *****" + "\n***** Communications, this SDK is GPL and GPL only. *****" + "\n***** To disable 3rd party gpl code, please use: *****" + "\n***** $ ./prepare.py -DENABLE_GPL_THIRD_PARTIES=NO *****" + "\n***************************************************************************" + "\n***************************************************************************") else: - warning("*****************************************************************\n" - "*****************************************************************\n" - "***** Linphone SDK without 3rd party GPL software *****\n" - "***** If you acquired a proprietary license from Belledonne *****\n" - "***** Communications, this SDK can be used to create *****\n" - "***** a proprietary linphone-based application. *****\n" - "*****************************************************************\n" - "*****************************************************************\n") + warning("\n***************************************************************************" + "\n***************************************************************************" + "\n***** Linphone SDK without 3rd party GPL software *****" + "\n***** If you acquired a proprietary license from Belledonne *****" + "\n***** Communications, this SDK can be used to create *****" + "\n***** a proprietary linphone-based application. *****" + "\n***************************************************************************" + "\n***************************************************************************") def extract_libs_list(): @@ -149,36 +149,72 @@ def extract_libs_list(): return list(set(l)) +missing_dependencies = {} + + def check_is_installed(binary, prog=None, warn=True): if not find_executable(binary): + if warn: - error("Could not find {}. Please install {}.".format(binary, prog)) + missing_dependencies[binary] = prog + # error("Could not find {}. Please install {}.".format(binary, prog)) return False return True +def detect_package_manager(): + if find_executable("brew"): + return "brew" + elif find_executable("port"): + return "sudo port" + else: + error( + "No package manager found. Please README or install brew using:\n\truby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"") + return "brew" + + def check_tools(): + package_manager_info = {"brew-pkg-config": "pkg-config", + "sudo port-pkg-config": "pkgconfig", + "brew-binary-path": "/usr/local/bin/", + "sudo port-binary-path": "/opt/local/bin/" + } reterr = 0 if " " in os.path.dirname(os.path.realpath(__file__)): error("Invalid location: linphone-iphone path should not contain any spaces.") reterr = 1 - for prog in ["autoconf", "automake", "pkg-config", "doxygen", "java", "nasm", "cmake", "wget", "yasm", "optipng"]: - reterr |= not check_is_installed(prog, "it") + for prog in ["autoconf", "automake", "doxygen", "java", "nasm", "cmake", "wget", "yasm", "optipng"]: + reterr |= not check_is_installed(prog, prog) + + reterr |= not check_is_installed("pkg-config", package_manager_info[detect_package_manager() + "-pkg-config"]) reterr |= not check_is_installed("ginstall", "coreutils") reterr |= not check_is_installed("intltoolize", "intltool") reterr |= not check_is_installed("convert", "imagemagick") + if find_executable("nasm"): + nasm_output = Popen("nasm -f elf32".split(" "), stderr=PIPE, stdout=PIPE).stderr.read() + if "fatal: unrecognised output format" in nasm_output: + missing_dependencies["nasm"] = "nasm" + reterr = 1 + if check_is_installed("libtoolize", warn=False): if not check_is_installed("glibtoolize", "libtool"): glibtoolize_path = find_executable(glibtoolize) reterr = 1 - error = "Please do a symbolic link from glibtoolize to libtoolize: 'ln -s {} ${}'." - error(error.format(glibtoolize_path, glibtoolize_path.replace("glibtoolize", "libtoolize"))) + msg = "Please do a symbolic link from glibtoolize to libtoolize:\n\tln -s {} ${}" + error(msg.format(glibtoolize_path, glibtoolize_path.replace("glibtoolize", "libtoolize"))) + + # list all missing packages to install + if missing_dependencies: + error("The following binaries are missing: {}. Please install them using:\n\t{} install {}".format( + " ".join(missing_dependencies.keys()), + detect_package_manager(), + " ".join(missing_dependencies.values()))) devnull = open(os.devnull, 'wb') - # just ensure that JDK is installed - if not, it will automatiaclyl display a popup to user + # just ensure that JDK is installed - if not, it will automatically display a popup to user p = Popen("java -version".split(" "), stderr=devnull, stdout=devnull) p.wait() if p.returncode != 0: @@ -186,20 +222,17 @@ def check_tools(): reterr = 1 # needed by x264 - check_is_installed("gas-preprocessor.pl", """it: - wget --no-check-certificate https://raw.github.com/yuvi/gas-preprocessor/master/gas-preprocessor.pl - chmod +x gas-preprocessor.pl - sudo mv gas-preprocessor.pl /usr/local/bin/""") - - nasm_output = Popen("nasm -f elf32".split(" "), stderr=PIPE, stdout=PIPE).stderr.read() - if "fatal: unrecognised output format" in nasm_output: - error( - "Invalid version of nasm: your version does not support elf32 output format. If you have installed nasm, please check that your PATH env variable is set correctly.") + if not find_executable("gas-preprocessor.pl"): + error("""Could not find gas-preprocessor.pl, please install it: + wget --no-check-certificate https://raw.github.com/yuvi/gas-preprocessor/master/gas-preprocessor.pl && \\ + chmod +x gas-preprocessor.pl && \\ + sudo mv gas-preprocessor.pl {}""".format(package_manager_info[detect_package_manager() + "-binary-path"])) + reterr = 1 + + if not os.path.isdir("submodules/linphone/mediastreamer2") or not os.path.isdir("submodules/linphone/oRTP"): + error("Missing some git submodules. Did you run:\n\tgit submodule update --init --recursive") reterr = 1 - if not os.path.isdir("submodules/linphone/mediastreamer2") or not os.path.isdir("submodules/linphone/oRTP"): - error("Missing some git submodules. Did you run 'git submodule update --init --recursive'?") - reterr = 1 p = Popen("xcrun --sdk iphoneos --show-sdk-path".split(" "), stdout=devnull, stderr=devnull) p.wait() if p.returncode != 0: @@ -211,12 +244,9 @@ def check_tools(): sdk_strings_path = "{}/{}".format(sdk_platform_path, "Developer/usr/bin/strings") if not os.path.isfile(sdk_strings_path): strings_path = find_executable("strings") - error("strings binary missing, please run 'sudo ln -s {} {}'.".format(strings_path, sdk_strings_path)) + error("strings binary missing, please run:\n\tsudo ln -s {} {}".format(strings_path, sdk_strings_path)) reterr = 1 - if reterr == 1: - error("Failed to detect required tools, aborting.") - return reterr @@ -504,7 +534,7 @@ def main(argv=None): tmptarget = IOSarm64Target() option_regex = re.compile("ENABLE_(.*):(.*)=(.*)") - option_list = [ "" ] + option_list = [""] for line in Popen(tmptarget.cmake_command("Debug", False, True, additional_args), cwd=tmpdir, shell=False, stdout=PIPE).stdout.readlines(): match = option_regex.match(line) From 6fca1c71cb48334c783d478e482b4eb1576d5775 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 26 Aug 2015 15:18:02 +0200 Subject: [PATCH 19/46] xcodeproj: force linphone UI tester to link with linphone/belle-sip/ortp/ms2 static libraries to avoid missing symbols on link --- linphone.xcodeproj/project.pbxproj | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 4ff6d14af..e65620b81 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -169,6 +169,12 @@ 63B81A101B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A0B1B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m */; }; 63B910C21B8B5368004641C9 /* CallTester.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B910BA1B8B5356004641C9 /* CallTester.m */; }; 63C458261B5680AC009F2D7E /* ring.wav in Resources */ = {isa = PBXBuildFile; fileRef = 2237D4081084D7A9001383EE /* ring.wav */; }; + 63C510751B8DF3BB008A415A /* liblinphone.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2211DB911475562600DEE054 /* liblinphone.a */; }; + 63C5107C1B8DF3DF008A415A /* libbellesip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 223CA7E516D9255800EF1BEC /* libbellesip.a */; }; + 63C5107D1B8DF3DF008A415A /* liblinphonetester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F0BB8C0F193623F200974404 /* liblinphonetester.a */; }; + 63C5107E1B8DF3DF008A415A /* libmediastreamer_base.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EE916006F0700B92522 /* libmediastreamer_base.a */; }; + 63C5107F1B8DF3DF008A415A /* libmediastreamer_voip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EEA16006F0700B92522 /* libmediastreamer_voip.a */; }; + 63C510801B8DF3DF008A415A /* libortp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 220FAD2C10765B400068D98F /* libortp.a */; }; 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; 63D2680F1B174A5E00A2CC11 /* numpad_one_voicemail_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */; }; 63D268101B174A5E00A2CC11 /* numpad_one_voicemail_over.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680E1B174A5E00A2CC11 /* numpad_one_voicemail_over.png */; }; @@ -2005,6 +2011,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63C5107C1B8DF3DF008A415A /* libbellesip.a in Frameworks */, + 63C5107D1B8DF3DF008A415A /* liblinphonetester.a in Frameworks */, + 63C5107E1B8DF3DF008A415A /* libmediastreamer_base.a in Frameworks */, + 63C5107F1B8DF3DF008A415A /* libmediastreamer_voip.a in Frameworks */, + 63C510801B8DF3DF008A415A /* libortp.a in Frameworks */, + 63C510751B8DF3BB008A415A /* liblinphone.a in Frameworks */, 63058A4F1B4E835200EFAE36 /* libKIF.a in Frameworks */, F0FF66AC1ACAEF4F008A4486 /* IOKit.framework in Frameworks */, ); @@ -5385,6 +5397,10 @@ ); INFOPLIST_FILE = TestsUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", + ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( @@ -5430,6 +5446,10 @@ ); INFOPLIST_FILE = TestsUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", + ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "$(inherited)", @@ -5475,6 +5495,10 @@ ); INFOPLIST_FILE = TestsUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", + ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "$(inherited)", @@ -5520,6 +5544,10 @@ ); INFOPLIST_FILE = TestsUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", + ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "$(inherited)", From 9c2a949f0883bdeec795521fb3634806fa4b013d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 26 Aug 2015 15:44:45 +0200 Subject: [PATCH 20/46] remote push notif: fix badge count display which was broken when used NewsStand as a test purpose.. --- Classes/LinphoneAppDelegate.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index fe20e12c3..947f6c4fc 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -179,9 +179,8 @@ } } else { if (!instance.isTesting) { - NSUInteger notifTypes = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | - UIRemoteNotificationTypeBadge | - UIRemoteNotificationTypeNewsstandContentAvailability; + NSUInteger notifTypes = + UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge; [app registerForRemoteNotificationTypes:notifTypes]; } } From 71e386f412c42f37a0f3c7a33a415610cc142e7f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 27 Aug 2015 12:16:12 +0200 Subject: [PATCH 21/46] prepare.py: add option --enable-non-free-codecs and --enable-gpl-third-parties, remove HAVE_* options from Xcode project since there are now automatically stubbed by the SDK --- Classes/LinphoneManager.m | 24 ++------ Classes/LinphoneUI/UIVideoButton.m | 15 +++-- Classes/SettingsViewController.m | 93 +++++++++++++++--------------- README.md | 9 +-- linphone.xcodeproj/project.pbxproj | 32 +++------- prepare.py | 53 ++++++++++------- submodules/cmake-builder | 2 +- 7 files changed, 103 insertions(+), 125 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 764125f2c..6bdbb167e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1427,28 +1427,14 @@ static BOOL libStarted = FALSE; connectivity = none; ms_init(); // Need to initialize mediastreamer2 before loading the plugins - + // Load plugins if available in the linphone SDK - otherwise these calls will do nothing libmsilbc_init(); -#if defined(HAVE_SILK) libmssilk_init(); -#endif -#ifdef HAVE_AMR - libmsamr_init(); // load amr plugin if present from the liblinphone sdk -#endif -#ifdef HAVE_X264 - libmsx264_init(); // load x264 plugin if present from the liblinphone sdk -#endif -#ifdef HAVE_OPENH264 - libmsopenh264_init(); // load openh264 plugin if present from the liblinphone sdk -#endif - -#if HAVE_G729 - libmsbcg729_init(); // load g729 plugin -#endif - -#ifdef HAVE_WEBRTC + libmsamr_init(); + libmsx264_init(); + libmsopenh264_init(); + libmsbcg729_init(); libmswebrtc_init(); -#endif // Set audio assets const char *lRing = diff --git a/Classes/LinphoneUI/UIVideoButton.m b/Classes/LinphoneUI/UIVideoButton.m index 5729b8033..d6651a8aa 100644 --- a/Classes/LinphoneUI/UIVideoButton.m +++ b/Classes/LinphoneUI/UIVideoButton.m @@ -99,15 +99,14 @@ - (bool)onUpdate { bool video_enabled = false; - -#ifdef VIDEO_ENABLED - LinphoneCall *currentCall = linphone_core_get_current_call([LinphoneManager getLc]); - if (linphone_core_video_enabled([LinphoneManager getLc]) && currentCall && - !linphone_call_media_in_progress(currentCall) && - linphone_call_get_state(currentCall) == LinphoneCallStreamsRunning) { - video_enabled = TRUE; + LinphoneCore *lc = [LinphoneManager getLc]; + LinphoneCall *currentCall = linphone_core_get_current_call(lc); + if (linphone_core_video_supported(lc)) { + if (linphone_core_video_enabled(lc) && currentCall && !linphone_call_media_in_progress(currentCall) && + linphone_call_get_state(currentCall) == LinphoneCallStreamsRunning) { + video_enabled = TRUE; + } } -#endif // VIDEO_ENABLED [self setEnabled:video_enabled]; if (last_update_state != video_enabled) diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index a39768712..0fb8c8f33 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -526,48 +526,47 @@ static UICompositeViewDescription *compositeDescription = nil; } + (IASKSpecifier *)filterSpecifier:(IASKSpecifier *)specifier { -#ifndef HAVE_SSL - if ([[specifier key] isEqualToString:@"transport_preference"]) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"TLS"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"tls"]; - [dict setObject:values forKey:@"Values"]; - return [[IASKSpecifier alloc] initWithSpecifier:dict]; + if (linphone_core_sip_transport_supported([LinphoneManager getLc], LinphoneTransportTls)) { + if ([[specifier key] isEqualToString:@"transport_preference"]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"TLS"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"tls"]; + [dict setObject:values forKey:@"Values"]; + return [[IASKSpecifier alloc] initWithSpecifier:dict]; + } + } else { + if ([[specifier key] isEqualToString:@"media_encryption_preference"]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionZRTP)) { + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"ZRTP"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"ZRTP"]; + [dict setObject:values forKey:@"Values"]; + } + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionSRTP)) { + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"SRTP"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"SRTP"]; + [dict setObject:values forKey:@"Values"]; + } + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionDTLS)) { + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"DTLS"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"DTLS"]; + [dict setObject:values forKey:@"Values"]; + } + return [[IASKSpecifier alloc] initWithSpecifier:dict]; + } } -#else - if ([[specifier key] isEqualToString:@"media_encryption_preference"]) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionZRTP)) { - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"ZRTP"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"ZRTP"]; - [dict setObject:values forKey:@"Values"]; - } - if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionSRTP)) { - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"SRTP"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"SRTP"]; - [dict setObject:values forKey:@"Values"]; - } - if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionDTLS)) { - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"DTLS"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"DTLS"]; - [dict setObject:values forKey:@"Values"]; - } - return [[IASKSpecifier alloc] initWithSpecifier:dict]; - } - -#endif // HAVE_SSL // Add "build from source" if MPEG4 or H264 disabled if ([[specifier key] isEqualToString:@"h264_preference"] && ![LinphoneManager isCodecSupported:"h264"]) { @@ -584,9 +583,9 @@ static UICompositeViewDescription *compositeDescription = nil; LinphoneManager *lm = [LinphoneManager instance]; NSMutableSet *hiddenKeys = [NSMutableSet set]; -#ifndef HAVE_SSL - [hiddenKeys addObject:@"media_encryption_preference"]; -#endif + if (!linphone_core_sip_transport_supported([LinphoneManager getLc], LinphoneTransportTls)) { + [hiddenKeys addObject:@"media_encryption_preference"]; + } #ifndef DEBUG [hiddenKeys addObject:@"release_button"]; @@ -630,9 +629,9 @@ static UICompositeViewDescription *compositeDescription = nil; [hiddenKeys addObject:@"enable_first_login_view_preference"]; -#ifndef VIDEO_ENABLED - [hiddenKeys addObject:@"enable_video_preference"]; -#endif // VIDEO_ENABLED + if (!linphone_core_video_supported([LinphoneManager getLc])) { + [hiddenKeys addObject:@"enable_video_preference"]; + } if (!linphone_core_video_enabled([LinphoneManager getLc])) { [hiddenKeys addObject:@"video_menu"]; diff --git a/README.md b/README.md index d0827d0c8..3dfdc0228 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,12 @@ This SDK can be generated in 2 flavors: * NO GPL third parties means that Linphone will only use non GPL code except for `liblinphone`, `mediastreamer2`, `oRTP` and `belle-sip`. If you choose this flavor, your final application is **still subject to GPL except if you have a [commercial license for the mentioned libraries](http://www.belledonne-communications.com/products.html)**. To generate the liblinphone multi arch SDK without GPL third parties, invoke: - ./prepare.py -DENABLE_GPL_THIRD_PARTIES=OFF [other options] && make + ./prepare.py --disable-gpl-third-parties=no [other options] && make ## Customizing features -You can choose to enable/disable features such as custom audio/video codecs, media encryption, etc. To get a list of all features, the simplest way is to invoke `prepare.py` with `--list-features`: +You can enable all non-free codecs using `--enable-non-free-codecs`. +You can also choose to enable/disable features one by one (custom audio/video codecs, media encryption, etc.). To get a list of all features, the simplest way is to invoke `prepare.py` with `--list-features`: ./prepare.py --list-features @@ -72,8 +73,8 @@ After the SDK is built, just open the Linphone Xcode project with Xcode, and pre ## Note regarding third party components subject to license The liblinphone SDK is compiled with third parties code that are subject to patent license, specially: AMR, SILK G729 and H264 codecs. - Linphone controls the embedding of these codecs thanks to the preprocessor macros HAVE_SILK, HAVE_AMR, HAVE_G729 HAVE_OPENH264 positioned in Xcode project. - Before embedding these 4 codecs in the final application, **make sure to have the right to do so**. + Linphone controls the embedding of these codecs by generating dummy libraries when there are not available. You can enable them using `prepare.py` + script (see `--enable-non-free-codecs` option). Before embedding these 4 codecs in the final application, **make sure to have the right to do so**. # Testing the application diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index e65620b81..f1cf39681 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -80,8 +80,6 @@ 2264B6D211200342002C2C53 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2264B6D111200342002C2C53 /* SystemConfiguration.framework */; }; 226CDAE014E2D0B800513B67 /* libmsbcg729.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226CDADE14E2D0B800513B67 /* libmsbcg729.a */; }; 226EF06C15FA256B005865C7 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 226EF06B15FA256B005865C7 /* MobileCoreServices.framework */; }; - 226F2ED61344B0EF00F6EF27 /* libopencore-amrwb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226F2ED31344B0EF00F6EF27 /* libopencore-amrwb.a */; }; - 226F2ED71344B0EF00F6EF27 /* libopencore-amrnb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226F2ED41344B0EF00F6EF27 /* libopencore-amrnb.a */; }; 226F2ED81344B0EF00F6EF27 /* libmsamr.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226F2ED51344B0EF00F6EF27 /* libmsamr.a */; }; 2274401A106F31BD006EC466 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22744019106F31BD006EC466 /* CoreAudio.framework */; }; 2274402F106F335E006EC466 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2274402E106F335E006EC466 /* AudioToolbox.framework */; }; @@ -175,6 +173,9 @@ 63C5107E1B8DF3DF008A415A /* libmediastreamer_base.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EE916006F0700B92522 /* libmediastreamer_base.a */; }; 63C5107F1B8DF3DF008A415A /* libmediastreamer_voip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EEA16006F0700B92522 /* libmediastreamer_voip.a */; }; 63C510801B8DF3DF008A415A /* libortp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 220FAD2C10765B400068D98F /* libortp.a */; }; + 63C5109E1B8F2603008A415A /* libopencore-amrnb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226F2ED41344B0EF00F6EF27 /* libopencore-amrnb.a */; }; + 63C5109F1B8F2603008A415A /* libopencore-amrwb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226F2ED31344B0EF00F6EF27 /* libopencore-amrwb.a */; }; + 63C510A01B8F48DB008A415A /* libmswebrtc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 63EA4C941B50189D00922857 /* libmswebrtc.a */; }; 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; 63D2680F1B174A5E00A2CC11 /* numpad_one_voicemail_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */; }; 63D268101B174A5E00A2CC11 /* numpad_one_voicemail_over.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680E1B174A5E00A2CC11 /* numpad_one_voicemail_over.png */; }; @@ -1889,6 +1890,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63C510A01B8F48DB008A415A /* libmswebrtc.a in Frameworks */, + 63C5109E1B8F2603008A415A /* libopencore-amrnb.a in Frameworks */, + 63C5109F1B8F2603008A415A /* libopencore-amrwb.a in Frameworks */, 63D7216D1B73975900D70E65 /* libmsx264.a in Frameworks */, 63D7215D1B7394D200D70E65 /* libtunnel.a in Frameworks */, 63D7216C1B73973D00D70E65 /* libx264.a in Frameworks */, @@ -1938,8 +1942,6 @@ 223148E61178A09900637D6A /* libmsilbc.a in Frameworks */, 226183B0147259670037138E /* libmssilk.a in Frameworks */, 22A10F3B11F8960300373793 /* libortp.a in Frameworks */, - 226F2ED71344B0EF00F6EF27 /* libopencore-amrnb.a in Frameworks */, - 226F2ED61344B0EF00F6EF27 /* libopencore-amrwb.a in Frameworks */, 226CDAE014E2D0B800513B67 /* libmsbcg729.a in Frameworks */, 220FAD3810765B400068D98F /* libspeex.a in Frameworks */, 220FAD3910765B400068D98F /* libspeexdsp.a in Frameworks */, @@ -4612,10 +4614,6 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = linphone_Prefix.pch; GCC_PREPROCESSOR_DEFINITIONS = ( - VIDEO_ENABLED, - HAVE_OPENH264, - HAVE_SILK, - HAVE_SSL, DEBUG, USE_APN_DEV, ); @@ -4702,12 +4700,6 @@ GCC_OPTIMIZATION_LEVEL = s; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = linphone_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - VIDEO_ENABLED, - HAVE_SILK, - HAVE_SSL, - HAVE_OPENH264, - ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -4790,12 +4782,7 @@ GCC_OPTIMIZATION_LEVEL = s; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = linphone_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - VIDEO_ENABLED, - HAVE_SILK, - HAVE_SSL, - USE_APN_DEV, - ); + GCC_PREPROCESSOR_DEFINITIONS = USE_APN_DEV; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -4879,11 +4866,6 @@ GCC_OPTIMIZATION_LEVEL = s; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = linphone_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = ( - VIDEO_ENABLED, - HAVE_SILK, - HAVE_SSL, - ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; diff --git a/prepare.py b/prepare.py index 3d1919f43..8bc775fc9 100755 --- a/prepare.py +++ b/prepare.py @@ -112,7 +112,7 @@ class PlatformListAction(argparse.Action): def gpl_disclaimer(platforms): cmakecache = 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]) - gpl_third_parties_enabled = ("ENABLE_GPL_THIRD_PARTIES:BOOL=ON" in open(cmakecache).read()) + gpl_third_parties_enabled = "ENABLE_GPL_THIRD_PARTIES:BOOL=YES" in open(cmakecache).read() or "ENABLE_GPL_THIRD_PARTIES:BOOL=ON" in open(cmakecache).read() if gpl_third_parties_enabled: warning("\n***************************************************************************" @@ -138,14 +138,14 @@ def gpl_disclaimer(platforms): def extract_libs_list(): l = [] # name = libspeexdsp.a; path = "liblinphone-sdk/apple-darwin/lib/libspeexdsp.a"; sourceTree = ""; }; - regex = re.compile("name = (lib(\S+)\.a); path = \"liblinphone-sdk/apple-darwin/") + regex = re.compile("name = (\")*(lib(\S+))\.a(\")*; path = \"liblinphone-sdk/apple-darwin/") f = open('linphone.xcodeproj/project.pbxproj', 'r') lines = f.readlines() f.close() for line in lines: m = regex.search(line) if m is not None: - l += [m.group(1)] + l += [m.group(2)] return list(set(l)) @@ -154,7 +154,6 @@ missing_dependencies = {} def check_is_installed(binary, prog=None, warn=True): if not find_executable(binary): - if warn: missing_dependencies[binary] = prog # error("Could not find {}. Please install {}.".format(binary, prog)) @@ -383,6 +382,13 @@ clean: $(addprefix clean-,$(packages)) veryclean: $(addprefix veryclean-,$(packages)) +generate-dummy-%: +\t@echo "[{archs}] Generating dummy $* static library." ; \\ +\tprintf "void $*_init() {{}}" | tr '-' '_' > .dummy.c ; \\ +\tfor arch in {archs}; do clang -c .dummy.c -arch $$arch -o .dummy-$$arch.a; done ; \\ +\tlipo -create -output .dummy.a .dummy-*.a ; \\ +\trm .dummy-*.a .dummy.c + lipo: \tarchives=`find liblinphone-sdk/{first_arch}-apple-darwin.ios -name *.a` && \\ \tmkdir -p liblinphone-sdk/apple-darwin && \\ @@ -398,18 +404,18 @@ lipo: \t\tall_archs="{first_arch}"; \\ \t\tmkdir -p `dirname $$destpath`; \\ \t\t{multiarch} \\ -\t\techo "[$$all_archs] Mixing `basename $$archive` in $$destpath"; \\ +\t\techo "[{archs}] Mixing `basename $$archive` in $$destpath"; \\ \t\tlipo -create $$all_paths -output $$destpath; \\ \tdone && \\ \tfor lib in {libs_list} ; do \\ \t\tif [ $${{lib:0:5}} = "libms" ] ; then \\ -\t\t\tlibrary_path=liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/$$lib ; \\ +\t\t\tlibrary_path=liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/$${{lib}}.a ; \\ \t\telse \\ -\t\t\tlibrary_path=liblinphone-sdk/apple-darwin/lib/$$lib ; \\ +\t\t\tlibrary_path=liblinphone-sdk/apple-darwin/lib/$${{lib}}.a ; \\ \t\tfi ; \\ \t\tif ! test -f $$library_path ; then \\ -\t\t\techo "[$$all_archs] Generating dummy $$lib static library." ; \\ -\t\t\tcp -f submodules/binaries/libdummy.a $$library_path ; \\ +\t\t\t$(MAKE) generate-dummy-$$lib ; \\ +\t\t\tmv .dummy.a $$library_path ; \\ \t\tfi \\ \tdone @@ -492,7 +498,11 @@ def main(argv=None): argparser.add_argument( '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') argparser.add_argument( - '-G' '--generator', help="CMake build system generator (default: Unix Makefiles).", default='Unix Makefiles', choices=['Unix Makefiles', 'Ninja']) + '--disable-gpl-third-parties', help="Disable GPL third parties such as FFMpeg, x264.", action='store_false') + argparser.add_argument( + '--enable-non-free-codecs', help="Enable non-free codecs such as OpenH264, MPEG4, etc.. Final application must comply with their respective license (see README.md).", action='store_true') + argparser.add_argument( + '-G' '--generator', help="CMake build system generator (default: Unix Makefiles).", default='Unix Makefiles', choices=['Unix Makefiles', 'Ninja'], dest='generator') argparser.add_argument( '-L', '--list-cmake-variables', help="List non-advanced CMake cache variables.", action='store_true', dest='list_cmake_variables') argparser.add_argument( @@ -504,26 +514,27 @@ def main(argv=None): args, additional_args = argparser.parse_known_args() - if check_tools() != 0: - return 1 - - if args.debug_verbose: - additional_args += ["-DENABLE_DEBUG_LOGS=ON"] - - additional_args += ["-G", args.G__generator] - if args.G__generator == 'Ninja': + additional_args += ["-G", args.generator] + if args.generator == 'Ninja': if not check_is_installed("ninja", "it"): return 1 generator = 'ninja -C' else: generator = '$(MAKE) -C' + if check_tools() != 0: + return 1 + + additional_args += ["-DENABLE_DEBUG_LOGS={}".format("YES" if args.debug_verbose else "NO")] + additional_args += ["-DENABLE_NON_FREE_CODECS={}".format("YES" if args.enable_non_free_codecs else "NO")] + additional_args += ["-DENABLE_GPL_THIRD_PARTIES={}".format("NO" if args.disable_gpl_third_parties else "YES")] + if args.tunnel or os.path.isdir("submodules/tunnel"): if not os.path.isdir("submodules/tunnel"): info("Tunnel wanted but not found yet, trying to clone it...") - if check_is_installed("git", "it", True): - Popen("git clone gitosis@git.linphone.org:tunnel.git submodules/tunnel".split(" ")).wait() - else: + p = Popen("git clone gitosis@git.linphone.org:tunnel.git submodules/tunnel".split(" ")) + p.wait() + if p.retcode != 0: error("Could not clone tunnel. Please see http://www.belledonne-communications.com/voiptunnel.html") return 1 warning("Tunnel enabled, disabling GPL third parties.") diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 3401c7cea..955f87493 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 3401c7cea3667101395d7ff41bbf98d152b4603a +Subproject commit 955f8749357d7caa195699f12efe2a04823f0e2d From d9565d6dcc990f3fa6f81fcca80b973a7764912b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 28 Aug 2015 11:47:32 +0200 Subject: [PATCH 22/46] Testers: reset log level to Message for automation builders --- LiblinphoneTester/MasterViewController.m | 2 +- TestsUI/LinphoneTestCase.m | 4 ---- submodules/cmake-builder | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/LiblinphoneTester/MasterViewController.m b/LiblinphoneTester/MasterViewController.m index ab5856a02..66ed6ad15 100644 --- a/LiblinphoneTester/MasterViewController.m +++ b/LiblinphoneTester/MasterViewController.m @@ -41,7 +41,7 @@ NSString *const kLogsUpdateNotification = @"kLogsUpdateNotification"; lastLogs = [[NSMutableArray alloc] initWithCapacity:kLastLogsCapacity]; logsBuffer = [NSMutableArray arrayWithCapacity:kLogsBufferCapacity]; - linphone_core_set_log_level(ORTP_WARNING); + linphone_core_set_log_level(ORTP_MESSAGE); linphone_core_set_log_handler((OrtpLogFunc)linphone_iphone_log_handler); } diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index 647e35024..aa3f2b2a1 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -23,11 +23,7 @@ if (!([language isEqualToString:@"en"] || [language containsString:@"en-"])) { LOGF(@"Language must be 'en' (English) instead of %@", language); } -#if DEBUG linphone_core_set_log_level(ORTP_MESSAGE); -#else - linphone_core_set_log_level(ORTP_WARNING); -#endif } - (void)beforeAll { diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 955f87493..51339c08f 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 955f8749357d7caa195699f12efe2a04823f0e2d +Subproject commit 51339c08f32b09fd4d04a7a56c16ad68ad6be01b From 181cf75f49e2d37cab8f7a751997a8d507e263f0 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 31 Aug 2015 10:22:30 +0200 Subject: [PATCH 23/46] prepare.py: remove submodules/binaries directory since we automatically generate dummy libraries in main Makefile --- submodules/binaries/dummy.c | 1 - submodules/binaries/libdummy.a | Bin 33276 -> 0 bytes submodules/binaries/why.txt | 11 ----------- 3 files changed, 12 deletions(-) delete mode 100644 submodules/binaries/dummy.c delete mode 100644 submodules/binaries/libdummy.a delete mode 100644 submodules/binaries/why.txt diff --git a/submodules/binaries/dummy.c b/submodules/binaries/dummy.c deleted file mode 100644 index 8b1378917..000000000 --- a/submodules/binaries/dummy.c +++ /dev/null @@ -1 +0,0 @@ - diff --git a/submodules/binaries/libdummy.a b/submodules/binaries/libdummy.a deleted file mode 100644 index 86589a6625676a66d41066dd423b9ae18cd1918b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33276 zcmeI*J#N%M7{>8g2pcjG)T}Pk%DfNSSVU)vm3ES0*S&0-~b$fGf+@R z6u=R<02e?}l;@e*aV!gvSsEn%uk?C8Y`*&9^Q|0m3{#tiU_v37}udMaIzS=qV`+w#9Ud^`j zbB%g&FpG14N-)Nse?xFsL+kx}HR{ED*+f@y-9M<|!&Ag~GOd@dj}I5KW%Kgz!Ppvp v_khFiD2VZCbI?rd$Mb3WD&p80I<-}%h_PNaFQ)UOZamJzf6o%bcP3l_YQ|!- diff --git a/submodules/binaries/why.txt b/submodules/binaries/why.txt deleted file mode 100644 index 416ae61d3..000000000 --- a/submodules/binaries/why.txt +++ /dev/null @@ -1,11 +0,0 @@ -Notes: - -This directory is here because XCode cannot handle optional static libraries linking so we must stub some library, tunnel for instance. - -You can regenerate dummy.c (which is an empty file...) using: - - - for arch in arm64 armv7 i386 x86_64; do - clang -c dummy.c -o dummy-$arch.a -arch $arch - done - lipo -create -output libdummy.a dummy-*.a From 0ecdc1c5aa86ffa99047ff8a4974e8c674bee69f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 31 Aug 2015 15:03:24 +0200 Subject: [PATCH 24/46] submodules: update cmake-builder so that one can choose to build only some non free codecs and not all of them --- submodules/cmake-builder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 51339c08f..e7195fe05 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 51339c08f32b09fd4d04a7a56c16ad68ad6be01b +Subproject commit e7195fe050bd4191f2c389170d8851260ba47f8d From 961aa3b44518fc800e98aa30fd2c6271edc73a08 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 31 Aug 2015 16:51:38 +0200 Subject: [PATCH 25/46] prepare.py&submodules: allow compilation of X264 and OpenH264 by refactoring cmake builder submodule --- prepare.py | 11 +++++++---- submodules/cmake-builder | 2 +- submodules/msx264 | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/prepare.py b/prepare.py index 8bc775fc9..6c17a8ad4 100755 --- a/prepare.py +++ b/prepare.py @@ -498,7 +498,7 @@ def main(argv=None): argparser.add_argument( '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') argparser.add_argument( - '--disable-gpl-third-parties', help="Disable GPL third parties such as FFMpeg, x264.", action='store_false') + '--disable-gpl-third-parties', help="Disable GPL third parties such as FFMpeg, x264.", action='store_true') argparser.add_argument( '--enable-non-free-codecs', help="Enable non-free codecs such as OpenH264, MPEG4, etc.. Final application must comply with their respective license (see README.md).", action='store_true') argparser.add_argument( @@ -525,9 +525,12 @@ def main(argv=None): if check_tools() != 0: return 1 - additional_args += ["-DENABLE_DEBUG_LOGS={}".format("YES" if args.debug_verbose else "NO")] - additional_args += ["-DENABLE_NON_FREE_CODECS={}".format("YES" if args.enable_non_free_codecs else "NO")] - additional_args += ["-DENABLE_GPL_THIRD_PARTIES={}".format("NO" if args.disable_gpl_third_parties else "YES")] + if args.debug_verbose is True: + additional_args += ["-DENABLE_DEBUG_LOGS=YES"] + if args.enable_non_free_codecs is True: + additional_args += ["-DENABLE_NON_FREE_CODECS=YES"] + if args.disable_gpl_third_parties is True: + additional_args += ["-DENABLE_GPL_THIRD_PARTIES=NO"] if args.tunnel or os.path.isdir("submodules/tunnel"): if not os.path.isdir("submodules/tunnel"): diff --git a/submodules/cmake-builder b/submodules/cmake-builder index e7195fe05..93910b557 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit e7195fe050bd4191f2c389170d8851260ba47f8d +Subproject commit 93910b55774ca708cc6c16c41c6a705630176ae1 diff --git a/submodules/msx264 b/submodules/msx264 index 2abff2362..e8fd6adb5 160000 --- a/submodules/msx264 +++ b/submodules/msx264 @@ -1 +1 @@ -Subproject commit 2abff23629257c3f6f46b8d7b3a483efd0eb4342 +Subproject commit e8fd6adb59e9015c1bfe58e364565016ef26122c From fa8a44eb5ffcc598379baa17e753e383e3e4546d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 31 Aug 2015 17:13:57 +0200 Subject: [PATCH 26/46] SettingsViewController: do not show custom label "Disabled, build from source to enable" for MPEG4 and H264 if there are not available; it is confusing and can be misleading about the cause of non-availability --- Classes/SettingsViewController.m | 33 +++++++------------------------- submodules/cmake-builder | 2 +- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index 0fb8c8f33..77cac3662 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -507,24 +507,6 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - -+ (IASKSpecifier *)disableCodecSpecifier:(IASKSpecifier *)specifier { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - - NSMutableString *type = [NSMutableString stringWithString:[dict objectForKey:kIASKType]]; - [type setString:kIASKPSTitleValueSpecifier]; - [dict setObject:type forKey:kIASKType]; - - NSMutableArray *values = - [NSMutableArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:1], nil]; - [dict setObject:values forKey:kIASKValues]; - - NSString *title = NSLocalizedString(@"Disabled, build from sources to enable", nil); - NSMutableArray *titles = [NSMutableArray arrayWithObjects:title, title, nil]; - [dict setObject:titles forKey:kIASKTitles]; - - return [[IASKSpecifier alloc] initWithSpecifier:dict]; -} - + (IASKSpecifier *)filterSpecifier:(IASKSpecifier *)specifier { if (linphone_core_sip_transport_supported([LinphoneManager getLc], LinphoneTransportTls)) { if ([[specifier key] isEqualToString:@"transport_preference"]) { @@ -568,14 +550,6 @@ static UICompositeViewDescription *compositeDescription = nil; } } - // Add "build from source" if MPEG4 or H264 disabled - if ([[specifier key] isEqualToString:@"h264_preference"] && ![LinphoneManager isCodecSupported:"h264"]) { - return [SettingsViewController disableCodecSpecifier:specifier]; - } - if ([[specifier key] isEqualToString:@"mp4v-es_preference"] && ![LinphoneManager isCodecSupported:"mp4v-es"]) { - return [SettingsViewController disableCodecSpecifier:specifier]; - } - return specifier; } @@ -614,6 +588,13 @@ static UICompositeViewDescription *compositeDescription = nil; if (!linphone_core_video_supported([LinphoneManager getLc])) [hiddenKeys addObject:@"video_menu"]; + if (![LinphoneManager isCodecSupported:"h264"]) { + [hiddenKeys addObject:@"h264_preference"]; + } + if (![LinphoneManager isCodecSupported:"mp4v-es"]) { + [hiddenKeys addObject:@"mp4v-es_preference"]; + } + if (![LinphoneManager isNotIphone3G]) [hiddenKeys addObject:@"silk_24k_preference"]; diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 93910b557..5ff6590ab 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 93910b55774ca708cc6c16c41c6a705630176ae1 +Subproject commit 5ff6590ab1b9e97bc97eadaa4f64353f266e2d9f From 8a8cb70c92ad8b43319ec3e890e9ec16e62e069d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 1 Sep 2015 09:53:44 +0200 Subject: [PATCH 27/46] SettingsViewController: fix "Unbalanced calls to begin/end appearance transitions for Date: Tue, 1 Sep 2015 12:05:16 +0200 Subject: [PATCH 28/46] LinphoneUITester: add performance tests for big conversation and big chats list --- .../LinphoneUI/UICompositeViewController.m | 4 +- Classes/PhoneMainView.m | 46 ++++++++++------ TestsUI/ChatTester.m | 53 +++++++++++++++++-- linphone.xcodeproj/project.pbxproj | 2 + submodules/linphone | 2 +- 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/Classes/LinphoneUI/UICompositeViewController.m b/Classes/LinphoneUI/UICompositeViewController.m index c64726546..5fe8f8be4 100644 --- a/Classes/LinphoneUI/UICompositeViewController.m +++ b/Classes/LinphoneUI/UICompositeViewController.m @@ -425,7 +425,9 @@ UIViewController *newStateBarViewController = [self getCachedController:description.stateBar]; UIViewController *newTabBarViewController = [self getCachedController:description.tabBar]; - [UICompositeViewController removeSubView:oldContentViewController]; + if (oldContentViewController != newContentViewController) { + [UICompositeViewController removeSubView:oldContentViewController]; + } if (oldTabBarViewController != nil && oldTabBarViewController != newTabBarViewController) { [UICompositeViewController removeSubView:oldTabBarViewController]; } diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 407e5b599..c9d48d9e7 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -77,24 +77,36 @@ static RootViewManager *rootViewManagerInstance = nil; currentViewController = newMainView; LinphoneAppDelegate *delegate = (LinphoneAppDelegate *)[UIApplication sharedApplication].delegate; - [UIView transitionWithView:delegate.window - duration:0.3 - options:UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowAnimatedContent - animations:^{ - delegate.window.rootViewController = newMainView; - // when going to landscape-enabled view, we have to get the current portrait frame and orientation, - // because it could still have landscape-based size - if (nextViewOrientation != previousOrientation && newMainView == self.rotatingViewController) { - newMainView.view.frame = previousMainView.view.frame; - [newMainView.mainViewController.view setFrame:previousMainView.mainViewController.view.frame]; - [newMainView willRotateToInterfaceOrientation:previousOrientation duration:0.3]; - [newMainView willAnimateRotationToInterfaceOrientation:previousOrientation duration:0.3]; - [newMainView didRotateFromInterfaceOrientation:nextViewOrientation]; - } - + if ([[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"] == true) { + [UIView transitionWithView:delegate.window + duration:0.3 + options:UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowAnimatedContent + animations:^{ + delegate.window.rootViewController = newMainView; + // when going to landscape-enabled view, we have to get the current portrait frame and orientation, + // because it could still have landscape-based size + if (nextViewOrientation != previousOrientation && newMainView == self.rotatingViewController) { + newMainView.view.frame = previousMainView.view.frame; + [newMainView.mainViewController.view setFrame:previousMainView.mainViewController.view.frame]; + [newMainView willRotateToInterfaceOrientation:previousOrientation duration:0.3]; + [newMainView willAnimateRotationToInterfaceOrientation:previousOrientation duration:0.3]; + [newMainView didRotateFromInterfaceOrientation:nextViewOrientation]; + } + } + completion:^(BOOL finished){ + }]; + } else { + delegate.window.rootViewController = newMainView; + // when going to landscape-enabled view, we have to get the current portrait frame and orientation, + // because it could still have landscape-based size + if (nextViewOrientation != previousOrientation && newMainView == self.rotatingViewController) { + newMainView.view.frame = previousMainView.view.frame; + [newMainView.mainViewController.view setFrame:previousMainView.mainViewController.view.frame]; + [newMainView willRotateToInterfaceOrientation:previousOrientation duration:0.]; + [newMainView willAnimateRotationToInterfaceOrientation:previousOrientation duration:0.]; + [newMainView didRotateFromInterfaceOrientation:nextViewOrientation]; } - completion:^(BOOL finished){ - }]; + } } return currentViewController; } diff --git a/TestsUI/ChatTester.m b/TestsUI/ChatTester.m index 95a81c1cc..38005d81a 100644 --- a/TestsUI/ChatTester.m +++ b/TestsUI/ChatTester.m @@ -165,10 +165,6 @@ [self startChatWith:[self me]]; [self uploadImageWithQuality:@"Minimum"]; [tester tapViewWithAccessibilityLabel:@"Cancel transfer"]; - if ([[[LinphoneManager instance] fileTransferDelegates] count] != 0) { - [[UIApplication sharedApplication] writeScreenshotForLine:__LINE__ inFile:@__FILE__ description:nil error:NULL]; - ; - } ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); } @@ -226,6 +222,55 @@ [tester tapViewWithAccessibilityLabel:@"Cancel"]; } +- (void)testPerformanceHugeChatList { + [tester tapViewWithAccessibilityLabel:@"Dialer"]; + + // create lots of chat rooms... + LinphoneCore *lc = [LinphoneManager getLc]; + for (int i = 0; i < 100; i++) { + LinphoneChatRoom *room = + linphone_core_get_chat_room_from_uri(lc, [[NSString stringWithFormat:@"%@ - %d", [self me], i] UTF8String]); + linphone_chat_room_send_message(room, "Hello"); + } + + [tester waitForTimeInterval:5]; // wait for all messages to be delivered + + NSTimeInterval before = [[NSDate date] timeIntervalSince1970]; + [tester tapViewWithAccessibilityLabel:@"Chat"]; + NSTimeInterval after = [[NSDate date] timeIntervalSince1970]; + + // delete all rooms from test because it takes time when done by tester + [tester tapViewWithAccessibilityLabel:@"Dialer"]; + for (MSList *it = linphone_core_get_chat_rooms(lc); it != NULL; it = it->next) { + linphone_chat_room_delete_history(it->data); + } + + // conversation loading MUST be less than 1 sec + XCTAssertLessThan(after - before, 1.); +} + +- (void)testPerformanceHugeConversation { + int count = 0; + LinphoneCore *lc = [LinphoneManager getLc]; + LinphoneChatRoom *room = linphone_core_get_chat_room_from_uri(lc, [[self me] UTF8String]); + // generate lots of messages... + for (; count < 100; count++) { + linphone_chat_room_send_message(room, [[NSString stringWithFormat:@"Message %d", count + 1] UTF8String]); + } + [tester waitForTimeInterval:5]; // wait for all messages to be delivered + // TODO: FIX below code: unread count is not always 100 messages while it should... + [tester waitForViewWithAccessibilityLabel:@"Contact name, Message, Unread message number" + value:[NSString stringWithFormat:@"%@ - Message %d (%d)", self.me, count, count] + traits:UIAccessibilityTraitStaticText]; + + NSTimeInterval before = [[NSDate date] timeIntervalSince1970]; + [self startChatWith:[self me]]; + NSTimeInterval after = [[NSDate date] timeIntervalSince1970]; + + // conversation loading MUST be less than 1 sec - opening an empty conversation is around 2.15 sec + XCTAssertLessThan(after - before, 2.15 + 1.); +} + - (void)testRemoveAllChats { NSArray *uuids = [self getUUIDArrayOfSize:5]; diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index f1cf39681..43aef7f4c 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -150,6 +150,7 @@ 631C4FB719D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 631C4FB619D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.m */; }; 632DA24D1B43EE9400EB356A /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D35860D515B549B500513429 /* Utils.m */; }; 632DA24E1B43EEEF00EB356A /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D35860D515B549B500513429 /* Utils.m */; }; + 635ED88B1B95A3B500404347 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 152F22351B15E889008C0621 /* libxml2.dylib */; }; 636316D11A1DEBCB0009B839 /* AboutViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D31A1DEBCB0009B839 /* AboutViewController.xib */; }; 636316D41A1DEC650009B839 /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D61A1DEC650009B839 /* SettingsViewController.xib */; }; 636316D91A1DECC90009B839 /* PhoneMainView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D71A1DECC90009B839 /* PhoneMainView.xib */; }; @@ -2013,6 +2014,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 635ED88B1B95A3B500404347 /* libxml2.dylib in Frameworks */, 63C5107C1B8DF3DF008A415A /* libbellesip.a in Frameworks */, 63C5107D1B8DF3DF008A415A /* liblinphonetester.a in Frameworks */, 63C5107E1B8DF3DF008A415A /* libmediastreamer_base.a in Frameworks */, diff --git a/submodules/linphone b/submodules/linphone index af43ad896..a722c7651 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit af43ad89650f70ce5e2fb4a45287aabbdd9b63d6 +Subproject commit a722c765153c7f0065ccca1137c7b4d97294477f From d55cc1b93ab6d43365315f457138d41c9f25c369 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 2 Sep 2015 10:54:00 +0200 Subject: [PATCH 29/46] UIChatRoomCell: click anywhere in the chat bubble to resend text, not only the tiny date and/or delivery status image --- Classes/LinphoneUI/UIChatRoomCell.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index f32e57d08..8bae63bb2 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -66,8 +66,7 @@ static UIFont *CELL_FONT = nil; resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)]; - [dateLabel addGestureRecognizer:resendTapGestureRecognizer]; - [statusImage addGestureRecognizer:resendTapGestureRecognizer]; + [innerView addGestureRecognizer:resendTapGestureRecognizer]; [self addSubview:innerView]; [deleteButton setAlpha:0.0f]; From 980811a75cf2abb93b742be7c0e4a1788bfd5994 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 2 Sep 2015 14:34:46 +0200 Subject: [PATCH 30/46] chat: fix crash when file transfer was aborted due to some error in liblinphone --- Classes/Utils/FileTransferDelegate.m | 13 +++++++------ submodules/linphone | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 112c62b9b..5775125ac 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -137,19 +137,20 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m } - (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom { - [[[LinphoneManager instance] fileTransferDelegates] addObject:self]; + [LinphoneManager.instance.fileTransferDelegates addObject:self]; LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom)); _data = [NSMutableData dataWithData:UIImageJPEGRepresentation(image, 1.0)]; linphone_content_set_type(content, "image"); linphone_content_set_subtype(content, "jpeg"); linphone_content_set_name(content, - [[NSString stringWithFormat:@"%li-%f.jpg", (long)[image hash], + [[NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]] UTF8String]); - linphone_content_set_size(content, [_data length]); + linphone_content_set_size(content, _data.length); _message = linphone_chat_room_create_file_transfer_message(chatRoom, content); - linphone_chat_message_ref(_message); + linphone_content_unref(content); + linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), linphone_iphone_file_transfer_send); @@ -158,7 +159,7 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:_message]; } - LOGI(@"%p Uploading content in %p", self, _message); + LOGI(@"%p Uploading content from message %p", self, _message); linphone_chat_room_send_chat_message(chatRoom, _message); } @@ -193,7 +194,7 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m linphone_chat_message_cancel_file_transfer(_message); linphone_chat_message_unref(_message); } - _message = nil; + _message = NULL; _data = nil; LOGI(@"%p Destroying", self); } diff --git a/submodules/linphone b/submodules/linphone index a722c7651..434907917 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit a722c765153c7f0065ccca1137c7b4d97294477f +Subproject commit 434907917e933737b31b93853019f3a8c7300675 From e8f3af4ff98c7b8a883b170281ac2edd5457fd20 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 2 Sep 2015 14:35:14 +0200 Subject: [PATCH 31/46] prepare.py: remove liblinphone-sdk/apple-darwin before doing lipo task, so that dummy libraries are regenerated as well --- prepare.py | 1 + 1 file changed, 1 insertion(+) diff --git a/prepare.py b/prepare.py index 6c17a8ad4..998b18325 100755 --- a/prepare.py +++ b/prepare.py @@ -391,6 +391,7 @@ generate-dummy-%: lipo: \tarchives=`find liblinphone-sdk/{first_arch}-apple-darwin.ios -name *.a` && \\ +\trm -rf liblinphone-sdk/apple-darwin && \\ \tmkdir -p liblinphone-sdk/apple-darwin && \\ \tcp -rf liblinphone-sdk/{first_arch}-apple-darwin.ios/include liblinphone-sdk/apple-darwin/. && \\ \tcp -rf liblinphone-sdk/{first_arch}-apple-darwin.ios/share liblinphone-sdk/apple-darwin/. && \\ From 338ef353da96cf986854b1427be13a9485af344a Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 2 Sep 2015 16:28:40 +0200 Subject: [PATCH 32/46] UICompositeViewController: always remove oldContent to avoid (?) duplicate incoming bubble chat on file transfer receive --- Classes/LinphoneUI/UICompositeViewController.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Classes/LinphoneUI/UICompositeViewController.m b/Classes/LinphoneUI/UICompositeViewController.m index 5fe8f8be4..c64726546 100644 --- a/Classes/LinphoneUI/UICompositeViewController.m +++ b/Classes/LinphoneUI/UICompositeViewController.m @@ -425,9 +425,7 @@ UIViewController *newStateBarViewController = [self getCachedController:description.stateBar]; UIViewController *newTabBarViewController = [self getCachedController:description.tabBar]; - if (oldContentViewController != newContentViewController) { - [UICompositeViewController removeSubView:oldContentViewController]; - } + [UICompositeViewController removeSubView:oldContentViewController]; if (oldTabBarViewController != nil && oldTabBarViewController != newTabBarViewController) { [UICompositeViewController removeSubView:oldTabBarViewController]; } From c1d6b7f4c495c2baffd1f9f5488c36278f92b3a5 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 2 Sep 2015 16:54:43 +0200 Subject: [PATCH 33/46] SettingsViewController: fix typo when checking if TLS is available --- Classes/SettingsViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index ce51a36f1..ea5a88125 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -508,7 +508,7 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - + (IASKSpecifier *)filterSpecifier:(IASKSpecifier *)specifier { - if (linphone_core_sip_transport_supported([LinphoneManager getLc], LinphoneTransportTls)) { + if (!linphone_core_sip_transport_supported([LinphoneManager getLc], LinphoneTransportTls)) { if ([[specifier key] isEqualToString:@"transport_preference"]) { NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; From 3c49bb7965a10f38b9b7d5f319822396bc27a4cd Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 3 Sep 2015 10:21:55 +0200 Subject: [PATCH 34/46] prepare.py: remove transient unused "libs" target, cleanup make help and fix make ipa generation --- .gitignore | 1 + prepare.py | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 45d7cad61..3e162d2d6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ OUTPUT git-clang-format.diff submodules/tunnel submodules/binaries/dummy-*.a +linphone-iphone.ipa diff --git a/prepare.py b/prepare.py index 998b18325..c5f04ebc5 100755 --- a/prepare.py +++ b/prepare.py @@ -376,8 +376,6 @@ veryclean-%: package-in-list-% \tdone; \\ \techo "Run 'make build-$*' to rebuild $* correctly." -build: libs - clean: $(addprefix clean-,$(packages)) veryclean: $(addprefix veryclean-,$(packages)) @@ -420,14 +418,14 @@ lipo: \t\tfi \\ \tdone -libs: $(addprefix all-,$(archs)) +build: $(addprefix all-,$(archs)) \t$(MAKE) lipo ipa: build \txcodebuild -configuration Release \\ -\t&& xcrun -sdk iphoneos PackageApplication -v build/Release-iphoneos/linphone.app -o linphone-iphone.ipa +\t&& xcrun -sdk iphoneos PackageApplication -v build/Release-iphoneos/linphone.app -o $$PWD/linphone-iphone.ipa -sdk: libs +sdk: build \techo "Generating SDK zip file for version $(LINPHONE_IPHONE_VERSION)" \tzip -r liblinphone-iphone-sdk-$(LINPHONE_IPHONE_VERSION).zip \\ \tliblinphone-sdk/apple-darwin \\ @@ -459,19 +457,18 @@ help: help-prepare-options \t@echo "" \t@echo "Available targets:" \t@echo "" -\t@echo " * all : builds all architectures and creates the liblinphone sdk" -\t@echo " * zipres : creates a tar.gz file with all the resources (images)" +\t@echo " * all or build: builds all architectures and creates the liblinphone SDK" +\t@echo " * sdk: generates a ZIP archive of liblinphone-sdk/apple-darwin containing the SDK. Use this only after a full build." +\t@echo " * zipres: creates a tar.gz file with all the resources (images)" \t@echo "" \t@echo "=== Advanced usage ===" \t@echo "" -\t@echo " * build-[package] : builds the package for all architectures" -\t@echo " * clean-[package] : clean the package for all architectures" +\t@echo " * build-[package]: builds the package for all architectures" +\t@echo " * clean-[package]: cleans the package for all architectures" \t@echo "" -\t@echo " * [{arch_opts}]-build-[package] : builds a package for the selected architecture" -\t@echo " * [{arch_opts}]-clean-[package] : clean the package for the selected architecture" +\t@echo " * [{arch_opts}]-build-[package]: builds a package for the selected architecture" +\t@echo " * [{arch_opts}]-clean-[package]: cleans the package for the selected architecture" \t@echo "" -\t@echo " * sdk : re-add all generated libraries to the SDK. Use this only after a full build." -\t@echo " * libs : after a rebuild of a subpackage, will mix the new libs in liblinphone-sdk/apple-darwin directory" """.format(archs=' '.join(platforms), arch_opts='|'.join(platforms), first_arch=platforms[0], options=' '.join(sys.argv), arch_targets=arch_targets, packages=' '.join(packages), @@ -579,7 +576,7 @@ def main(argv=None): if args.clean: target.clean() else: - retcode = prepare.run(target, args.debug, False, args.list_cmake_variables, args.force, additional_args) + retcode = prepare.run (target, args.debug, False, args.list_cmake_variables, args.force, additional_args) if retcode != 0: if retcode == 51: Popen("make help-prepare-options".split(" ")) From 7d3e4e557276ffe28442513ecd1599dcc8cd4101 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 3 Sep 2015 16:12:17 +0200 Subject: [PATCH 35/46] LinphoneUITester: do not remove chat rooms from tester, it cannot be done properly from there - only ChatTableViewController should do that --- Classes/ChatTableViewController.m | 4 ++-- Classes/KIF | 2 +- TestsUI/ChatTester.m | 6 ------ submodules/linphone | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index ed656c698..d0f5e94c9 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -50,8 +50,8 @@ #pragma mark - ViewController Functions -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; self.tableView.accessibilityIdentifier = @"ChatRoom list"; [self loadData]; } diff --git a/Classes/KIF b/Classes/KIF index 7cf06309a..d99b9a1ab 160000 --- a/Classes/KIF +++ b/Classes/KIF @@ -1 +1 @@ -Subproject commit 7cf06309ad1e5b694f1ae6f2f40c0e8d386f7f06 +Subproject commit d99b9a1ab55a655841492df9d033c1543d175990 diff --git a/TestsUI/ChatTester.m b/TestsUI/ChatTester.m index 38005d81a..f1e50ea67 100644 --- a/TestsUI/ChatTester.m +++ b/TestsUI/ChatTester.m @@ -239,12 +239,6 @@ [tester tapViewWithAccessibilityLabel:@"Chat"]; NSTimeInterval after = [[NSDate date] timeIntervalSince1970]; - // delete all rooms from test because it takes time when done by tester - [tester tapViewWithAccessibilityLabel:@"Dialer"]; - for (MSList *it = linphone_core_get_chat_rooms(lc); it != NULL; it = it->next) { - linphone_chat_room_delete_history(it->data); - } - // conversation loading MUST be less than 1 sec XCTAssertLessThan(after - before, 1.); } diff --git a/submodules/linphone b/submodules/linphone index 434907917..08e923a41 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 434907917e933737b31b93853019f3a8c7300675 +Subproject commit 08e923a41c73ce78826c3ef93e9107e89222ce40 From d4f5211bffcea31b77a46c810665b0eac335229d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 09:34:09 +0200 Subject: [PATCH 36/46] submodules: update KIF to fix emoji issue --- Classes/KIF | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/KIF b/Classes/KIF index d99b9a1ab..dc82f0f13 160000 --- a/Classes/KIF +++ b/Classes/KIF @@ -1 +1 @@ -Subproject commit d99b9a1ab55a655841492df9d033c1543d175990 +Subproject commit dc82f0f131d48d76d9fdfe227b5c947a8e601e93 From eec076395f1209a7286a3883d19bfea4af6f7a71 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 12:06:12 +0200 Subject: [PATCH 37/46] submodules: update linphone --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 08e923a41..9f2b9df16 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 08e923a41c73ce78826c3ef93e9107e89222ce40 +Subproject commit 9f2b9df16a2f6537196a7f2ec8db792d63287a9d From 04551d7f670c92718a770e39e22d8b029912478b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 14:24:42 +0200 Subject: [PATCH 38/46] FileTransfer: fix crash when cancelling file transfer --- Classes/Utils/FileTransferDelegate.m | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 5775125ac..28b74008d 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -188,13 +188,17 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m - (void)stopAndDestroy { [[[LinphoneManager instance] fileTransferDelegates] removeObject:self]; if (_message != NULL) { - LOGI(@"%p Cancelling transfer from %p", self, _message); - linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), NULL); - linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message), NULL); - linphone_chat_message_cancel_file_transfer(_message); - linphone_chat_message_unref(_message); + LinphoneChatMessage *msg = _message; + _message = NULL; + LOGI(@"%p Cancelling transfer from %p", self, msg); + linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(msg), NULL); + linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(msg), NULL); + // when we cancel file transfer, this will automatically trigger NotDelivered callback... recalling ourself a + // second time + // so we have to unset message BEFORE calling this + linphone_chat_message_cancel_file_transfer(msg); + linphone_chat_message_unref(msg); } - _message = NULL; _data = nil; LOGI(@"%p Destroying", self); } From 9395ea63c5c5550fd248500e757ce04a340b649d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 14:39:13 +0200 Subject: [PATCH 39/46] Wizard: display "Incorrect username or password" instead of "Forbidden" when failing to register --- Classes/WizardViewController.m | 3 + TestsUI/ChatTester.m | 152 ++++++++++++++++----------------- TestsUI/WizardTester.m | 3 +- 3 files changed, 81 insertions(+), 77 deletions(-) diff --git a/Classes/WizardViewController.m b/Classes/WizardViewController.m index 7802a23da..af9e0c5f5 100644 --- a/Classes/WizardViewController.m +++ b/Classes/WizardViewController.m @@ -545,6 +545,9 @@ static UICompositeViewDescription *compositeDescription = nil; } case LinphoneRegistrationFailed: { [waitView setHidden:true]; + if ([message isEqualToString:@"Forbidden"]) { + message = NSLocalizedString(@"Incorrect username or password.", nil); + } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Registration failure", nil) message:message delegate:nil diff --git a/TestsUI/ChatTester.m b/TestsUI/ChatTester.m index f1e50ea67..4c9bf5c1a 100644 --- a/TestsUI/ChatTester.m +++ b/TestsUI/ChatTester.m @@ -101,73 +101,11 @@ [tester waitForViewWithAccessibilityLabel:@"Download"]; [tester tapViewWithAccessibilityLabel:@"Download"]; [tester waitForTimeInterval:.5f]; // just wait a few secs to start download - ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 1); + ASSERT_EQ(LinphoneManager.instance.fileTransferDelegates.count, 1); } #pragma mark - tests -- (void)test3DownloadsSimultanously { - [self startChatWith:[self me]]; - [self uploadImageWithQuality:@"Maximum"]; - [self uploadImageWithQuality:@"Average"]; - [self uploadImageWithQuality:@"Minimum"]; - UITableView *tv = [self findTableView:@"Chat list"]; - // wait for ALL uploads to terminate... - for (int i = 0; i < 45; i++) { - [tester waitForTimeInterval:1.f]; - if ([tv numberOfRowsInSection:0] == 6) - break; - } - [tester waitForTimeInterval:.5f]; - ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0); - [tester scrollViewWithAccessibilityIdentifier:@"Chat list" byFractionOfSizeHorizontal:0.f vertical:1.f]; - for (int i = 0; i < 3; i++) { - // messages order is not known: if upload bitrate is huge, first image can be uploaded before last started - while (![tester tryFindingTappableViewWithAccessibilityLabel:@"Download" error:nil]) { - [tester scrollViewWithAccessibilityIdentifier:@"Chat list" byFractionOfSizeHorizontal:0.f vertical:-.1f]; - } - [tester waitForViewWithAccessibilityLabel:@"Download"]; - [tester tapViewWithAccessibilityLabel:@"Download"]; - [tester waitForTimeInterval:.2f]; // just wait a few secs to start download - } - while ([LinphoneManager instance].fileTransferDelegates.count > 0) { - [tester waitForTimeInterval:.5]; - } - [self goBackFromChat]; -} - -- (void)test3UploadsSimultanously { - [self startChatWith:[self me]]; - // use Maximum quality to be sure that first transfer is not terminated when the third begins - [self uploadImageWithQuality:@"Maximum"]; - [self uploadImageWithQuality:@"Average"]; - [self uploadImageWithQuality:@"Minimum"]; - UITableView *tv = [self findTableView:@"Chat list"]; - // wait for ALL uploads to terminate... - for (int i = 0; i < 45; i++) { - [tester waitForTimeInterval:1.f]; - if ([tv numberOfRowsInSection:0] == 6) - break; - } - [tester waitForTimeInterval:.5f]; - ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0); - ASSERT_EQ([tv numberOfRowsInSection:0], 6); - [self goBackFromChat]; -} - -- (void)testCancelDownloadImage { - [self downloadImage]; - [tester tapViewWithAccessibilityLabel:@"Cancel transfer"]; - ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); -} - -- (void)testCancelUploadImage { - [self startChatWith:[self me]]; - [self uploadImageWithQuality:@"Minimum"]; - [tester tapViewWithAccessibilityLabel:@"Cancel transfer"]; - ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); -} - - (void)testChatFromContactPhoneNumber { [tester tapViewWithAccessibilityLabel:@"New Discussion"]; [tester tapViewWithAccessibilityLabel:@"Anna Haro"]; @@ -180,10 +118,12 @@ traits:UIAccessibilityTraitStaticText]; } -- (void)testDownloadImage { - [self downloadImage]; - [tester waitForAbsenceOfViewWithAccessibilityLabel:@"Cancel transfer"]; - ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); +- (void)testInvalidSIPAddress { + + [self startChatWith:@"sip://toto"]; + + [tester waitForViewWithAccessibilityLabel:@"Invalid address" traits:UIAccessibilityTraitStaticText]; + [tester tapViewWithAccessibilityLabel:@"Cancel"]; } - (void)testMessageRemoval { @@ -214,14 +154,6 @@ [self goBackFromChat]; } -- (void)testInvalidSIPAddress { - - [self startChatWith:@"sip://toto"]; - - [tester waitForViewWithAccessibilityLabel:@"Invalid address" traits:UIAccessibilityTraitStaticText]; - [tester tapViewWithAccessibilityLabel:@"Cancel"]; -} - - (void)testPerformanceHugeChatList { [tester tapViewWithAccessibilityLabel:@"Dialer"]; @@ -317,7 +249,75 @@ [self goBackFromChat]; } -- (void)testUploadImage { +- (void)testTransfer3DownloadsSimultanously { + [self startChatWith:[self me]]; + [self uploadImageWithQuality:@"Maximum"]; + [self uploadImageWithQuality:@"Average"]; + [self uploadImageWithQuality:@"Minimum"]; + UITableView *tv = [self findTableView:@"Chat list"]; + // wait for ALL uploads to terminate... + for (int i = 0; i < 45; i++) { + [tester waitForTimeInterval:1.f]; + if ([tv numberOfRowsInSection:0] == 6) + break; + } + [tester waitForTimeInterval:.5f]; + ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0); + [tester scrollViewWithAccessibilityIdentifier:@"Chat list" byFractionOfSizeHorizontal:0.f vertical:1.f]; + for (int i = 0; i < 3; i++) { + // messages order is not known: if upload bitrate is huge, first image can be uploaded before last started + while (![tester tryFindingTappableViewWithAccessibilityLabel:@"Download" error:nil]) { + [tester scrollViewWithAccessibilityIdentifier:@"Chat list" byFractionOfSizeHorizontal:0.f vertical:-.1f]; + } + [tester waitForViewWithAccessibilityLabel:@"Download"]; + [tester tapViewWithAccessibilityLabel:@"Download"]; + [tester waitForTimeInterval:.2f]; // just wait a few secs to start download + } + while ([LinphoneManager instance].fileTransferDelegates.count > 0) { + [tester waitForTimeInterval:.5]; + } + [self goBackFromChat]; +} + +- (void)testTransfer3UploadsSimultanously { + [self startChatWith:[self me]]; + // use Maximum quality to be sure that first transfer is not terminated when the third begins + [self uploadImageWithQuality:@"Maximum"]; + [self uploadImageWithQuality:@"Average"]; + [self uploadImageWithQuality:@"Minimum"]; + UITableView *tv = [self findTableView:@"Chat list"]; + // wait for ALL uploads to terminate... + for (int i = 0; i < 45; i++) { + [tester waitForTimeInterval:1.f]; + if ([tv numberOfRowsInSection:0] == 6) + break; + } + [tester waitForTimeInterval:.5f]; + ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0); + ASSERT_EQ([tv numberOfRowsInSection:0], 6); + [self goBackFromChat]; +} + +- (void)testTransferCancelDownloadImage { + [self downloadImage]; + [tester tapViewWithAccessibilityLabel:@"Cancel transfer"]; + ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)testTransferCancelUploadImage { + [self startChatWith:[self me]]; + [self uploadImageWithQuality:@"Minimum"]; + [tester tapViewWithAccessibilityLabel:@"Cancel transfer"]; + ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)testTransferDownloadImage { + [self downloadImage]; + [tester waitForAbsenceOfViewWithAccessibilityLabel:@"Cancel transfer"]; + ASSERT_EQ([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)testTransferUploadImage { [self startChatWith:[self me]]; ASSERT_EQ([[LinphoneManager instance] fileTransferDelegates].count, 0); diff --git a/TestsUI/WizardTester.m b/TestsUI/WizardTester.m index 313564fa7..3e39986fc 100644 --- a/TestsUI/WizardTester.m +++ b/TestsUI/WizardTester.m @@ -116,7 +116,8 @@ UIView *alertViewText = [tester waitForViewWithAccessibilityLabel:@"Registration failure" traits:UIAccessibilityTraitStaticText]; if (alertViewText) { - UIView *reason = [tester waitForViewWithAccessibilityLabel:@"Forbidden" traits:UIAccessibilityTraitStaticText]; + UIView *reason = [tester waitForViewWithAccessibilityLabel:@"Incorrect username or password." + traits:UIAccessibilityTraitStaticText]; if (reason == nil) { [tester fail]; } else { From 683fc0de03ef948fe9748809fe4ae2dc925bf60c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 14:42:19 +0200 Subject: [PATCH 40/46] i18n: update translations and modify prepare.py to NOT push translations with make push-transifex (we only change sources) --- .../Base.lproj/ChatRoomViewController.strings | Bin 3344 -> 2792 bytes .../Base.lproj/DialerViewController.strings | Bin 4450 -> 4454 bytes .../DialerViewController~ipad.strings | Bin 4668 -> 4672 bytes Classes/Base.lproj/WizardViews.strings | Bin 19238 -> 18746 bytes .../LinphoneUI/Base.lproj/UICallCell.strings | Bin 9532 -> 9820 bytes .../LinphoneUI/Base.lproj/UIChatCell.strings | Bin 1480 -> 1480 bytes .../Base.lproj/UIChatRoomCell.strings | Bin 1798 -> 2580 bytes .../LinphoneUI/ar.lproj/UICallCell.strings | Bin 9500 -> 9732 bytes .../LinphoneUI/ar.lproj/UIChatCell.strings | Bin 1464 -> 1464 bytes .../ar.lproj/UIChatRoomCell.strings | Bin 1764 -> 2546 bytes .../LinphoneUI/de.lproj/UICallCell.strings | Bin 9614 -> 9846 bytes .../LinphoneUI/de.lproj/UIChatCell.strings | Bin 1514 -> 1514 bytes .../de.lproj/UIChatRoomCell.strings | Bin 1824 -> 2606 bytes .../LinphoneUI/fr.lproj/UICallCell.strings | Bin 9690 -> 9922 bytes .../LinphoneUI/fr.lproj/UIChatCell.strings | Bin 1504 -> 1504 bytes .../fr.lproj/UIChatRoomCell.strings | Bin 1812 -> 2618 bytes .../LinphoneUI/ja.lproj/UICallCell.strings | Bin 9080 -> 9312 bytes .../LinphoneUI/ja.lproj/UIChatCell.strings | Bin 1402 -> 1402 bytes .../ja.lproj/UIChatRoomCell.strings | Bin 1628 -> 2410 bytes .../LinphoneUI/nl.lproj/UICallCell.strings | Bin 9730 -> 9962 bytes .../LinphoneUI/nl.lproj/UIChatCell.strings | Bin 1514 -> 1514 bytes .../nl.lproj/UIChatRoomCell.strings | Bin 1868 -> 2650 bytes .../LinphoneUI/ru.lproj/UICallCell.strings | Bin 9644 -> 9876 bytes .../LinphoneUI/ru.lproj/UIChatCell.strings | Bin 1480 -> 1480 bytes .../LinphoneUI/zh_TW.lproj/UICallCell.strings | Bin 9504 -> 9736 bytes .../LinphoneUI/zh_TW.lproj/UIChatCell.strings | Bin 1480 -> 1480 bytes Classes/ar.lproj/AboutViewController.strings | Bin 1430 -> 1432 bytes .../ar.lproj/ChatRoomViewController.strings | Bin 3342 -> 2810 bytes Classes/ar.lproj/DialerViewController.strings | Bin 4436 -> 4438 bytes .../DialerViewController~ipad.strings | Bin 4656 -> 4658 bytes Classes/ar.lproj/WizardViews.strings | Bin 19042 -> 18548 bytes .../de.lproj/ChatRoomViewController.strings | Bin 3410 -> 2830 bytes Classes/de.lproj/DialerViewController.strings | Bin 4534 -> 4536 bytes .../DialerViewController~ipad.strings | Bin 4756 -> 4758 bytes Classes/de.lproj/WizardViews.strings | Bin 19632 -> 19138 bytes .../fr.lproj/ChatRoomViewController.strings | Bin 3426 -> 2846 bytes Classes/fr.lproj/DialerViewController.strings | Bin 4534 -> 4536 bytes .../DialerViewController~ipad.strings | Bin 4760 -> 4762 bytes Classes/fr.lproj/WizardViews.strings | Bin 20222 -> 19732 bytes .../ja.lproj/ChatRoomViewController.strings | Bin 3226 -> 2690 bytes Classes/ja.lproj/DialerViewController.strings | Bin 4372 -> 4374 bytes .../DialerViewController~ipad.strings | Bin 4580 -> 4582 bytes Classes/ja.lproj/WizardViews.strings | Bin 18154 -> 17660 bytes .../nl.lproj/ChatRoomViewController.strings | Bin 3486 -> 2926 bytes Classes/nl.lproj/DialerViewController.strings | Bin 4522 -> 4524 bytes .../DialerViewController~ipad.strings | Bin 4778 -> 4780 bytes Classes/nl.lproj/WizardViews.strings | Bin 19542 -> 19048 bytes .../ru.lproj/ChatRoomViewController.strings | Bin 3406 -> 2854 bytes Classes/ru.lproj/DialerViewController.strings | Bin 4500 -> 4502 bytes .../DialerViewController~ipad.strings | Bin 4726 -> 4728 bytes Classes/ru.lproj/WizardViews.strings | Bin 19656 -> 19162 bytes .../ChatRoomViewController.strings | Bin 3190 -> 2692 bytes .../zh_TW.lproj/DialerViewController.strings | Bin 4382 -> 4384 bytes .../DialerViewController~ipad.strings | Bin 4600 -> 4602 bytes Classes/zh_TW.lproj/WizardViews.strings | Bin 19238 -> 18744 bytes Resources/ar.lproj/Localizable.strings | Bin 30968 -> 30238 bytes Resources/de.lproj/Localizable.strings | Bin 33274 -> 32594 bytes Resources/en.lproj/Localizable.strings | Bin 31690 -> 31018 bytes Resources/fr.lproj/Localizable.strings | Bin 33028 -> 32336 bytes Resources/ja.lproj/Localizable.strings | Bin 28288 -> 27782 bytes Resources/nl.lproj/Localizable.strings | Bin 33192 -> 32382 bytes Resources/ru.lproj/Localizable.strings | Bin 32186 -> 31446 bytes Resources/zh_TW.lproj/Localizable.strings | Bin 31598 -> 30926 bytes .../ar.lproj/Advanced.strings | Bin 1042 -> 1042 bytes .../ar.lproj/Audio.strings | Bin 1576 -> 1418 bytes .../ar.lproj/Call.strings | Bin 580 -> 710 bytes .../ar.lproj/Network.strings | Bin 892 -> 1036 bytes .../ar.lproj/Root.strings | Bin 1502 -> 1448 bytes .../ar.lproj/Video.strings | Bin 550 -> 808 bytes .../de.lproj/Audio.strings | Bin 1714 -> 1528 bytes .../de.lproj/Call.strings | Bin 686 -> 800 bytes .../de.lproj/Network.strings | Bin 962 -> 1102 bytes .../de.lproj/Root.strings | Bin 1566 -> 1502 bytes .../de.lproj/Video.strings | Bin 612 -> 870 bytes .../en.lproj/Audio.strings | 3 +-- .../en.lproj/Call.strings | 1 + .../en.lproj/Network.strings | 5 +++-- .../en.lproj/Root.strings | 3 +-- .../en.lproj/Video.strings | 3 +++ .../fr.lproj/Audio.strings | Bin 1622 -> 1460 bytes .../fr.lproj/Call.strings | Bin 640 -> 770 bytes .../fr.lproj/Network.strings | Bin 914 -> 1042 bytes .../fr.lproj/Root.strings | Bin 1580 -> 1532 bytes .../fr.lproj/Video.strings | Bin 618 -> 914 bytes .../ja.lproj/Audio.strings | Bin 1626 -> 1448 bytes .../ja.lproj/Network.strings | Bin 902 -> 1044 bytes .../ja.lproj/Root.strings | Bin 1424 -> 1382 bytes .../ja.lproj/Video.strings | Bin 584 -> 842 bytes .../nl.lproj/Audio.strings | Bin 1626 -> 1448 bytes .../nl.lproj/Call.strings | Bin 624 -> 738 bytes .../nl.lproj/Network.strings | Bin 902 -> 1044 bytes .../nl.lproj/Root.strings | Bin 1472 -> 1430 bytes .../nl.lproj/Video.strings | Bin 584 -> 842 bytes .../ru.lproj/Audio.strings | Bin 1666 -> 1488 bytes .../ru.lproj/Call.strings | Bin 604 -> 718 bytes .../ru.lproj/Network.strings | Bin 922 -> 1072 bytes .../ru.lproj/Root.strings | Bin 1548 -> 1506 bytes .../ru.lproj/Video.strings | Bin 628 -> 886 bytes .../zh_TW.lproj/Audio.strings | Bin 1626 -> 1448 bytes .../zh_TW.lproj/Network.strings | Bin 902 -> 1044 bytes .../zh_TW.lproj/Root.strings | Bin 1456 -> 1414 bytes .../zh_TW.lproj/Video.strings | Bin 584 -> 842 bytes prepare.py | 2 +- 103 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Classes/Base.lproj/ChatRoomViewController.strings b/Classes/Base.lproj/ChatRoomViewController.strings index 93c9cfce9417d35e1300e9b7d6aa24f4a0aa307d..fcaf31239ab71e43eb1b156e736de285dc64d8ac 100644 GIT binary patch delta 11 ScmbOr^+I%m5Z7cYo@)RZWdtJt delta 242 zcmaDMIzeiK5Ep*{LlHwhLpqR5WhiDSo~+GoZ5_%`z>otJO=L)6Pyo_JKr#hLmowxc zi5H;iWXJ@n$eUcqsVHp1pu}Je)T70q&%gy_n=_b9R%9}y$lO3S)rksr+|EEpH^tZCmV5X0{|K%FQ@%PI{6s8!bAm$%{Gi`0syAi3G@H} delta 13 UcmaE+^hjw!(ZrIvjbDlc05G-&xc~qF diff --git a/Classes/Base.lproj/DialerViewController~ipad.strings b/Classes/Base.lproj/DialerViewController~ipad.strings index a3c0320f63c078b330a30b39690667a3b2a218d4..31b19f8b623f18ad7ec00a80bb0bcef85e88393e 100644 GIT binary patch delta 27 gcmdm^azJH55o6xO!g>%PI@yg)VWNV>VjD(50FW{W_5c6? delta 13 UcmX@0vPWe?(ZrIvjbD5O0WAjxOaK4? diff --git a/Classes/Base.lproj/WizardViews.strings b/Classes/Base.lproj/WizardViews.strings index 25d4378364189fcb3745faead1e97ed1f5f15062..8b6aa3f3b3004d58c46a2ef0c0b3ef09b5618e26 100644 GIT binary patch delta 55 zcmZ2Bjd9l`#tkkqj0%$#Wz8p7$=Cr|iEOHqH^`+;PLUDY93d;9HCceyWwHRj*5o~2 L7MuThYA^x->roMb delta 242 zcmdlriE-I9#tkkqlP8FB?v@8EA%S v8G|{44}&g4I71+iEMo`*@|75@859__81xyqfNU%(CMzn4au|TsaWMb@9U(QF delta 69 zcmccPv&U=08TrXZG76J_$j59>P?*3t`4flSWI3gX$w>;UCL1U}nJlCnHn~bgVe%$1 Xx5*z=B*2PIR8u&t7?c>S8Mqh##_$)t diff --git a/Classes/LinphoneUI/Base.lproj/UIChatCell.strings b/Classes/LinphoneUI/Base.lproj/UIChatCell.strings index 7b10fdec38febad496e9b5db3693b4eb6e2805ff..679cbe7906b0fb183c01566518e68ec81810aca5 100644 GIT binary patch delta 26 icmX@XeS&*K87rf~ delta 26 icmX@XeS&*K87rglN%izu62_#d261faY z4Awx!S`7LOTtGH96?zj5RVPni;gQB;`s9m@szB#V=3$m2=nPYAmJoEt3%5c6aSCLMkkhJ1!{hCGHGAf3pNGC7_}esUJG#6%;N$-9`i1kj`zHs4|5 zV43`g$pEBT))}ZJk0F^M6{uZ-p@g9b%r9n01Bw)Zj51GSaA(M1&}Hyu@C1^nK$%XzHs2w^vvVzYsu8z$E?E34qQ9%Kd=0{|%d BL8t%# delta 16 Xcmew){DgOd5c6aiPPxruEL)fXGTsFi diff --git a/Classes/LinphoneUI/de.lproj/UICallCell.strings b/Classes/LinphoneUI/de.lproj/UICallCell.strings index 0c4232ce20669ca1b648fbf6592d69d403902f85..3329cc3f66db71787f129646ec8e8d3d0ea4ab1f 100644 GIT binary patch delta 172 zcmeD4{^qlRLxEd?L4(1KA%G#6L38p%PQ}d{3cncnL4t-1rZ9=kib|YJ=z^04dE_U1 zsBA+wVX~ZR!Q@%OdXpb;3osghR2i2sm^1h==rV*e1Omx2hA<#siNTsdfkBHwpMeX= R#!xZ2S4f=00IZ6O0RXHaAC~|C delta 45 wcmez7)91Z`Lt*kHPKC`T3cna93-QQpj!}9AW=xJ#wwSy|r4A%JIZU+x0DWf<_W%F@ diff --git a/Classes/LinphoneUI/de.lproj/UIChatCell.strings b/Classes/LinphoneUI/de.lproj/UIChatCell.strings index ec85a65fab04b1c80794f5a56b57412fa989af7e..e3f49202f95f977875b05f00dcfd26d109c707b5 100644 GIT binary patch delta 13 UcmaFG{fc|T3|2;i$un640Viq%>i_@% delta 13 UcmaFG{fc|T3|2w=yfM;I$p>11<&tMrJt< delta 12 TcmZ1{vVd=c1oP&9%p5EL9h?LF diff --git a/Classes/LinphoneUI/fr.lproj/UICallCell.strings b/Classes/LinphoneUI/fr.lproj/UICallCell.strings index 528217606770d9dc33d1b85fd972e64e8cef4d53..477fc2fd7695170d526011d03a55fda104a90b67 100644 GIT binary patch delta 172 zcmccReaLr1k^;8^g9d{eLjXfCgXZQ$1#u>RkbohBDNJzkMP~WU)0CbuVw0FWOJy6f z36m2Q6eky`W=*c*)tg)(B*16@(r#MDV9wyfpvw@>5C|m87{Y*jB?fB-1qLk!eFiQd Q8;gp`=T*enK&rSH0ML#isQ>@~ delta 45 ycmX@)d&_%6k^-aE diff --git a/Classes/LinphoneUI/fr.lproj/UIChatRoomCell.strings b/Classes/LinphoneUI/fr.lproj/UIChatRoomCell.strings index 53010b51d8d862f3e8a8e526a6b541f7a5c9fdc2..de063b5980e6e03f8e5d4c123a62637c424dd623 100644 GIT binary patch delta 339 zcmbQjw@YM$0P{p6J>GnVa)vyH9EN;`M23{fp3LSGjZ`MjW8s>-fLUx3qsl}Dq0Iu! zEG(1R8097^*vUErmE|!cGo%8wC@_>T6oL803~4}-qKTFA=4lM>3>gf%4BiZ$Kr$65 zk;|aOU=38P#h}l?1!QAWp*PV`6=bWrBhd6bhEkyEK=Xi_Ks1Iu3?&o)s{&m%S%6uN Ypo>hg*+ZZTE<|`;KQKH5Y7+?B+D4WfP5teYX$`dEe3rC TE+89=iph;aq8tWbbzBSp^8X~+ delta 49 zcmaFh@xyI{kKE)-VhWop$qB4d06B~WWB>pF delta 17 Ycmeyx^^0qR1}mfS$qB4d06C`xX8-^I diff --git a/Classes/LinphoneUI/ja.lproj/UIChatRoomCell.strings b/Classes/LinphoneUI/ja.lproj/UIChatRoomCell.strings index 8c644d98eca2be5332ec39d49ac596f1b41c6b6a..1c2582d0b28fc9152368034a9075c5dc96b5e6fe 100644 GIT binary patch delta 294 zcmcb^^GayLH>SyKOgfWAm<1*qFq=(oVbTM!Hy>b{!#wea+(ZRCS!aeshCGI3hE#?e z1_g!^h9WS(m>~@)QZ!kgS>7~_!JQ$4L6^as!4pWP0%dX;lo+gmsS;ZnA4a6DBA^y diff --git a/Classes/LinphoneUI/nl.lproj/UICallCell.strings b/Classes/LinphoneUI/nl.lproj/UICallCell.strings index ffdb4d952ac62746bcb634944babfae94ca58cf0..bc7116b5fb41a9f74bd3267ca19efebecbae9e57 100644 GIT binary patch delta 178 zcmZqjdF8tyNr78|L4(1KA%G#6L34AWf+iC`NWhT66ec*ikwbp+EJcgW50rK>VwGH_ zY%%$RN*%IElM@vbC-B06870|3YPc8x5)&kj delta 53 zcmaFm+vKw$NrBO7awCWQ<~{`urpZkla+8-ST5SHKw2KkUIi_qeSw^)EqGs|j)e-;= C91|M= diff --git a/Classes/LinphoneUI/nl.lproj/UIChatCell.strings b/Classes/LinphoneUI/nl.lproj/UIChatCell.strings index b9b54b4d4c91dc37e878d5445a074689f31cbf4b..549ac9f147a5301b7a78f5b2555a7ea1c8837732 100644 GIT binary patch delta 21 dcmaFG{fc|T3|2;i$^MM;lkc!dOuoP>1pryL2Y3Jg delta 21 dcmaFG{fc|T3|21pryy2YUbj diff --git a/Classes/LinphoneUI/nl.lproj/UIChatRoomCell.strings b/Classes/LinphoneUI/nl.lproj/UIChatRoomCell.strings index 26f3304fd2ea0013126668b7bcf57adbe1c745d6..254e8b072379b525431a2cf35788c01c6026c980 100644 GIT binary patch delta 334 zcmX@ZcS~f00P|!KCLMkkhJ1!{hCGHGAf3pNGC7(_esTu0#NJ#vI<`Rf&Ib7002DMLE8WT delta 12 Tcmca5a)xh%0Q2T=%r-0lA#?XYgUrWe8^o1d?S8VL-kTgEfN!gBF860~e5uMaATY M0-_woV0By!0OnaDTL1t6 delta 45 vcmbQ@yT*HijlyIhUWLsW3U3%EtEkCME>N`Cyh~{vgfmTL8%TC?g=!7}c4rUZ diff --git a/Classes/LinphoneUI/ru.lproj/UIChatCell.strings b/Classes/LinphoneUI/ru.lproj/UIChatCell.strings index 7b10fdec38febad496e9b5db3693b4eb6e2805ff..230842181a38be11cf4d50043dc0e3111a47311c 100644 GIT binary patch delta 17 ZcmX@XeS&*K87rf~b@Vz6dVV9;XFXW#;| RF;q;xC@#)n09M7t008xuBnJQh delta 45 zcmeD1S>Ux{gZ$(}JPMod$iHEnEW{+Y`J3W1Fk>>8%C^Y?s%(=_@JLO5qmlyvs|OLP diff --git a/Classes/LinphoneUI/zh_TW.lproj/UIChatCell.strings b/Classes/LinphoneUI/zh_TW.lproj/UIChatCell.strings index 7b10fdec38febad496e9b5db3693b4eb6e2805ff..230842181a38be11cf4d50043dc0e3111a47311c 100644 GIT binary patch delta 17 ZcmX@XeS&*K87rf~IE diff --git a/Classes/ar.lproj/ChatRoomViewController.strings b/Classes/ar.lproj/ChatRoomViewController.strings index c1bade640e780b11ba6a968165d53845edf8b8bd..7f67666e7726042b229535aef930bd5a9ddafce8 100644 GIT binary patch delta 11 ScmeB^`X#!-gln<~&oKZR*921l delta 225 zcmew*+9$Qago{6bp@<=$AstAjG88iuPYz_awhm<|V8{WACNiWjC;;gqAejQB%Ng>J z#0yY$GGqc(u_-X9v$?Qo zvAMAs0eLP!zA~E!RMe2oapHN)$tzg(I1_;uCIcOo12xtZ!&p<0v7D+vBdple*%T*U ORGmD7Rba9U*ERs7nkxJN diff --git a/Classes/ar.lproj/DialerViewController.strings b/Classes/ar.lproj/DialerViewController.strings index dd8e8fb99c40d74f3228289f24467cec124e0602..0d050fc7f62e942f6eb014e2c66d15ddcbf70813 100644 GIT binary patch delta 12 TcmcbjbWLeO5o6xQ!p8ytB)0{1 delta 10 RcmcbnbVX@G(Z-TT0stJe1qc8D diff --git a/Classes/ar.lproj/DialerViewController~ipad.strings b/Classes/ar.lproj/DialerViewController~ipad.strings index 25b63bc2857ca5dc7f247d61ab4b91d91fa04052..aaf670cba80d323ffea4558e06ea414e3094c651 100644 GIT binary patch delta 12 Tcmdm>vPoq^5o6xQ!u^5(A%F!A delta 10 Rcmdm_vO#4+(Z-T}f&dx?1fc)` diff --git a/Classes/ar.lproj/WizardViews.strings b/Classes/ar.lproj/WizardViews.strings index db03ac1240bbcc6a74cfae6839b316982fda237e..497aa319de000ed62a0dc5bba1133de3f770d043 100644 GIT binary patch delta 37 tcmaDfh4IS-#ti{7j0%$tIpsI!$(U(PHjr|e{Ekm+@()jo%~qZoi~s}D4F~`L delta 222 zcmew|f$`B4#ti{7lLh1zHW$g5XiaWV5SqM?U57V-p_HMBA(LlRJ2m%)O;o1u(BiNTsdfkBHwpMeX=#-d{4MMHiRqZm>rAGA{iT4O*hD<`FAoLL delta 266 zcmeAZyCk*2fr~$Yp@<=$AstAjG88iuPYz_awhm<|V8{WACNiWjC;;gqAejQB%Ng>J z#0yY$GGqc(UaaeE>qeHLL&t diff --git a/Classes/de.lproj/DialerViewController.strings b/Classes/de.lproj/DialerViewController.strings index bbc5e3bbd5c0165455786a1224244ebf0f46374c..4feccb95b636290720f0bdfc44a0366b4a872921 100644 GIT binary patch delta 12 Tcmdm{yhC|H5o6xQLRUcmAp8WL delta 10 Rcmdm?yiIvR(Z&)NK>!(T1Tg>r diff --git a/Classes/de.lproj/DialerViewController~ipad.strings b/Classes/de.lproj/DialerViewController~ipad.strings index 2802cfdb5f9d03db6ee279c15b04d17626927ee6..1455b6eb65351f86e30290085b2ec8d8a6b18010 100644 GIT binary patch delta 12 TcmbQDI!$##5o6xQLS-QU9rXk~ delta 10 RcmbQHIz@Ft(Z&)bApjQU1JD2f diff --git a/Classes/de.lproj/WizardViews.strings b/Classes/de.lproj/WizardViews.strings index 924c057712df48f8d8738327a7ef5e3aedef967a..135adbe94ad86a0eb68b0849e1bf4ca11ae6fe1d 100644 GIT binary patch delta 33 pcmdlmlkw10#tkyEj0%%CDkyHYk=>>}`Gd5? delta 217 zcmX>!m2tyN#tkyElmEz?Z4QxLpgq~a(vCNPp_HMBA(otJO=L)6Pyo_JKr#hLmowxc zi5H;iWXJ@n$eVnSNnYHX!GuAH!5XMbi$R}(3&;kE=uI?KogBc#6^dphL?hUWQXpBv z@DgarONKI_gNlGoN@d6e;yj?ZK3p!DAp_{RBA~P3vJ)?wPZnX(;dTZ}!(T1Tg>r diff --git a/Classes/fr.lproj/DialerViewController~ipad.strings b/Classes/fr.lproj/DialerViewController~ipad.strings index 9ed2b307ceeea32766d427e625dc199a274546b4..87fdedcf57aabeaeb0bab7092b68f923cc6bd3f9 100644 GIT binary patch delta 12 TcmbQCI!kpz5o6xQLUkbk9#sTM delta 10 RcmbQGIzx3r(Z&)rApjRP1Ka=r diff --git a/Classes/fr.lproj/WizardViews.strings b/Classes/fr.lproj/WizardViews.strings index a848126ff6c8c48f00fdd013572656adc826ac8c..ae67dba8adf3fd4ae423f09825bc30cdb7a6e893 100644 GIT binary patch delta 33 pcmex2mvPE0#tpY*85JgPlvkYmKu&D4fSiHulL+a#-UW&$^3fFTDcn#hpCpa7(cfMg1gE@#L? z5-&j2$&d+DkvF-KOvrR!}bFDRa3^Z%E Q!E1xb6IfIx@8LWK0CIvrAOHXW diff --git a/Classes/ja.lproj/DialerViewController.strings b/Classes/ja.lproj/DialerViewController.strings index c838177f7b83083741e24d25534054111d05fa8c..7e66f6fbc9f7920d2b7116f0d6e5d5dced17648f 100644 GIT binary patch delta 12 TcmbQDG)-wj5o6xQ!o>mr9=8Ow delta 10 RcmbQHG(~Ab(Z-TR0st4Z1V{h? diff --git a/Classes/ja.lproj/DialerViewController~ipad.strings b/Classes/ja.lproj/DialerViewController~ipad.strings index 95ad97363d344d38f77306f8a320d21746be90d6..878b45f090d29d419f5d4ec1f13fcb9b9c0cdf24 100644 GIT binary patch delta 12 TcmaE&{7iX55o6xQ!eT)HB}@e< delta 10 RcmaE+{6u*|(Z-S@K>!^E1iJtL diff --git a/Classes/ja.lproj/WizardViews.strings b/Classes/ja.lproj/WizardViews.strings index 7e1a68a70a83ac485ec258888df44598497c981d..75bbd975a4a73b616a433d81d72ebc0a3cffaee5 100644 GIT binary patch delta 41 zcmV+^0M`HNjRE|L0kEhV0U(p%9wC#U8y2(P8dfNiU>`)25DqGnghn{C%0(anU`-Eu delta 226 zcmey<$@r?5al;C!$pt)elNU%!YF=YS% diff --git a/Classes/nl.lproj/ChatRoomViewController.strings b/Classes/nl.lproj/ChatRoomViewController.strings index d917cace1e0f439120f8c83256f243b33d2187a1..72c87d738d860e48ffd66b2954f118e652813f2b 100644 GIT binary patch delta 15 XcmbOy{Z4E{2iN3TtOAoy@LU4`Gw}w0 delta 259 zcmaDSHcxs(2N!<;LlHwhLpqR5WhiDSo;;Dm+B%e>fFTDcn#hpCpa7(cfMg1gE@#L? z5-&j2$&d+DkvI7xqr9j&g9(EYgEdf>7K1(m7my7UnXJfWXdebt12V4!Xk#MKv~-}F zGB8Vlp%l&5G)!A3Co-8&7GTlgb_VN72D&*1YNIKJjiw+Q`5l3_!$i1PuTH diff --git a/Classes/nl.lproj/DialerViewController~ipad.strings b/Classes/nl.lproj/DialerViewController~ipad.strings index b4cb3d935d4d85862703f8b541832f13e51a27fc..acb2bdc9c12506a9d53b1b1dcf278fe88532187a 100644 GIT binary patch delta 12 TcmZ3bx<++E5o6xQLQ5e4AO!?} delta 10 RcmZ3Zx=M9I(Z&)BApjVj1QGxM diff --git a/Classes/nl.lproj/WizardViews.strings b/Classes/nl.lproj/WizardViews.strings index c33ea78389d04ec00a6f359a021c8948ed49964a..a61cbcce957dae7905a7e58fe678b0232253bb10 100644 GIT binary patch delta 37 tcmcaMgYm@_#tj^@j0%$jl@%v*$%$>Yll9V`>>%PYxq)A6^E0mkMgZ)%3@QKs delta 230 zcmaDch4I=9#tj^@lO4?ECUeP2Y<7_K(w1w3NY< zp@2b`Aqgn1%V5Fa%}~am#9+;!z@WvT&%gy_V^J~jq9H$uQ4Fb*7qW#?%lOHHZps+u VH_F;hp1`X!xq)A6^AC>#MgWYgF=zk) diff --git a/Classes/ru.lproj/ChatRoomViewController.strings b/Classes/ru.lproj/ChatRoomViewController.strings index 880056bf079c15eca7aae69a561b9039b66da7ed..00213048d4349f2696e8b76a4f809fea223cf988 100644 GIT binary patch delta 15 XcmX>nwM=Y70N3PIYzmWS@N5GBF!2Td delta 246 zcmZ1`c1~(T02hA%LlHwhLpqR5WhiDSo*d6^Z5_%`z>otJO=L)6Pyo_JKr#hLmowxc zi5H;iWXJ@n$ea9;QC{4f!GuAH!5XMbi$R}(3&;kE=uI?Koh-n?WiHR+z+%T@3?xli z9Dz`Q!JNea%y(unXR%_jV9{rA1kwg9?m)H?khTTV{*y1Vm`~ovsKf0HbXXokGSI;} kAnSz98BEcwn>>-lm|Kp;iNywJ2T=Fqvn-mE1GugM02`?;IRF3v diff --git a/Classes/ru.lproj/DialerViewController.strings b/Classes/ru.lproj/DialerViewController.strings index 9eab509a01cac2bc67dc5123d6f7bbbf6adbadd5..805ac8272b845b6a2ff90469e40d8d3a3bd05a25 100644 GIT binary patch delta 12 TcmbQDJWY8*5o6xQLS;b!9n1tc delta 10 RcmbQHJVkjz(Z&)bK>!xT1Iqva diff --git a/Classes/ru.lproj/DialerViewController~ipad.strings b/Classes/ru.lproj/DialerViewController~ipad.strings index 5f7423174443002b278be81653889a052bd4af7a..ad8ebdf51aa37566950b4d158b9366ca8762fff6 100644 GIT binary patch delta 12 TcmeyS@xlkwJ6#tjo>7!@WjlvdolLB>mGa)Ol0WC4Dy%@N)Oi~!p$3#kAA delta 240 zcmcaLmGQ((#tjo>COgP0Ozx2t+k8UCL}&5_HlfK6*mZaV7)lw67?K$>7!nzZCkIL> znwBznG88cAG9&@Tbr~!eycx{U)*D7$<)KLlHwhLpqR5WhiDSp8S{1+B%e>fFTDcn#hpCpa7(cfMg1gE@#L? z5-&j2$&d+DkvBP>Szgqf!GuAH!5XMbi$R}(3&;kFO#aAf$j9ZkIY2Cl+mEx~Xu`6% w$rD)2CjVg9;dTaEmB)|_bV3f)08)Tnp~V1!_~79Kfb9`5EUt0N`UTVgLXD diff --git a/Classes/zh_TW.lproj/DialerViewController.strings b/Classes/zh_TW.lproj/DialerViewController.strings index 1412c98fca9cacdd34273c5cabd9ad070ed50bf9..957c0c68764cc432e94deeba13974d59b2579519 100644 GIT binary patch delta 12 TcmbQIv_NS>5o6xQ!nFbbAEyM< delta 10 RcmZ3WG*4+l(Z-TB0st6%1ZDsL diff --git a/Classes/zh_TW.lproj/DialerViewController~ipad.strings b/Classes/zh_TW.lproj/DialerViewController~ipad.strings index 556597fc71c5a95a37eff49145c7945609a1786a..cc89bfe55bc4c3c80ce30ec0173765e91506a3af 100644 GIT binary patch delta 12 TcmeyN{7ZR45o6xQ!gfIbCoBbI delta 10 RcmeyR{6l#{(Z-TCK>!|=1or>{ diff --git a/Classes/zh_TW.lproj/WizardViews.strings b/Classes/zh_TW.lproj/WizardViews.strings index 25d4378364189fcb3745faead1e97ed1f5f15062..a71b3edde7f2e9c2c2f3e615bd779d677927e307 100644 GIT binary patch delta 37 tcmZ2Bjd8~$#tkkqj0%$#Wz9EN$-L8=EWqnBS%6<_@*XdX&Hp?#7y%6&B$F6YCnvInQqA;2PGx=+ YmjcbdXqq`$fM09!IS-4?0v;NS02DYd5dZ)H diff --git a/Resources/ar.lproj/Localizable.strings b/Resources/ar.lproj/Localizable.strings index 315cda811c0e35cea4d55498f6be3dcb85cf5369..c6362341a2c29d66319cc167a609fd2c51bc5358 100644 GIT binary patch delta 1260 zcmb_cOHWfl6rM|Eq&#e`iaZ1_E%mmAz5pSRnDA(URzy%kVk!m-LK~$eP*E4^#swk9 z7|zBRqOM%I0B6I(7~T34OiXa)BZi=HVT=pE8QUsdo93qX%=ymw&f}Z=3!w6SgN|qtDUkefZ9|CQCUQV!D0ZLQnheh_(I}PQ&RcS{rI9)7cC}wt$*4GPjsGwNQeM z1hEC#PT@v2&W(%iv6rR;X*P$xq(D<_30+-bNqRh99n{fV0v_45%$Nmy*gpY7S3)g8T?xk)>-mA0G?!`RmVG!ueG61OyiHr#1i zPFkruQu@ad%gHSh*;6jRSmieV^60D+St2;|sztff)f<^B5nHM2T3ram z_~CQ_B&8rFng#N{9F(@_S7JG&k(cV4D(-QXfGnjH3QSVeU1H84YJ_EI$5D2op8L?NllxIb zo&ju4M-ar>46oEYyn{E8X1`tizZw}f^>_aIf90=7ovy=~#S2HLfi{Y2sW{k=+bX7u z?{j)vSx#$)e%#iU81n$hFq_d)#STzGN(0>tFpdCi8ajHxISMwS_yQczBdw_9G{3-m z_$Ab~pth5{crOp~%k;@rRTki9z{5!(mUDD-85=@m2l*-@RpZDyiMna5gF(76WhWx+ z-4Tja6`1{~nnW!*#E(@UO!Tm>RBYDG8!6Z6r)+m2ZF#L?!0o`VTkqvdD3xRH)9H}3?Z35m;fUDm%Nm7eU_rSXWihOjPN1YP&2H$V zCSX-{UGzwD$`J=opoWUh>U{z=pl+ipvZ-0>Oi#0LcEc8g4Vsqb{@7) zG%P)?N|=LC+)xgu)c8f-OsnPr$`0m;H&=H}<}2t7qoAEU2Tc!o>88;_>zZ2>M^i^A zHd?8_nBAE5@mMX?a-(xzRv4#cS! z@gTYf3Npcy?CAV^@a%bqAf9$o@GJu_B4hYon3IkjB_#iU-h03Q?<4vBNdCMgz4OQi z$6yj_(1d9LD95 zC&C%Yw&B-C2d-Qh^s8`-?AWCKd45!U%FYF&7Tl$yIAs$Wr1lONnAAH5RMO0@*$u-i z`aUM;>ys*l#a$K3gk&)$9zD>B^;uSxrRQ4{NSb#io@U5+;gE=X%AG@!b<2qtXNgVY(m=K!pr;U(;}}b-ZiK zE+NJ#xDuAE2k5JI;QU}7ok|!(M*@G}g;VME;D^aWXL2qp|IsB#rw9Qf>>59`f`LT|qC{Q)9S B?L~W z!5{e4b591@_tHbpJw#6-6cM2y5fOp(7A2i?)n)||m&-lhcmDj&?|069wdweF$N9Lz zi3R5abh>JB@2nC!Dtd(~43QHlaZOlc7qBs+%lEFiO1vqlRWZ8ip*JStcwIV-m~vT; z?{RwZBpg2UceX~g3Zf`7SoUk^4Jz_uaKTw`(IvY~kr8RKRr=;co@}-XVn*nwZr$&( zC@Li^EQcf2ePmk{k)s#`8||U`emmC?Hz?j9pGFq9{9Pn%524_ZKh3bwe<508=1;Wv zZ)m&ZxJ6`C@t??YHaw@Gx6aozEm|loNy$uen(S?wWSP`{kw~YgX%o@PNVY6;AKh)y z%83%?vRIZ~iyP4?J8qLMd($L^N;yTUs}j=Id6dp+LS~8CpX3Od$rYTcb9;2EY!dd@ z+9tFsL-XbZ0u}v!a5N^ zTbGLNlNtHBYcYVSfrDsh8izXQ#{EQ%^d-hTc-OCBY1rqY0by+-vUjJy0dYYLi&p&T zPf7pCLbW`7^`YaOM*U9{W75TDW71BtR$B`4(DULZu}S?}fSk=PPSwtcL3&sLUKW9?ZLUM${wo&!hiuYWUIAOa?k;^8}N9lDrBGX$+Y_ z&N3h?Z?eC#5mF?q4vu|=@RP5$Q(Nh>VH^eCkZjLF);|2h-4t7`o delta 760 zcmbV~OG^S#6vxl_Of4CiAO+3Q3ZgVi>yE?7lJJsUn%)WXI!)~+O%j9!D-RL zUC}~ZR0FMBwTSuh*rlK=L4{K2pm$~zw!#U@Fe)mqJ#oRtI=g$o8Yff=e>%@au zvvvq(a6;?Gv*8#%GCJ(l^I;dKNN808OcJU{-!ua4X*!DcYMgR8 z0{`lO_nU%eo;*b;sJlp)@o_1iaV&>9d4B_B4kyJJVkj@MZ(@Dl~lEI{yB>A5QJ5jgAgsAG6jMa z+D3{}7v;YH>^{+S=meul&`!rKH>} G)GTi;;

h diff --git a/Resources/fr.lproj/Localizable.strings b/Resources/fr.lproj/Localizable.strings index 80a3c5ce68351ab7d2acfc33eb383bf93f588804..7396b41112574e0f3862bbf191c4b23b33c78715 100644 GIT binary patch delta 536 zcmZ8dJ4*vW5T3jEj)BBrBqDeQHAOT&KqQ4=EeeTP#X^%yqNjP8%SCJyMJxnCm|jGz zC9q&&qrX7xwD1quh*($!^xHd-D8n$jv$Nl0j*rx*hEo4h#?xexNqZEf5NR}r4ABV9 zqh`^sqLxTUSX8Dro=U88+||PG$}N8=ZG5c`C{eywV?3Qmin!~tRh)Ldw)0E1o4fo2 z?lOL5DUYnM$4c>|w~gbz4x#qcRq+tG=n|iyyB={fbFO%FFjWv)uvK|y$?pO;A4Gb= zFjO8Nlu9hXP1o{3WhHg)f|NG>-#{u0ppQ}?Yn;f37>&_ delta 757 zcmaJ;OG_J36h29)k2Gp#2#BqiaYX2%R4k>tlu84oBB&@5Dpe=1IvNw1nS{0oh2Y9X zNqhEXRxU-jJ8_}EK!1RXt_l%!QN%@Y;dk%&09z#F=H&35?{UuIMQFVq-aZfUMtF-~ zMSA&kBFe?cGmcGW#A(ETz<;Vn(j#Rt%)(} zF)Z{QwHg<%fob{X!DEBRz`ZSmy=9h*v)isW!v}LcT`oXPNZWu`>66%B&~z=U{C$K^ a$udZ<`NZkwFEx{WZI1o57P03v9$o@T_`0qD diff --git a/Resources/ja.lproj/Localizable.strings b/Resources/ja.lproj/Localizable.strings index 1f7d8c8aed271642108d0c5c5985a219b750e4e0..c6d2059c8bd00d0b42c53f85a795cfb087455197 100644 GIT binary patch delta 528 zcmZp;%h-04al;Kp%_N3WhGK?F20aEP1_cINAXZ{fWpDt}nLu#`2Dtp>gEEnm&oItm zhluA*UT-Ho*&vFC7g;q#v>{4h@&y^M&HtF*uxy^dv5k!rZu(?(etAYcuvzzn`8HqT z&tTg8M%aLJbAeotAa625K0^@@rZOZmluW*BB&}P(kO*`}F+(|6CI!Wro(y?Fb!a*S zF?4_}yI>@+_?*7Dr~*S8&|^hF6H5?gO`hpy$_ba5te76VIlw)MTQr{`7w8mFNaQh; z0UeS9WTi|#uOn&<3Yl_-44^E?u^_Gaz;MiCNP((W02&XHRbWU5>L~-V@+LbPNlspr qD`pJ$AXqJuGk_r<3^a!ZcJiXw3HIQIpdQA}TA{D_HlIt`#0dbdU4Ib( delta 703 zcmaiyO=uHQ6ov1kwKP8@wj%YX;ItytYV_b3(D_) z(Zxgd_Nap!3t!IL7~{2Gn~$UtY9loh+3!(}3REGNEGmiCHm3O`;SN7(5)Z=ubkDIC3&NDPYW8~njI0mP% z3d33A2XRwPoigHTI=8IdDo{~IE#wSHU788m%Tkpi7veHq7iESz_++zE({S)9N!7Ln(*Sf2gKZq=M< lCgVm(VhfSSnbZ#6GIsT})uglhn4C#p;&G=-y)s@$e*;6YzA*p* diff --git a/Resources/nl.lproj/Localizable.strings b/Resources/nl.lproj/Localizable.strings index 3aaf4fe79f4fa531251fbd544930a6eed8f28c8f..e73fc007dc6207e7d57c521612780a7a9f0a81b9 100644 GIT binary patch delta 533 zcmZ3{%=GUMnAfmw-o*KieX@bD6mK#^B0~-kDln)rH~@7a1g6b@ z#B8`WpHm7G0V>RAC<4M%hGd44$&FUhlgqRPWc3)7fLd*VSc$=tArB~rMHSdu1@mQ6 zq6!RY44FVfiWy26;94h73^Zkj%1m~Qh~Hcgw1!tWpCK1$mjY0E9zz+}k(ravCrj2V zFqAW70A)Zf0cpwy20p^inP&O0UnLr-~Gvo_lcUC@~oi%x3Tk0c3gt}E5z0RREG BeHH)! delta 851 zcmb7CK~EDw6n@*L1}GTW5)D$!iYZ(QfrP|^5N!p~7~z27LV|AFrES{IlHIieiSgjo z+l$7?sqsSKf*DUn|Be?gn0PeA@68^z7Y}ALvv1yf^S$qTGZ%lX<2R|Z3ya^TzVKl> z&pWF_BL%ug4mBynthl+lz~`xT{X2b};e6N0P9eRFF-0Yw=-$-j!G{AgN%Aqdq_7>c zDDZd`VO_z$&ArSsKEHBF+xCalOhkbJhqQ~$0H9sK+lVC!$fpjXfIn~MZbd*=L6j6K z0~aDA=KZ{VIHiU(P66)&C#{Uz*fb(VuEXy#t-^}A;f|TZzP4@w5r9?ZJ?`bV^^Y4{ zW2|lu>*>Y!*STn4&i=$HX?m0DeAJkjYyd5HyhfY!gl4IZbx3<)@TkQL>)TpwoQ&wN zJ0GprF3#1=PH5bQ@FhOPm1tFn4iJfcWv(|?UIO=hdW6pb(ltBDV-Po@K-i_K^s$3g z-Q?Ql4$x6@ij)w=LPcyBLzzSJOr@O>K97G@s-K=dw?`{RVjWVY2%a|kK_T0h<oAKIL#tmFd>`4rz48;tUljWHt;p~aR(Ubo%ZeY%2D4x8UNq({dlf>k8Ofr)v z2}f-XW8TNQc^Bsv_Q`U>Qj-$|`GBGsn|Xw$Fm2u-#>chUMCpn!Z!$wZLlF?BG9)vU zOb$#IWd`ym2PO(L>P=o~EX;{j4rKh~cjf|| w3`#(jEf6a)1Ov^Xp&Nj91WyiD76rM3AI%-$U^o-Ih;eg8f|lUsn4&mt0FDfKX8-^I delta 818 zcmbtSJxo(k6h1A-G`6MTwW4WIyg)jbFhFY~g8j$8B6W~KQiDE96_Vmp-ou26K#Ze< zXK^&f!AUeXad04xj!w)S91WY3iTJ&15CX=Sn3sFsch0-#JNNs}+xiyx@ICN09F*t5 zS5odcDVw!$C`Cn5l#`vxfPAUl)L%O`k4V&2k$yjo)lVgfxP9{EOiVr|tNQiP_n~KT z6)$j}&v6=ijz_r6*I0_)jBZ;mg99Edkxlo>rMuJwR(LN^3)n|XI` z>{xxJ0vExP(aJjr~lU7 zBj;e}LIE5_!!vZK_ion~SLbLDLT72&h@RUM4dg=n zGAwAo3>PsjguMx~Y*hFb?HNCgdiQt!pIPIFX=Ni>@BBr#Xh>b@o^tfl-mQeRGf`d3 zY$v69F)W`Zj%WNy_>QE_T(i)+Q+jPW|TAi-0^% zbxpW5Z=|-!H^70w7Oem^4E86#fE*@?`U+jeqj1uOA@)8CrohsawNzs4KltQba#~-S jNn6&exzat5dT57#Up5|e%e>PS+4n_OEnDAl9z}ivDuS*= diff --git a/Resources/zh_TW.lproj/Localizable.strings b/Resources/zh_TW.lproj/Localizable.strings index a4f1a9c09f133a9a2fafe1477c4c879fd01ff6ca..6609b4448c7504a746f60e500e5bee1daaf4be5a 100644 GIT binary patch delta 489 zcmaF&jq%(^#tnZM*^?Mb8HyPyCkrwO^JfBC3Jg#Y2EECGjFFQ+FwS5Gicj9iBtMxe zg=exH6C0c#l_D@%fzb=7hGnx3a|G*VEzUUh$r1THllO@7Op5)mjPLMlM_`XCx1#2 wGeq`QCQu!+2ZDj-K)gpa`*>08n>?{7c5_SgG{(s>aT=R_;(iHiD#+so02p0+F8}}l delta 691 zcmbtSyGjE=6up}$d1=^X3k^iFiH|}gpkO5tgEqkg0ye7{b@I~0tayn#`Qr@6r{l;ZL@h4AT@x;MP za@T=v?@%ZWGbBF=RntoP%L*Z#ELF)^iY)51CSn>h^aPAD$T&WEJ@bFM0n7W$ze1ck zXy&L>0X_=xxsQ#x1kaCUWqv)|^58>c6l<#!c*@i(dvut$HZBEx@rw&O?3q#v&@)gZ zfdx1ulrnLz9y!`mAPj4;3=wJyMKUtPkZsBTzC#k$FShM`aWf#vNmI!#DKdzKz8wUy WQTFtU6Wi3pT-kKlJTPSr$Z#mL=>c_m zvQ2!pLtGE617?CMn-iFCxp^g{Iir{^*mw=7A<97GT-dzWCW|p^iG%D@2THp_C0*Gp zfo6J4_Gea~T*d4lOd0Wcs(FnA84Es JgEa#e0{|u@B6t7* delta 205 zcmbQlF^OYBiBK>@DnlMa3WEZJ4?{jfIzutT#6C3@1$0|0tfmKV%k1sbN#rUo=#6V>R+JQ zgEa#egAzj!Ln=c75GOK}Feor21L+(fRA9(s$OnpKGNb`9NEF1*2Z|~I9 diff --git a/Settings/InAppSettings.bundle/ar.lproj/Network.strings b/Settings/InAppSettings.bundle/ar.lproj/Network.strings index f3f1b6daebe478ab55eddc219e8f03cd01cf3af4..dee6be3f2e96bb3ad0fc57d5c613a617a0e0202e 100644 GIT binary patch delta 300 zcmeyv*2A&k6;r(qBvAMAs0gZNn8V3Ne5*UR5 diff --git a/Settings/InAppSettings.bundle/ar.lproj/Root.strings b/Settings/InAppSettings.bundle/ar.lproj/Root.strings index e8f29b4054d82438285620035e3eb81a9a2a286b..916a33cdc24b2761c96d61d4948569e4409170ee 100644 GIT binary patch delta 255 zcmcb|y@Go}f|v=L6aU=V4HYA zg;9OuQ$|KEkZLzJCm^}`2jdGE-w`M>`3Nw5rJNM*trVGP-0Zwc$<-N@&QJX%`X_AG4g~klrrQ2VJbro!{i&x zCQhyl6$~W|MGT1y3JhsL;Y1*>6v$6yC}vOsirE6O5(7R}lUZ0?CiAeEOm1R{lLRTu Y1R8;=6(}-Uk~Md75~~c0H3Js|0K$$Y!vFvP diff --git a/Settings/InAppSettings.bundle/ar.lproj/Video.strings b/Settings/InAppSettings.bundle/ar.lproj/Video.strings index 19bfcdd3994ca9c2e01ecf63f6bdd1e144b7d0fc..f64008c009da4cdb80d46c903c78ae9568b76a35 100644 GIT binary patch delta 244 zcmZ3+vVv`c7Nb=dLncECLn=c)g91YVLlKZw48$c2NA6Gqe#6Q zLjXfCl7;}VF=;?!iomQCpfNBt)(l)gl}-$a40%9n%fXhHFk}E#ZKwJW3X98sv b7_u3X!2DtceW0Td4notdN|g4=EsTo*0soaaHV0B^y0LP06u>b%7 delta 230 zcmeyty@_{20rTcb%qooajtnUbi3|k{B@CGiWelkd3JgU+ehHYB%#hEJ2V@rk=^O?n zpqwobD=}c|34-d$1FB7BNC)B^hEky3bf9W$1}?06!1jcIElLC`PX}631aw3RLk2@G W9?Ob=PC!_Psk4-!c=K8oZ$<#ONG#_7 diff --git a/Settings/InAppSettings.bundle/de.lproj/Call.strings b/Settings/InAppSettings.bundle/de.lproj/Call.strings index 8597ac972c997f6a32040c4a39ea876634a5d9c8..d25fb7033ad8c39c58e866e20d813bbf9f93f899 100644 GIT binary patch delta 122 zcmZ3-x`1uNI;J8eh9HJih5{f?WGG=!U`PhiIY6kukjIb@6v<>r17eUUh@B4x{tr@r&008F}{r~^~ delta 7 OcmZ3$wvKhfIwk-Ma{{^m diff --git a/Settings/InAppSettings.bundle/de.lproj/Network.strings b/Settings/InAppSettings.bundle/de.lproj/Network.strings index 987d15c85652548d80a666ebb99a6bf3c1ff564e..037fd04bed57d8a66d9667b31cdf2cec14c76022 100644 GIT binary patch delta 302 zcmX@aevV@U4|Av^LkdG8LjgkxLncERLn?y;LlKZ)0%j#M1 delta 191 zcmX@dafp2b4|9DeLjgk$Lq08A*DbKAVZ3XumS+LOCsq2 diff --git a/Settings/InAppSettings.bundle/de.lproj/Root.strings b/Settings/InAppSettings.bundle/de.lproj/Root.strings index 41d2a5e00fa735d18af19edcc63e48a117e5bff1..52a71eeda542e13049635590623f80667ecf6864 100644 GIT binary patch delta 73 zcmbQobB}w256k3bESD^U7*ZK>fH;w%7)UBGBs1hQ6aiUEK(;LqD>2|uF?l*`I{=Wh B5N7}Y delta 129 zcmcb|J&$LD4@;mcLj^+#LlHwFg91YuLn@FiVJHRiQyGdGlz?KkK&-?N1r#f0cmkBG zV#s00WJqSn0IE=6a080xF=PY9Ga2%MtW<`)$<8ddZKwJW3X98sv c7_u3X!2DtceW05V?m^S7LX7swM;Ye>0MmFaJpcdz delta 19 bcmaFH_Jn0a7UN_SCXvYp7y~9>V44O1OUegq diff --git a/Settings/InAppSettings.bundle/en.lproj/Audio.strings b/Settings/InAppSettings.bundle/en.lproj/Audio.strings index 3bf01c791..f6d77bfc8 100644 --- a/Settings/InAppSettings.bundle/en.lproj/Audio.strings +++ b/Settings/InAppSettings.bundle/en.lproj/Audio.strings @@ -14,13 +14,12 @@ "G.729" = "G.729"; "GSM" = "GSM"; "iLBC" = "iLBC"; +"iSAC" = "iSAC"; "PCMU" = "PCMU"; "PCMA" = "PCMA"; "Advanced" = "Advanced"; "Playback gain" = "Playback gain"; "Microphone gain" = "Microphone gain"; -"Adaptive rate control" = "Adaptive rate control"; -"Adaptive rate algorithm" = "Adaptive rate algorithm"; "Codec bitrate limit" = "Codec bitrate limit"; "Enable Voice Processing" = "Enable Voice Processing"; "Enable Bass Boost" = "Enable Bass Boost"; diff --git a/Settings/InAppSettings.bundle/en.lproj/Call.strings b/Settings/InAppSettings.bundle/en.lproj/Call.strings index 20d54ef56..6b175c9d3 100644 --- a/Settings/InAppSettings.bundle/en.lproj/Call.strings +++ b/Settings/InAppSettings.bundle/en.lproj/Call.strings @@ -5,3 +5,4 @@ "Incoming call timeout" = "Incoming call timeout"; "In call timeout" = "In call timeout"; "Voice mail URI" = "Voice mail URI"; +"Repeat call notification" = "Repeat call notification"; diff --git a/Settings/InAppSettings.bundle/en.lproj/Network.strings b/Settings/InAppSettings.bundle/en.lproj/Network.strings index 603793659..c090abb46 100644 --- a/Settings/InAppSettings.bundle/en.lproj/Network.strings +++ b/Settings/InAppSettings.bundle/en.lproj/Network.strings @@ -10,5 +10,6 @@ "Media Encryption" = "Media Encryption"; "Push Notification" = "Push Notification"; "Limits" = "Limits"; -"Upload bandwidth" = "Upload bandwidth"; -"Download bandwidth" = "Download bandwidth"; +"Adaptive rate control" = "Adaptive rate control"; +"Adaptive rate control" = "Adaptive rate control"; +"Adaptive rate algorithm" = "Adaptive rate algorithm"; diff --git a/Settings/InAppSettings.bundle/en.lproj/Root.strings b/Settings/InAppSettings.bundle/en.lproj/Root.strings index a4f199b92..b570484c6 100644 --- a/Settings/InAppSettings.bundle/en.lproj/Root.strings +++ b/Settings/InAppSettings.bundle/en.lproj/Root.strings @@ -18,10 +18,9 @@ "Network" = "Network"; "Tunnel" = "Tunnel"; "Advanced" = "Advanced"; -"Extra features" = "Extra features"; "Development debug actions" = "Development debug actions"; "About" = "About"; "Quit" = "Quit"; -"Exit" = "Exit"; +"Release core" = "Release core"; "Clear cache" = "Clear cache"; "Battery alert" = "Battery alert"; diff --git a/Settings/InAppSettings.bundle/en.lproj/Video.strings b/Settings/InAppSettings.bundle/en.lproj/Video.strings index 598678c4c..c30eed42b 100644 --- a/Settings/InAppSettings.bundle/en.lproj/Video.strings +++ b/Settings/InAppSettings.bundle/en.lproj/Video.strings @@ -2,7 +2,10 @@ "Automatically accept" = "Automatically accept"; "Show self view" = "Show self view"; "Show preview" = "Show preview"; +"Video preset" = "Video preset"; "Preferred video size" = "Preferred video size"; +"Preferred FPS" = "Preferred FPS"; +"Bandwidth limit in kbits/s" = "Bandwidth limit in kbits/s"; "Codecs" = "Codecs"; "MPEG-4" = "MPEG-4"; "H.264" = "H.264"; diff --git a/Settings/InAppSettings.bundle/fr.lproj/Audio.strings b/Settings/InAppSettings.bundle/fr.lproj/Audio.strings index 9bb1b7819ee97b4f2e07be8d6a1d33bdbd10a028..e124e98a66fa8e8e5a1e4f9656fdd623551ac5eb 100644 GIT binary patch delta 41 scmcb{vxR#@46}G9LokCQgENB?g93vs5Gyf&MK%XA^D}N%VKrg|0KFFn>;M1& delta 206 zcmdnOeT`>B4D;qXW){YJM}`!JM1}%}5{68MGKN$J1%@IZzXZ%mX2@sA1G0;NbPj_O zP|g;Jl^C4i;$MK`AU!Ei@+CtO(3}#W8fykFAc@cPM4;Yu8=z4|U@aL8xky$ZG=dzH T3APYqO)1zis5P4_S*#fWylW^T diff --git a/Settings/InAppSettings.bundle/fr.lproj/Call.strings b/Settings/InAppSettings.bundle/fr.lproj/Call.strings index 2ca653c3cc2b79a3e50a3ad995d52670898509ea..e95196b8836c8da76bb52c957cd45533a341821a 100644 GIT binary patch delta 139 zcmZo*ZDQNdz*Miq5X6wmPyob<3?&Q-49P$`2M84y@)+`gBAELfgy!K9jKxJY#Yc1B?fC|1}+8wwQ?FD delta 7 OcmZo-Yhc~bzytsZUjje? diff --git a/Settings/InAppSettings.bundle/fr.lproj/Network.strings b/Settings/InAppSettings.bundle/fr.lproj/Network.strings index 6b78bf767d07f5ec0177fe57be7e6c9852652cf1..014bf5b59ae1e37407cb86d3de01c62ecb2bfcf4 100644 GIT binary patch delta 298 zcmbQlK8a()C#HHwh7^WGh608XhD?SshExUxh9V%p1k6fi$Y;m{vWtLp4ucX<&K8K3 z7@XnaUx4BuJtoD!fKYX&YLNzn9qni-!6bXq#lp+#T^WiaF-c>v)oC6He; P!TtgHq7>{GR9^r9zauv_ delta 169 zcmbQlF^PS{C#L#Ph608hhJ1!Zh7<+`h9n@J2V|8qWCF<&h71NJpr|bnD>1k*yadW; v0!0-Va)CPXfGm*e5}=$l0~c6DK2T>KDds6c4NPH3WhiDy29hA_k&OiaI7A;~ diff --git a/Settings/InAppSettings.bundle/fr.lproj/Root.strings b/Settings/InAppSettings.bundle/fr.lproj/Root.strings index 8ca7357254a217020ff9142aa469c3da4f46793c..9140a72ebc8f80ec1d9046a9d306afca568021cd 100644 GIT binary patch delta 89 zcmZ3(^M`wb7t7=&EVn#^7*ZK>fH;w%7)UBGBs1hQ6aiUEK(;LqD>1k*yksZ=ij^{C cf@Ktd>N6RVz+@gn0Ye5*M;=4!t{fn{gyH36dzPonKr<)*XHlJ8#@Yq|ksTNi diff --git a/Settings/InAppSettings.bundle/fr.lproj/Video.strings b/Settings/InAppSettings.bundle/fr.lproj/Video.strings index d7b6da9ab1612ac9bd59d1366969a599193fd4fd..a530a1e8d34960bce4be4d25531c11b006ec9e4b 100644 GIT binary patch delta 280 zcmYk0JqiLb5QSer5Uf2wNMpIRh>eBC79t4tQCHn{cOzy|JMUl);1#@wC(%>*GT;wk z!u-7X-n?4Z_PtR3IdZI!!9in>12fNPU|0_s22*w&*3^}(kD`CV1*?20RQEEbV)mz> zP+egmEKPQg8x<@z!j3MMGc7(#YHRT~7@$MSh|}0PiBE$qm8B4JUZt7U{CDKX+9OH% h{f_;tXB0&v&liCW&9$6y7MLY8cCs%nfe#OLdjmqrG=2a8 delta 19 bcmbQl{)%No7UN_wCXvYp7{ez2VVVX2MP3Ip diff --git a/Settings/InAppSettings.bundle/ja.lproj/Audio.strings b/Settings/InAppSettings.bundle/ja.lproj/Audio.strings index 8dc312533cfd6dac25283761a07d7709aab2e955..2c781dc34b39b0339d8fda379b253926591fd304 100644 GIT binary patch delta 41 scmcb`vx0j=46}G9LokCQgENB?g93vs5Gyf&MK%XAi!yGuVpU)S0K7#9?f?J) delta 222 zcmZ3%eT!#94D;qXW-i8hM}`!JM1}%}5{68MGKN$J1%@IZzXZ%mX2@sA1G0;NbPj_O tP|g;Jl^96TW6i*YPlpfCz(kN9Q?;%ZR;q4A@9oa)qx>sO6N>F5;wo^t&1?P%=8Sz|_ Zb1hX;6wJ_3)l-=>oiLX+JxzJ0=@+e#r#Jur delta 179 zcmbQj(Z;^v4pV(7Ljgk$Lq0fH;w%7)UBGBs1hQ6aiUEK(;LqD>2|uF|l5BvJ`6> E0LHx$2LJ#7 delta 108 zcmaFHHGzA>D`rPmh6;ufh9ZVU1_g#RhEyP3!cYq2r!o{XC;`Q6fmn$FkE+QJnGcGC TPz8{5Vn}4j1KLs!wyT68188mzkev&}B|vs2P*#B< Xn;{9zFJ{mOx&dK78M-I0WSkEGIn65r delta 19 bcmX@bc7kO?0ORB%j9QcTFj`FB!ZZy4OmYW@ diff --git a/Settings/InAppSettings.bundle/nl.lproj/Audio.strings b/Settings/InAppSettings.bundle/nl.lproj/Audio.strings index 8dc312533cfd6dac25283761a07d7709aab2e955..2c781dc34b39b0339d8fda379b253926591fd304 100644 GIT binary patch delta 41 scmcb`vx0j=46}G9LokCQgENB?g93vs5Gyf&MK%XAi!yGuVpU)S0K7#9?f?J) delta 222 zcmZ3%eT!#94D;qXW-i8hM}`!JM1}%}5{68MGKN$J1%@IZzXZ%mX2@sA1G0;NbPj_O tP|g;Jl^96TW6i*YPlpfCz(k03rn!LI3~& delta 7 OcmaFF`hjIb0TTcY1p@v6 diff --git a/Settings/InAppSettings.bundle/nl.lproj/Network.strings b/Settings/InAppSettings.bundle/nl.lproj/Network.strings index cb18d99693baaf54e486de859ec9fb3246436881..bf538146cabbc6c6a5cffb3550da91e50d05aa89 100644 GIT binary patch literal 1044 zcmd6lK~KU!5QX2_U(s;FKj6i9AcO-65+YI0O{+ixttm)?KVJQ&gV`mN3O5eh-R``3 zGjI0&e0MZZu9@DHsMLoxT4=@kQd*x&73vUsV4a7(*A2*5INn*tT4N9Q?;%ZR;q4A@9oa)qx>sO6N>F5;wo^t&1?P%=8Sz|_ Zb1hX;6wJ_3)l-=>oiLX+JxzJ0=@+e#r#Jur delta 179 zcmbQj(Z;^v4pV(7Ljgk$Lq03?vm8k{R+DihwL7Alnv*l^AfSm{>15*^9Ld E0FdYqbpQYW delta 108 zcmbQneSmv|7>lDTLj^+#LlHwFg91YuLn@FiVJHRiQyGdGlz?KkK&-@oN7ZCrmZRbz T`AncrR2`WUYsDuku$BP;pLZ3L diff --git a/Settings/InAppSettings.bundle/nl.lproj/Video.strings b/Settings/InAppSettings.bundle/nl.lproj/Video.strings index bb336f09cb832df167104f18ef39fadc55a7adf7..fa870bafc9780a98db2cbbb6c1748c53d9af528e 100644 GIT binary patch delta 225 zcmX@Xa*Az30Hb{vLncECLn=c)g91YVLlKZw48$c2NPz8{5Vn}4j1KLs!wyT68188mzkev&}B|vs2P*#B< Xn;{9zFJ{mOx&dK78M-I0WSkEGIn65r delta 19 bcmX@bc7kO?0ORB%j9QcTFj`FB!ZZy4OmYW@ diff --git a/Settings/InAppSettings.bundle/ru.lproj/Audio.strings b/Settings/InAppSettings.bundle/ru.lproj/Audio.strings index cbe619ed6fac65a7c917dfc9cb725c9ecba4844b..28476bf7280368608b9b8f2d232742887483e702 100644 GIT binary patch delta 41 scmZqTy}-R8hFLt5A(+9D!I?pcL4m;*h?N+?BAWx5Z5cNwu_`bE0JbFv4*&oF delta 223 zcmcb>-Nd^ghIw-xvk_yxBSQ*9B0~W~2}34B8AB?A0z(myUjk+&GvqVm0og@BI)_0C tC}#`AN(`jvv1Z`Hr^6R$U?R})bf6VQKqr(iWH96sX%(iv%_~?m7y$*~DmVZD diff --git a/Settings/InAppSettings.bundle/ru.lproj/Call.strings b/Settings/InAppSettings.bundle/ru.lproj/Call.strings index 48bffaded429d29c820dd792177a519d53a0bb77..2ae0d1fea7fdd2f9d2403c819588490a13adc077 100644 GIT binary patch delta 122 zcmcb^a*lOF3{#O3Ll8qMLje#cGL$eVFeC%%93WI+$YaO{iexgR0WnAv#LfqbDgote MftVbf)(l(>00sFM1^@s6 delta 7 OcmX@ddWU603=;qh?E=C8 diff --git a/Settings/InAppSettings.bundle/ru.lproj/Network.strings b/Settings/InAppSettings.bundle/ru.lproj/Network.strings index 1139751c88c17f1a68733a21a0fc61dc4f405e9b..e0e20f8cf1b6ae5ec25024c16628782d1ca125e7 100644 GIT binary patch delta 322 zcmbQmzJX)I52kuYh7^WGh608XhD?SshExUxh9V%p1k6fi$Y;m{vWtLp4ucX<&K8K3 u7)a4$&A^3EM?KI$I#>g=B@yU_bf8CyfF3Pj$Y96?d&r8gkFaS3`3eA3Mmi<{ delta 171 zcmdnMF^he}52pH1h608hhJ1!Zh7<+`h9n@J2V|8qWCF<&h71NJpr|bnD>2Bk*s)jx zu_KECivoikixZ0pkmb%|!J@=q&A3?vm8k{R+DihwL7Alnv*l^AfSnB2(P4FHM+ B5Iq0@ delta 108 zcmaFF-NUmXh{eg3p@N}=p@<=oL4hHSAr(lMFq8uMsSL#oNFTs0Kt@)Vn}4j1G=Xi?5Yxm44^4FKz1$=mjKzB eKv@NbY=$H-znDQE=vuH#Er7ygX`g(RaXtX%QZgw3 delta 23 fcmeyy_Jw6b4dY}NCXvZ3Ok$H?Fj`E0z%&g2Xsif* diff --git a/Settings/InAppSettings.bundle/zh_TW.lproj/Audio.strings b/Settings/InAppSettings.bundle/zh_TW.lproj/Audio.strings index 8dc312533cfd6dac25283761a07d7709aab2e955..2c781dc34b39b0339d8fda379b253926591fd304 100644 GIT binary patch delta 41 scmcb`vx0j=46}G9LokCQgENB?g93vs5Gyf&MK%XAi!yGuVpU)S0K7#9?f?J) delta 222 zcmZ3%eT!#94D;qXW-i8hM}`!JM1}%}5{68MGKN$J1%@IZzXZ%mX2@sA1G0;NbPj_O tP|g;Jl^96TW6i*YPlpfCz(kN9Q?;%ZR;q4A@9oa)qx>sO6N>F5;wo^t&1?P%=8Sz|_ Zb1hX;6wJ_3)l-=>oiLX+JxzJ0=@+e#r#Jur delta 179 zcmbQj(Z;^v4pV(7Ljgk$Lq0hE#?eAWmc`29gR4$qe}nML?DkkZlXZN(?wuOsp53Y{gmz E0Dcw_BLDyZ delta 108 zcmZqU-oU+qg~id8p@N}=p@<=oL4hHSAr(lMFq8uMsSL#oN>G diff --git a/Settings/InAppSettings.bundle/zh_TW.lproj/Video.strings b/Settings/InAppSettings.bundle/zh_TW.lproj/Video.strings index bb336f09cb832df167104f18ef39fadc55a7adf7..fa870bafc9780a98db2cbbb6c1748c53d9af528e 100644 GIT binary patch delta 225 zcmX@Xa*Az30Hb{vLncECLn=c)g91YVLlKZw48$c2NPz8{5Vn}4j1KLs!wyT68188mzkev&}B|vs2P*#B< Xn;{9zFJ{mOx&dK78M-I0WSkEGIn65r delta 19 bcmX@bc7kO?0ORB%j9QcTFj`FB!ZZy4OmYW@ diff --git a/prepare.py b/prepare.py index c5f04ebc5..1f1a16227 100755 --- a/prepare.py +++ b/prepare.py @@ -439,7 +439,7 @@ pull-transifex: push-transifex: \t./Tools/i18n_generate_strings_files.sh && \\ -\ttx push -s -t -f --no-interactive +\ttx push -s -f --no-interactive zipres: \t@tar -czf ios_assets.tar.gz Resources iTunesArtwork From 0a4d30aa3f654cce3470b4b137c23d710596fbcb Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 4 Sep 2015 16:02:07 +0200 Subject: [PATCH 41/46] chat: update linphone and fix chat rooms usage to avoid crashes when receiving ACK after having deleted the chat room --- Classes/ChatTableViewController.m | 7 +++---- Classes/ChatViewController.m | 4 +--- Classes/ContactDetailsTableViewController.m | 2 +- Classes/HistoryDetailsViewController.m | 10 +++------- Classes/LinphoneAppDelegate.m | 4 ++-- Classes/LinphoneManager.m | 4 ++-- submodules/linphone | 2 +- 7 files changed, 13 insertions(+), 20 deletions(-) diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index d0f5e94c9..ef7b180c2 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -75,8 +75,8 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo - (MSList *)sortChatRooms { MSList *sorted = nil; - MSList *unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]); - MSList *iter = unsorted; + const MSList *unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]); + const MSList *iter = unsorted; while (iter) { // store last message in user data @@ -176,8 +176,7 @@ static void chatTable_free_chatrooms(void *data) { [ftd cancel]; } } - linphone_chat_room_delete_history(chatRoom); - linphone_chat_room_unref(chatRoom); + linphone_core_delete_chat_room(linphone_chat_room_get_lc(chatRoom), chatRoom); data = ms_list_remove(data, chatRoom); // will force a call to [self loadData] diff --git a/Classes/ChatViewController.m b/Classes/ChatViewController.m index 15c346ce9..e17b80c1b 100644 --- a/Classes/ChatViewController.m +++ b/Classes/ChatViewController.m @@ -98,14 +98,12 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)startChatRoom { // Push ChatRoom LinphoneChatRoom *room = - linphone_core_get_or_create_chat_room([LinphoneManager getLc], [addressField.text UTF8String]); + linphone_core_get_chat_room_from_uri([LinphoneManager getLc], [addressField.text UTF8String]); if (room != nil) { ChatRoomViewController *controller = DYNAMIC_CAST( [[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if (controller != nil) { - LinphoneChatRoom *room = - linphone_core_get_or_create_chat_room([LinphoneManager getLc], [addressField.text UTF8String]); [controller setChatRoom:room]; } } else { diff --git a/Classes/ContactDetailsTableViewController.m b/Classes/ContactDetailsTableViewController.m index 82f709fe6..f17f43a1f 100644 --- a/Classes/ContactDetailsTableViewController.m +++ b/Classes/ContactDetailsTableViewController.m @@ -644,7 +644,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSe ChatRoomViewController); if (controller != nil) { LinphoneChatRoom *room = - linphone_core_get_or_create_chat_room([LinphoneManager getLc], [dest UTF8String]); + linphone_core_get_chat_room_from_uri([LinphoneManager getLc], [dest UTF8String]); [controller setChatRoom:room]; } } diff --git a/Classes/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index bc1ea227e..7da06d8ab 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -358,11 +358,8 @@ static UICompositeViewDescription *compositeDescription = nil; } - (IBAction)onMessageClick:(id)event { - LinphoneAddress *addr; - addr = linphone_call_log_get_remote_address(callLog); - - char *lAddress = linphone_address_as_string_uri_only(addr); - if (lAddress == NULL) + const LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog); + if (addr == NULL) return; // Go to ChatRoom view [[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]]; @@ -370,10 +367,9 @@ static UICompositeViewDescription *compositeDescription = nil; [[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if (controller != nil) { - LinphoneChatRoom *room = linphone_core_get_or_create_chat_room([LinphoneManager getLc], lAddress); + LinphoneChatRoom *room = linphone_core_get_chat_room([LinphoneManager getLc], addr); [controller setChatRoom:room]; } - ms_free(lAddress); } @end diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 947f6c4fc..60ce84ba9 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -317,7 +317,7 @@ } - (LinphoneChatRoom *)findChatRoomForContact:(NSString *)contact { - MSList *rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); + const MSList *rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); const char *from = [contact UTF8String]; while (rooms) { const LinphoneAddress *room_from_address = linphone_chat_room_get_peer_address((LinphoneChatRoom *)rooms->data); @@ -445,7 +445,7 @@ [self application:application didReceiveLocalNotification:notification]; } else if ([identifier isEqualToString:@"mark_read"]) { NSString *from = [notification.userInfo objectForKey:@"from_addr"]; - LinphoneChatRoom *room = linphone_core_get_or_create_chat_room(lc, [from UTF8String]); + LinphoneChatRoom *room = linphone_core_get_chat_room_from_uri(lc, [from UTF8String]); if (room) { linphone_chat_room_mark_as_read(room); [[PhoneMainView instance] updateApplicationBadgeNumber]; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 6bdbb167e..813283f4d 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2048,8 +2048,8 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1 + (int)unreadMessageCount { int count = 0; - MSList *rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); - MSList *item = rooms; + const MSList *rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); + const MSList *item = rooms; while (item) { LinphoneChatRoom *room = (LinphoneChatRoom *)item->data; if (room) { diff --git a/submodules/linphone b/submodules/linphone index 9f2b9df16..44327da3e 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 9f2b9df16a2f6537196a7f2ec8db792d63287a9d +Subproject commit 44327da3ec399aa4eb29a4fb93a585bd99c47af5 From db84eae27f05c923a5cf03758de01d11518527e5 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 7 Sep 2015 12:06:56 +0200 Subject: [PATCH 42/46] prepare.py: use correct build type when using --list-features option --- prepare.py | 8 +++++--- submodules/cmake-builder | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/prepare.py b/prepare.py index 1f1a16227..b14456239 100755 --- a/prepare.py +++ b/prepare.py @@ -35,9 +35,9 @@ sys.dont_write_bytecode = True sys.path.insert(0, 'submodules/cmake-builder') try: import prepare -except: +except Exception as e: error( - "Could not find prepare module, probably missing submodules/cmake-builder? Try running:\ngit submodule update --init --recursive") + "Could not find prepare module: {}, probably missing submodules/cmake-builder? Try running:\ngit submodule update --init --recursive".format(e)) exit(1) @@ -544,10 +544,12 @@ def main(argv=None): if args.list_features: tmpdir = tempfile.mkdtemp(prefix="linphone-iphone") tmptarget = IOSarm64Target() + tmptarget.abs_cmake_dir = tmpdir option_regex = re.compile("ENABLE_(.*):(.*)=(.*)") option_list = [""] - for line in Popen(tmptarget.cmake_command("Debug", False, True, additional_args), + build_type = 'Debug' if args.debug else 'Release' + for line in Popen(tmptarget.cmake_command(build_type, False, True, additional_args), cwd=tmpdir, shell=False, stdout=PIPE).stdout.readlines(): match = option_regex.match(line) if match is not None: diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 5ff6590ab..015037369 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 5ff6590ab1b9e97bc97eadaa4f64353f266e2d9f +Subproject commit 0150373697676183e6735d69620d6e7dc5545134 From a76f80c7a0c170f004283a1470adb0d436ff7146 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 7 Sep 2015 16:58:40 +0200 Subject: [PATCH 43/46] Wizard: never use == for NSNumber comparaison, it will compare pointers and this is actually broken on iOS 8. Instead use isEqual method --- Classes/ChatRoomTableViewController.m | 7 ++++--- Classes/WizardViewController.m | 7 +++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index c1dcd3adf..673894539 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -64,9 +64,10 @@ // also append transient upload messages because they are not in history yet! for (FileTransferDelegate *ftd in [[LinphoneManager instance] fileTransferDelegates]) { - if (linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(ftd.message)) == - linphone_chat_room_get_peer_address(chatRoom) && - linphone_chat_message_is_outgoing(ftd.message)) { + const LinphoneAddress *ftd_peer = + linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(ftd.message)); + const LinphoneAddress *peer = linphone_chat_room_get_peer_address(chatRoom); + if (linphone_address_equal(ftd_peer, peer) && linphone_chat_message_is_outgoing(ftd.message)) { LOGI(@"Appending transient upload message %p", ftd.message); self->messageList = ms_list_append(self->messageList, linphone_chat_message_ref(ftd.message)); } diff --git a/Classes/WizardViewController.m b/Classes/WizardViewController.m index af9e0c5f5..07a6a222c 100644 --- a/Classes/WizardViewController.m +++ b/Classes/WizardViewController.m @@ -944,9 +944,8 @@ static UICompositeViewDescription *compositeDescription = nil; otherButtonTitles:nil, nil]; [errorView show]; } else if ([response object] != nil) { // Don't handle if not object: HTTP/Communication Error - NSString *value = [response object]; if ([[request method] isEqualToString:@"check_account"]) { - if ([value integerValue] == 1) { + if ([response.object isEqualToNumber:[NSNumber numberWithInt:1]]) { UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Check issue", nil) message:NSLocalizedString(@"Username already exists", nil) @@ -962,7 +961,7 @@ static UICompositeViewDescription *compositeDescription = nil; [self createAccount:identity password:password email:email]; } } else if ([[request method] isEqualToString:@"create_account_with_useragent"]) { - if ([value integerValue] == 0) { + if ([response.value isEqualToNumber:[NSNumber numberWithInt:0]]) { NSString *username = [WizardViewController findTextField:ViewElement_Username view:contentView].text; NSString *password = [WizardViewController findTextField:ViewElement_Password view:contentView].text; [self changeView:validateAccountView back:FALSE animation:TRUE]; @@ -978,7 +977,7 @@ static UICompositeViewDescription *compositeDescription = nil; [errorView show]; } } else if ([[request method] isEqualToString:@"check_account_validated"]) { - if ([value integerValue] == 1) { + if ([response.object isEqualToNumber:[NSNumber numberWithInt:1]]) { NSString *username = [WizardViewController findTextField:ViewElement_Username view:contentView].text; NSString *password = [WizardViewController findTextField:ViewElement_Password view:contentView].text; [self addProxyConfig:username password:password domain:nil withTransport:nil]; From 2030dbb15c91c09b26976ddc886683c2d6794eb9 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 7 Sep 2015 17:11:03 +0200 Subject: [PATCH 44/46] Wizard: (typo) never use == for NSNumber comparaison, it will compare pointers and this is actually broken on iOS 8. Instead use isEqual method --- Classes/WizardViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/WizardViewController.m b/Classes/WizardViewController.m index 07a6a222c..cc1f633f5 100644 --- a/Classes/WizardViewController.m +++ b/Classes/WizardViewController.m @@ -961,7 +961,7 @@ static UICompositeViewDescription *compositeDescription = nil; [self createAccount:identity password:password email:email]; } } else if ([[request method] isEqualToString:@"create_account_with_useragent"]) { - if ([response.value isEqualToNumber:[NSNumber numberWithInt:0]]) { + if ([response.object isEqualToNumber:[NSNumber numberWithInt:0]]) { NSString *username = [WizardViewController findTextField:ViewElement_Username view:contentView].text; NSString *password = [WizardViewController findTextField:ViewElement_Password view:contentView].text; [self changeView:validateAccountView back:FALSE animation:TRUE]; From 97dd05622ba0535f80a6dbcdcf27913ccfa0683f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 7 Sep 2015 17:38:58 +0200 Subject: [PATCH 45/46] submodules: fix crash in liblinphone --- Classes/Utils/Utils.m | 14 +++----------- submodules/linphone | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index 6cdce2d5c..015f8a3fa 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -23,11 +23,9 @@ @implementation LinphoneLogger -+ (void)logv:(OrtpLogLevel)severity - file:(const char *)file - line:(int)line - format:(NSString *)format - args:(va_list)args { ++ (void)log:(OrtpLogLevel)severity file:(const char *)file line:(int)line format:(NSString *)format, ... { + va_list args; + va_start(args, format); NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; int filesize = 20; if (severity <= ORTP_DEBUG) { @@ -38,12 +36,6 @@ ortp_log(severity, "%*s:%3d - %s", filesize, file + MAX((int)strlen(file) - filesize, 0), line, [str UTF8String]); } -} - -+ (void)log:(OrtpLogLevel)severity file:(const char *)file line:(int)line format:(NSString *)format, ... { - va_list args; - va_start(args, format); - [LinphoneLogger logv:severity file:file line:line format:format args:args]; va_end(args); } diff --git a/submodules/linphone b/submodules/linphone index 44327da3e..f46f1fbe7 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 44327da3ec399aa4eb29a4fb93a585bd99c47af5 +Subproject commit f46f1fbe77630dfa79d58099b7684d6a97e5fa99 From b47c75d4a26ec1aef9a9873093a25afe68e1dfda Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 8 Sep 2015 10:37:17 +0200 Subject: [PATCH 46/46] submodules: update linphone again --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index f46f1fbe7..352b9c840 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit f46f1fbe77630dfa79d58099b7684d6a97e5fa99 +Subproject commit 352b9c84067692131b2c58ad8d2d62a37b664e9e