[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Device (please compete the following information):**\n- sessionId, if applicable:\n- iOS SDK version: \n- OS and version:\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/workflows/metrics.yml",
    "content": "name: Aggregit\n\non:\n  schedule:\n    - cron: \"0 0 * * *\"\n\njobs:\n  recordMetrics:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: michaeljolley/aggregit@v1\n      with:\n        githubToken: ${{ secrets.GITHUB_TOKEN }}\n        project_id: ${{ secrets.project_id }}\n        private_key: ${{ secrets.private_key }}\n        client_email: ${{ secrets.client_email }}\n        firebaseDbUrl: ${{ secrets.firebaseDbUrl }}\n"
  },
  {
    "path": ".gitignore",
    "content": "OpenTok.framework/\nOpenTok.framework\n\n# Xcode\n.DS_Store\n*/build/*\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\nprofile\n*.moved-aside\nDerivedData\n.idea/\n*.hmap\n*.xccheckout\n\n#CocoaPods\nPods\nPodfile.lock\n*.xcworkspacedata\n*.xcworkspace\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: objective-c\nosx_image: xcode11.7\nbefore_install:\n  - pod repo update > /dev/null\nscript: ./travis_build.sh \n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n}\n\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"6211\" systemVersion=\"14A298i\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6204\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        publisher =  OTPublisher(delegate: self, settings: settings)!\n\n        session.publish(publisher!, error: &error)\n        \n        if let pubView = publisher!.view {\n            pubView.frame = CGRect(x: 0, y: 0, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(pubView)\n        }\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        \n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func cleanupPublisher() {\n        publisher!.view?.removeFromSuperview()\n        publisher = nil\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            DispatchQueue.main.async {\n                let controller = UIAlertController(title: \"Error\", message: err.localizedDescription, preferredStyle: .alert)\n                controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n                self.present(controller, animated: true, completion: nil)\n            }\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n        cleanupPublisher()\n        cleanupSubscriber()\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        cleanupPublisher()\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        if let subsView = subscriber?.view {\n            subsView.frame = CGRect(x: 0, y: kWidgetHeight, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n}\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375CF1EB1633400645696 /* AppDelegate.swift */; };\n\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05375D01EB1633400645696 /* Assets.xcassets */; };\n\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D11EB1633400645696 /* LaunchScreen.storyboard */; };\n\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D31EB1633400645696 /* Main.storyboard */; };\n\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375D61EB1633400645696 /* ViewController.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05375D01EB1633400645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05375D21EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D41EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D51EB1633400645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05375D61EB1633400645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF86C649A1D5C7C630081846D /* Basic-Video-Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Basic-Video-Chat.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64971D5C7C630081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA05375CE1EB1633400645696 /* Basic-Video-Chat */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */,\n\t\t\t\tA05375D01EB1633400645696 /* Assets.xcassets */,\n\t\t\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05375D31EB1633400645696 /* Main.storyboard */,\n\t\t\t\tA05375D51EB1633400645696 /* Info.plist */,\n\t\t\t\tA05375D61EB1633400645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Basic-Video-Chat\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64911D5C7C630081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375CE1EB1633400645696 /* Basic-Video-Chat */,\n\t\t\t\tF86C649B1D5C7C630081846D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C649B1D5C7C630081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C649A1D5C7C630081846D /* Basic-Video-Chat.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64991D5C7C630081846D /* Basic-Video-Chat */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Basic-Video-Chat\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF86C64961D5C7C630081846D /* Sources */,\n\t\t\t\tF86C64971D5C7C630081846D /* Frameworks */,\n\t\t\t\tF86C64981D5C7C630081846D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Basic-Video-Chat\";\n\t\t\tproductName = \"Hello-World\";\n\t\t\tproductReference = F86C649A1D5C7C630081846D /* Basic-Video-Chat.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64921D5C7C630081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64991D5C7C630081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Basic-Video-Chat\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64911D5C7C630081846D;\n\t\t\tproductRefGroup = F86C649B1D5C7C630081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64991D5C7C630081846D /* Basic-Video-Chat */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64981D5C7C630081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */,\n\t\t\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64961D5C7C630081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */,\n\t\t\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D21EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375D31EB1633400645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D41EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64AA1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AB1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64AD1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Basic-Video-Chat/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AE1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Basic-Video-Chat/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Basic-Video-Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AA1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AB1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Basic-Video-Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AD1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AE1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64921D5C7C630081846D /* Project object */;\n}\n"
  },
  {
    "path": "Basic-Video-Chat/Basic-Video-Chat.xcodeproj/xcshareddata/xcschemes/Basic-Video-Chat.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1170\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n               BuildableName = \"Basic-Video-Chat.app\"\n               BlueprintName = \"Basic-Video-Chat\"\n               ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Basic-Video-Chat/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Basic-Video-Chat' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Basic-Video-Chat/README.md",
    "content": "Basic Video Chat Sample App\n===============================\n\nThe Basic-Video-Chat app is a very simple application meant to get a new developer\nstarted using the OpenTok iOS SDK.\n\nQuick Start\n-----------\n\nTo use this application:\n\n1. Follow the instructions in the [Quick Start](../README.md#quick-start)\n   section of the main README file for this repository.\n\n   Among other things, you need to set values for the `kApiKey`, `kSessionId`,\n   and `kToken` constants. See [Obtaining OpenTok\n   Credentials](../README.md#obtaining-opentok-credentials)\n   in the main README file for the repository.\n\n2. When you run the application, it connects to an OpenTok session and\n   publishes an audio-video stream from your device to the session.\n\n3. Run the app on a second client. You can do this by deploying the app to an\n   iOS device and testing it in the simulator at the same time. Or you can use\n   the browser_demo.html file to connect in a browser (see the following\n   section).\n\n   When the second client connects, it also publishes a stream to the session,\n   and both clients subscribe to (view) each other’s stream.\n\nApplication Notes\n-----------------\n\n*   Follow the code from the `ViewController.viewDidLoad(_:)` method through\n    to the OpenTok callbacks to see how streams are created and handled in\n    the OpenTok iOS SDK.\n\n*   By default, all delegate methods from classes in the OpenTok iOS SDK are\n    invoked on the main queue. This means that you can directly modify the view\n    hierarchy from inside the callback, without any asynchronous callouts.\n\n*   When the main view loads, the ViewController calls the\n    `OTSession.initWithApiKey(_:, sessionId:,delegate:)` method to initialize\n    a Session object. The app then calls the\n    `OTSession.connectWithToken(_:, error:)` to connect to the session. The\n    `OTSessionDelegate.sessionDidConnect(_:)` message is sent when the app\n    connects to the OpenTok session.\n\n*   The `doPublish()` method of the app initializes a publisher and passes it\n    into the `OTSession.publish(_:,error:)` method. This publishes an\n    audio-video stream to the session.\n\n*   The `OTSessionDelegate.session(_:,streamCreated:)` message is sent when\n    a new stream is created in the session. In response, the\n    method calls `OTSubscriber(stream:,delegate:)`,\n    passing in the OTStream object. This causes the app to subscribe to the\n    stream.\n\n To add a second publisher (which will display as a subscriber in your emulator), either run the app a second time in an iOS device or use the OpenTok Playground to connect to the session in a supported web browser (Chrome, Firefox, or Internet Explorer 10-11) by following the steps below:\n\n1. Go to [OpenTok Playground](https://tokbox.com/developer/tools/playground) (must be logged into your [Account](https://tokbox.com/account))\n2. Select the **Join existing session** tab\n3. Copy the session ID you used in your project file and paste it in the **Session ID** input field\n4. Click **Join Session**\n5. On the next screen, click **Connect**, then click **Publish Stream**\n6. You can adjust the Publisher options (not required), then click **Continue** to connect and begin publishing and subscribing\n\n\nConfiguration Notes\n-------------------\n\n*   You can test in the iOS Simulator or on a supported iOS device. However, the\n    XCode iOS Simulator does not provide access to the camera. When running in\n    the iOS Simulator, an OTPublisher object uses a demo video instead of the\n    camera.\n\n[1]: https://tokbox.com/account/#/\n[2]: https://tokbox.com/developer/sdks/server/\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n- Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\ndevrel@vonage.com.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations."
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nFor anyone looking to get involved to this project, we are glad to hear from you. Here are a few types of contributions\nthat we would be interested in hearing about.\n\n*  Bug fixes\n    -  If you find a bug, please first report it using Github Issues.\n    -  Issues that have already been identified as a bug will be labelled `bug`.\n    -  If you'd like to submit a fix for a bug, send a Pull Request from your own fork and mention the Issue number.\n*  New Features\n    -  If you'd like to accomplish something in the library that it doesn't already do, describe the problem in a new\n       Github Issue.\n    -  Issues that have been identified as a feature request will be labelled `enhancement`.\n    -  If you'd like to implement the new feature, please wait for feedback from the project maintainers before spending\n       too much time writing the code. In some cases, `enhancement`s may not align well with the project objectives at\n       the time.\n*  Documentation and Miscellaneous\n    -  If you think the documentation could be clearer, you've got an alternative\n       implementation of something that may have more advantages, or any other change we would still be glad hear about\n       it.\n       -  If its a trivial change, go ahead and send a Pull Request with the changes you have in mind\n       -  If not, open a Github Issue to discuss the idea first.\n\n## Requirements\n\nFor a contribution to be accepted:\n\n*  Code must follow existing styling conventions\n*  Commit messages must be descriptive. Related issues should be mentioned by number.\n\nIf the contribution doesn't meet these criteria, a maintainer will discuss it with you on the Issue. You can still\ncontinue to add more commits to the branch you have sent the Pull Request from.\n\n## How To\n\n1. Fork this repository on GitHub.\n1. Clone/fetch your fork to your local development machine.\n1. Create a new branch (e.g. `issue-12`, `feat.add_foo`, etc) and check it out.\n1. Make your changes and commit them. \n1. Push your new branch to your fork. (e.g. `git push myname issue-12`)\n1. Open a Pull Request from your new branch to the original fork's `master` branch."
  },
  {
    "path": "CallKit/CallKitDemo/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  CallKitDemo\n//\n//  Created by Xi Huang on 6/5/17.\n//  Copyright © 2017 Tokbox, Inc. All rights reserved.\n//\n\nimport UIKit\nimport PushKit\nimport CallKit\nimport OpenTok\n\nlet apiKey = \"\"\nlet sessionId = \"\"\nlet token = \"\"\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n    \n    let pushRegistry = PKPushRegistry(queue: DispatchQueue.main)\n    let callManager = SpeakerboxCallManager()\n    var providerDelegate: ProviderDelegate?\n\n    // Trigger VoIP registration on launch\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {\n        \n        \n        providerDelegate = ProviderDelegate(callManager: callManager)\n        \n        pushRegistry.delegate = self\n        pushRegistry.desiredPushTypes = [.voIP]\n        \n        return true\n    }\n}\n\nextension AppDelegate: PKPushRegistryDelegate {\n    \n    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {\n        print(\"\\(#function) voip token: \\(credentials.token)\")\n        \n        let deviceToken = credentials.token.reduce(\"\", {$0 + String(format: \"%02X\", $1) })\n        print(\"\\(#function) token is: \\(deviceToken)\")\n    }\n\n    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {\n        \n        print(\"\\(#function) incoming voip notfication: \\(payload.dictionaryPayload)\")\n        if let uuidString = payload.dictionaryPayload[\"UUID\"] as? String,\n            let handle = payload.dictionaryPayload[\"handle\"] as? String,\n            let uuid = UUID(uuidString: uuidString) {\n            \n            OTAudioDeviceManager.setAudioDevice(OTDefaultAudioDevice.sharedInstance())\n                \n            // display incoming call UI when receiving incoming voip notification\n            let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)\n            self.displayIncomingCall(uuid: uuid, handle: handle, hasVideo: false) { _ in\n                UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)\n            }\n        }\n    }\n    \n    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {\n        print(\"\\(#function) token invalidated\")\n    }\n        \n    /// Display the incoming call to the user\n    func displayIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {\n        providerDelegate?.reportIncomingCall(uuid: uuid, handle: handle, hasVideo: hasVideo, completion: completion)\n    }\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit/CallKitDemo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit/CallKitDemo/Assets.xcassets/IconMask.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-40.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-80.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-120.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit/CallKitDemo/Assets.xcassets/baseHeroMount.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"baseHeroMount.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"baseHeroMount@2x.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\",\n      \"filename\" : \"baseHeroMount@3x.png\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"zeplin\",\n    \"version\" : \"1\"\n  }\n}"
  },
  {
    "path": "CallKit/CallKitDemo/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "CallKit/CallKitDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16C67\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"CallKitDemo\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"baseHeroMount\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YYx-UX-emU\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"647\"/>\n                            </imageView>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M5B-6m-yHD\">\n                                <rect key=\"frame\" x=\"143\" y=\"318.5\" width=\"89\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Simulate Call\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"receiveCallLucas:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"8EM-RY-UL5\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g8T-fv-bWg\">\n                                <rect key=\"frame\" x=\"68\" y=\"356.5\" width=\"239\" height=\"30\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                <state key=\"normal\" title=\"Simulate Call after 3s(Background)\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"receiveCallLucasAfterThreeSeconds:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"cEH-h5-VOU\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9aI-yW-7Tw\">\n                                <rect key=\"frame\" x=\"149\" y=\"280.5\" width=\"77\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Make a call\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"callButtonPressed:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"eRQ-rc-Kp9\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"YYx-UX-emU\" secondAttribute=\"trailing\" id=\"3jK-fK-jae\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"centerY\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerY\" id=\"5Go-8s-H2G\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"top\" secondItem=\"9aI-yW-7Tw\" secondAttribute=\"bottom\" constant=\"8\" id=\"D14-vC-v4H\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"YYx-UX-emU\" secondAttribute=\"bottom\" id=\"Fga-mw-vE3\"/>\n                            <constraint firstItem=\"g8T-fv-bWg\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"J1U-YB-kys\"/>\n                            <constraint firstItem=\"g8T-fv-bWg\" firstAttribute=\"top\" secondItem=\"M5B-6m-yHD\" secondAttribute=\"bottom\" constant=\"8\" id=\"S8a-NF-fyJ\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"TpI-O1-PZx\"/>\n                            <constraint firstItem=\"YYx-UX-emU\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" id=\"jn7-Kc-DzS\"/>\n                            <constraint firstItem=\"YYx-UX-emU\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"myS-Ve-QB6\"/>\n                            <constraint firstItem=\"9aI-yW-7Tw\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"rra-Ar-7og\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"callButton\" destination=\"9aI-yW-7Tw\" id=\"Kh9-cg-IdH\"/>\n                        <outlet property=\"simulateCallButton\" destination=\"M5B-6m-yHD\" id=\"U2Q-QK-ta3\"/>\n                        <outlet property=\"simulateCallButton2\" destination=\"g8T-fv-bWg\" id=\"ABY-0C-tDn\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"32.799999999999997\" y=\"93.103448275862078\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"baseHeroMount\" width=\"374\" height=\"667\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "CallKit/CallKitDemo/CallKitDemo-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n\n#import \"OTDefaultAudioDevice.h\"\n"
  },
  {
    "path": "CallKit/CallKitDemo/CallKitDemo.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>aps-environment</key>\n\t<string>development</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "CallKit/CallKitDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleURLTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>CFBundleURLName</key>\n\t\t\t<string>$(PRODUCT_BUNDLE_IDENTIFIER).url-scheme.dial</string>\n\t\t\t<key>CFBundleURLSchemes</key>\n\t\t\t<array>\n\t\t\t\t<string>callkitdemo</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>$(PRODUCT_NAME) uses camera</string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string>$(PRODUCT_NAME) uses microphone</string>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>audio</string>\n\t\t<string>fetch</string>\n\t\t<string>remote-notification</string>\n\t\t<string>voip</string>\n\t</array>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "CallKit/CallKitDemo/OTDefaultAudioDevice.h",
    "content": "//\n//  OTAudioDeviceIOSDefault.h\n//\n//  Copyright (c) 2014 TokBox, Inc. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <OpenTok/OpenTok.h>\n\n#define kMixerInputBusCount 2\n#define kOutputBus 0\n#define kInputBus 1\n\n#define AUDIO_DEVICE_HEADSET     @\"AudioSessionManagerDevice_Headset\"\n#define AUDIO_DEVICE_BLUETOOTH   @\"AudioSessionManagerDevice_Bluetooth\"\n#define AUDIO_DEVICE_SPEAKER     @\"AudioSessionManagerDevice_Speaker\"\n\n\n@interface OTDefaultAudioDevice : NSObject <OTAudioDevice>\n{\n    AudioStreamBasicDescription stream_format;\n}\n\n/**\n Returns YES if a wired headset is available.\n */\n@property (nonatomic, readonly) BOOL headsetDeviceAvailable;\n\n/**\n Returns YES if a bluetooth device is available.\n */\n@property (nonatomic, readonly) BOOL bluetoothDeviceAvailable;\n\n- (BOOL)setAudioBus:(id<OTAudioBus>)audioBus;\n\n/**\n * Audio device lifecycle should live for the duration of the process, and\n * needs to be set before OTSession is initialized.\n *\n * It is not recommended to initialize unique audio device instances.\n */\n+ (instancetype)sharedInstance;\n+ (instancetype)sharedInstanceWithAudioSession:(AVAudioSession *)audioSession;\n\n- (OTAudioFormat*)captureFormat;\n- (OTAudioFormat*)renderFormat;\n\n- (BOOL)renderingIsAvailable;\n- (BOOL)initializeRendering;\n- (BOOL)renderingIsInitialized;\n- (BOOL)captureIsAvailable;\n- (BOOL)initializeCapture;\n- (BOOL)captureIsInitialized;\n\n- (BOOL)startRendering;\n- (BOOL)stopRendering;\n- (BOOL)isRendering;\n- (BOOL)startCapture;\n- (BOOL)stopCapture;\n- (BOOL)isCapturing;\n\n- (uint16_t)estimatedRenderDelay;\n- (uint16_t)estimatedCaptureDelay;\n\n//desired Audio Route can be bluetooth and headset.\n//bluetooth has higher priority of all, next headset, next speaker\n- (BOOL)configureAudioSessionWithDesiredAudioRoute:(NSString*)desiredAudioRoute;\n- (BOOL)detectCurrentRoute;\n\n- (BOOL)setPlayOutRenderCallback:(AudioUnit)unit;\n\n@end\n"
  },
  {
    "path": "CallKit/CallKitDemo/OTDefaultAudioDevice.m",
    "content": "//\n//  OTDefaultAudioDeviceIOS.m\n//\n//  Copyright (c) 2014 TokBox, Inc. All rights reserved.\n//\n\n#import \"OTDefaultAudioDevice.h\"\n#import <AudioToolbox/AudioToolbox.h>\n#import <AVFoundation/AVFoundation.h>\n#include <mach/mach.h>\n#include <mach/mach_time.h>\n\n\n/*\n *  System Versioning Preprocessor Macros\n */\n\n#define SYSTEM_VERSION_EQUAL_TO(v) \\\n([[[UIDevice currentDevice] systemVersion] compare:v \\\noptions:NSNumericSearch] == NSOrderedSame)\n#define SYSTEM_VERSION_GREATER_THAN(v) \\\n([[[UIDevice currentDevice] systemVersion] compare:v \\\noptions:NSNumericSearch] == NSOrderedDescending)\n#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) \\\n([[[UIDevice currentDevice] systemVersion] compare:v \\\noptions:NSNumericSearch] != NSOrderedAscending)\n#define SYSTEM_VERSION_LESS_THAN(v) \\\n([[[UIDevice currentDevice] systemVersion] compare:v \\\noptions:NSNumericSearch] == NSOrderedAscending)\n#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) \\\n([[[UIDevice currentDevice] systemVersion] compare:v \\\noptions:NSNumericSearch] != NSOrderedDescending)\n\n\n// Simulator *must* run at 44.1 kHz in order to function properly.\n#if (TARGET_IPHONE_SIMULATOR)\n#define kSampleRate 44100\n#else\n#define kSampleRate 48000\n#endif\n\n#define OT_ENABLE_AUDIO_DEBUG 0\n\n#if OT_ENABLE_AUDIO_DEBUG\n#define OT_AUDIO_DEBUG(fmt, ...) NSLog(fmt, ##__VA_ARGS__)\n#else\n#define OT_AUDIO_DEBUG(fmt, ...)\n#endif\n\nstatic double kPreferredIOBufferDuration = 0.01;\n\nstatic mach_timebase_info_data_t info;\n\nstatic OSStatus recording_cb(void *ref_con,\n                             AudioUnitRenderActionFlags *action_flags,\n                             const AudioTimeStamp *time_stamp,\n                             UInt32 bus_num,\n                             UInt32 num_frames,\n                             AudioBufferList *data);\n\nstatic OSStatus playout_cb(void *ref_con,\n                           AudioUnitRenderActionFlags *action_flags,\n                           const AudioTimeStamp *time_stamp,\n                           UInt32 bus_num,\n                           UInt32 num_frames,\n                           AudioBufferList *data);\n\n@interface OTDefaultAudioDevice ()\n- (BOOL) setupAudioUnit:(AudioUnit *)voice_unit playout:(BOOL)isPlayout;\n- (void) setupListenerBlocks;\n@property (assign) BOOL isAudioSessionSetup;\n@end\n\n\n\n@implementation OTDefaultAudioDevice\n{\n    OTAudioFormat *_audioFormat;\n    \n    AudioUnit recording_voice_unit;\n    AudioUnit playout_voice_unit;\n    BOOL playing;\n    BOOL playout_initialized;\n    BOOL recording;\n    BOOL recording_initialized;\n    BOOL interrupted_playback;\n    NSString* _previousAVAudioSessionCategory;\n    NSString* avAudioSessionMode;\n    double avAudioSessionPreffSampleRate;\n    NSInteger avAudioSessionChannels;\n    BOOL isRecorderInterrupted;\n    BOOL isPlayerInterrupted;\n    BOOL areListenerBlocksSetup;\n    BOOL _isResetting;\n    int _restartRetryCount;\n    AVAudioSession* _avAudioSession;\n    \n    /* synchronize all access to the audio subsystem */\n    dispatch_queue_t _safetyQueue;\n    \n@public\n    id _audioBus;\n    \n    AudioBufferList *buffer_list;\n    uint32_t buffer_num_frames;\n    uint32_t buffer_size;\n    uint32_t _recordingDelay;\n    uint32_t _playoutDelay;\n    uint32_t _playoutDelayMeasurementCounter;\n    uint32_t _recordingDelayHWAndOS;\n    uint32_t _recordingDelayMeasurementCounter;\n    Float64 _playout_AudioUnitProperty_Latency;\n    Float64 _recording_AudioUnitProperty_Latency;\n}\n\n#pragma mark - OTAudioDeviceImplementation\n\n- (instancetype)init\n{\n    self = [super init];\n    if (self) {\n        _audioFormat = [[OTAudioFormat alloc] init];\n        _audioFormat.sampleRate = kSampleRate;\n        _audioFormat.numChannels = 1;\n        _safetyQueue = dispatch_queue_create(\"ot-audio-driver\",\n                                             DISPATCH_QUEUE_SERIAL);\n        _restartRetryCount = 0;\n    }\n    return self;\n}\n\n+ (instancetype)sharedInstance {\n    static OTDefaultAudioDevice* _sharedInstance;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        _sharedInstance = [[OTDefaultAudioDevice alloc] init];\n        [_sharedInstance setupAudioSession:nil];\n    });\n    return _sharedInstance;\n}\n\n+ (instancetype)sharedInstanceWithAudioSession:(AVAudioSession *)audioSession\n{\n    static OTDefaultAudioDevice* _sharedInstance;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        _sharedInstance = [[OTDefaultAudioDevice alloc] init];\n        [_sharedInstance setupAudioSession:audioSession];\n    });\n    return _sharedInstance;\n}\n\n- (BOOL)setAudioBus:(id<OTAudioBus>)audioBus\n{\n    _audioBus = audioBus;\n    _audioFormat = [[OTAudioFormat alloc] init];\n    _audioFormat.sampleRate = kSampleRate;\n    _audioFormat.numChannels = 1;\n    \n    return YES;\n}\n\n- (void)dealloc\n{\n    [self removeObservers];\n    [self teardownAudio];\n    _audioFormat = nil;\n}\n\n- (OTAudioFormat*)captureFormat\n{\n    return _audioFormat;\n}\n\n- (OTAudioFormat*)renderFormat\n{\n    return _audioFormat;\n}\n\n- (BOOL)renderingIsAvailable\n{\n    return YES;\n}\n\n// Audio Unit lifecycle is bound to start/stop cycles, so we don't have much\n// to do here.\n- (BOOL)initializeRendering\n{\n    if (playing) {\n        return NO;\n    }\n    if (playout_initialized) {\n        return YES;\n    }\n    playout_initialized = true;\n    return YES;\n}\n\n- (BOOL)renderingIsInitialized\n{\n    return playout_initialized;\n}\n\n- (BOOL)captureIsAvailable\n{\n    return YES;\n}\n\n// Audio Unit lifecycle is bound to start/stop cycles, so we don't have much\n// to do here.\n- (BOOL)initializeCapture\n{\n    if (recording) {\n        return NO;\n    }\n    if (recording_initialized) {\n        return YES;\n    }\n    recording_initialized = true;\n    return YES;\n}\n\n- (BOOL)captureIsInitialized\n{\n    return recording_initialized;\n}\n\n- (BOOL)startRendering\n{\n    @synchronized(self) {\n        OT_AUDIO_DEBUG(@\"startRendering %d\", playing);\n        \n        if (playing) {\n            return YES;\n        }\n        \n        playing = YES;\n        // Initialize only when playout voice unit is already teardown\n        if(playout_voice_unit == NULL)\n        {\n            if (NO == [self setupAudioUnit:&playout_voice_unit playout:YES]) {\n                playing = NO;\n                return NO;\n            }\n        }\n        \n        OSStatus result = AudioOutputUnitStart(playout_voice_unit);\n        if (CheckError(result, @\"startRendering.AudioOutputUnitStart\")) {\n            playing = NO;\n        }\n        \n        return playing;\n    }\n}\n\n- (BOOL)stopRendering\n{\n    @synchronized(self) {\n        OT_AUDIO_DEBUG(@\"stopRendering %d\", playing);\n        isPlayerInterrupted = NO;\n        if (!playing) {\n            return YES;\n        }\n        \n        playing = NO;\n        \n        OSStatus result = AudioOutputUnitStop(playout_voice_unit);\n        if (CheckError(result, @\"stopRendering.AudioOutputUnitStop\")) {\n            return NO;\n        }\n        \n        // publisher is already closed\n        if (!recording && !_isResetting)\n        {\n            OT_AUDIO_DEBUG(@\"teardownAudio from stopRendering\");\n            [self teardownAudio];\n        }\n\n        return YES;\n    }\n}\n\n- (BOOL)isRendering\n{\n    return playing;\n}\n\n- (BOOL)startCapture\n{\n    @synchronized(self) {\n        OT_AUDIO_DEBUG(@\"startCapture %d\", recording);\n        \n        if (recording) {\n            return YES;\n        }\n        \n        recording = YES;\n        // Initialize only when recording voice unit is already teardown\n        if(recording_voice_unit == NULL)\n        {\n            if (NO == [self setupAudioUnit:&recording_voice_unit playout:NO]) {\n                recording = NO;\n                return NO;\n            }\n        }\n        \n        OSStatus result = AudioOutputUnitStart(recording_voice_unit);\n        if (CheckError(result, @\"startCapture.AudioOutputUnitStart\")) {\n            recording = NO;\n        }\n        \n        return recording;\n    }\n}\n\n- (BOOL)stopCapture\n{\n    @synchronized(self) {\n        OT_AUDIO_DEBUG(@\"stopCapture %d\", recording);\n        isRecorderInterrupted = NO;\n        if (!recording) {\n            return YES;\n        }\n        \n        recording = NO;\n        \n        OSStatus result = AudioOutputUnitStop(recording_voice_unit);\n        \n        if (CheckError(result, @\"stopCapture.AudioOutputUnitStop\")) {\n            return NO;\n        }\n        \n        [self freeupAudioBuffers];\n        \n        // subscriber is already closed\n        if (!playing && !_isResetting)\n        {\n            OT_AUDIO_DEBUG(@\"teardownAudio from stopCapture\");\n            [self teardownAudio];\n        }\n        return YES;\n    }\n}\n\n- (BOOL)isCapturing\n{\n    return recording;\n}\n\n- (uint16_t)estimatedRenderDelay\n{\n    return _playoutDelay;\n}\n\n- (uint16_t)estimatedCaptureDelay\n{\n    return _recordingDelay;\n}\n\n#pragma mark - AudioSession Setup\n\nstatic NSString* FormatError(OSStatus error)\n{\n    uint32_t as_int = CFSwapInt32HostToLittle(error);\n    uint8_t* as_char = (uint8_t*) &as_int;\n    // see if it appears to be a 4-char-code\n    if (isprint(as_char[0]) &&\n        isprint(as_char[1]) &&\n        isprint(as_char[2]) &&\n        isprint(as_char[3]))\n    {\n        return [NSString stringWithFormat:@\"%c%c%c%c\",\n                as_int >> 24, as_int >> 16, as_int >> 8, as_int];\n    }\n    else\n    {\n        // no, format it as an integer\n        return [NSString stringWithFormat:@\"%d\", error];\n    }\n}\n\n/**\n * @return YES if in error\n */\nstatic bool CheckError(OSStatus error, NSString* function) {\n    if (!error) return NO;\n    \n    NSString* error_string = FormatError(error);\n    NSLog(@\"ERROR[OpenTok]:Audio device error: %@ returned error: %@\",\n          function, error_string);\n    \n    return YES;\n}\n\n- (void)checkAndPrintError:(OSStatus)error function:(NSString *)function\n{\n    CheckError(error,function);\n}\n\n- (void)disposePlayoutUnit\n{\n    if (playout_voice_unit) {\n        AudioUnitUninitialize(playout_voice_unit);\n        AudioComponentInstanceDispose(playout_voice_unit);\n        playout_voice_unit = NULL;\n    }\n}\n\n- (void)disposeRecordUnit\n{\n    if (recording_voice_unit) {\n        AudioUnitUninitialize(recording_voice_unit);\n        AudioComponentInstanceDispose(recording_voice_unit);\n        recording_voice_unit = NULL;\n    }\n}\n\n- (void) teardownAudio\n{\n    [self disposePlayoutUnit];\n    [self disposeRecordUnit];\n    [self freeupAudioBuffers];\n    \n    AVAudioSession *mySession = [AVAudioSession sharedInstance];\n    [mySession setCategory:_previousAVAudioSessionCategory error:nil];\n    [mySession setMode:avAudioSessionMode error:nil];\n    [mySession setPreferredSampleRate: avAudioSessionPreffSampleRate\n                                error: nil];\n    [mySession setPreferredInputNumberOfChannels:avAudioSessionChannels\n                                           error:nil];\n    \n    self.isAudioSessionSetup = NO;\n}\n\n- (void)freeupAudioBuffers\n{\n    if (buffer_list && buffer_list->mBuffers[0].mData) {\n        free(buffer_list->mBuffers[0].mData);\n        buffer_list->mBuffers[0].mData = NULL;\n    }\n    \n    if (buffer_list) {\n        free(buffer_list);\n        buffer_list = NULL;\n        buffer_num_frames = 0;\n    }\n}\n\n- (void) setupAudioSession\n{\n    AVAudioSession *mySession = [AVAudioSession sharedInstance];\n    _previousAVAudioSessionCategory = mySession.category;\n    avAudioSessionMode = mySession.mode;\n    avAudioSessionPreffSampleRate = mySession.preferredSampleRate;\n    avAudioSessionChannels = mySession.inputNumberOfChannels;\n    \n    [mySession setPreferredSampleRate: kSampleRate error: nil];\n    [mySession setPreferredInputNumberOfChannels:1 error:nil];\n    [mySession setPreferredIOBufferDuration:kPreferredIOBufferDuration\n                                      error:nil];\n    \n    NSError *error = nil;\n    NSUInteger audioOptions = 0;\n#if !(TARGET_OS_TV)\n    audioOptions |= AVAudioSessionCategoryOptionAllowBluetooth ;\n    audioOptions |= AVAudioSessionCategoryOptionDefaultToSpeaker;\n    [mySession setCategory:AVAudioSessionCategoryPlayAndRecord\n               withOptions:audioOptions\n                     error:&error];\n#else\n    [mySession setCategory:AVAudioSessionCategoryPlayback\n               withOptions:audioOptions\n                     error:&error];\n#endif\n    \n    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"7.0\")) {\n        [mySession setMode:AVAudioSessionModeVideoChat error:nil];\n    }\n    else {\n        [mySession setMode:AVAudioSessionModeVoiceChat error:nil];\n    }\n    \n    if (error)\n        OT_AUDIO_DEBUG(@\"Audiosession setCategory %@\",error);\n    \n    error = nil;\n    \n    [self setupListenerBlocks];\n    [mySession setActive:YES error:&error];\n    \n    if (error)\n        OT_AUDIO_DEBUG(@\"Audiosession setActive %@\",error);\n    \n}\n\n- (void) setupAudioSession:(AVAudioSession *)audioSession\n{\n    if (self.isAudioSessionSetup) return;\n    self.isAudioSessionSetup = YES;\n    \n    AVAudioSession *mySession = audioSession;\n    if (mySession == nil) {\n        mySession = [AVAudioSession sharedInstance];\n    }\n    _previousAVAudioSessionCategory = mySession.category;\n    avAudioSessionMode = mySession.mode;\n    avAudioSessionPreffSampleRate = mySession.preferredSampleRate;\n    avAudioSessionChannels = mySession.inputNumberOfChannels;\n    \n    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@\"7.0\")) {\n        [mySession setMode:AVAudioSessionModeVideoChat error:nil];\n    }\n    else {\n        [mySession setMode:AVAudioSessionModeVoiceChat error:nil];\n    }\n    \n    [mySession setPreferredSampleRate: kSampleRate error: nil];\n    [mySession setPreferredInputNumberOfChannels:1 error:nil];\n    [mySession setPreferredIOBufferDuration:kPreferredIOBufferDuration\n                                      error:nil];\n    \n    NSError *error = nil;\n    NSUInteger audioOptions = AVAudioSessionCategoryOptionMixWithOthers;\n#if !(TARGET_OS_TV)\n    audioOptions |= AVAudioSessionCategoryOptionAllowBluetooth ;\n    audioOptions |= AVAudioSessionCategoryOptionDefaultToSpeaker;\n    [mySession setCategory:AVAudioSessionCategoryPlayAndRecord\n               withOptions:audioOptions\n                     error:&error];\n#else\n    [mySession setCategory:AVAudioSessionCategoryPlayback\n               withOptions:audioOptions\n                     error:&error];\n#endif\n    \n    if (error)\n        OT_AUDIO_DEBUG(@\"Audiosession setCategory %@\",error);\n    \n    error = nil;\n    \n    [self setupListenerBlocks];\n    [mySession setActive:YES error:&error];\n    \n    if (error)\n        OT_AUDIO_DEBUG(@\"Audiosession setActive %@\",error);\n    \n}\n\n- (void)setBluetoothAsPrefferedInputDevice\n{\n    // Apple's Bug(???) : Audio Interruption Ended notification won't be called\n    // for bluetooth devices if we dont set preffered input as bluetooth.\n    // Should work for non bluetooth routes/ports too. This makes both input\n    // and output to bluetooth device if available.\n    NSArray* bluetoothRoutes = @[AVAudioSessionPortBluetoothA2DP,\n                                 AVAudioSessionPortBluetoothLE,\n                                 AVAudioSessionPortBluetoothHFP];\n    NSArray* routes = [[AVAudioSession sharedInstance] availableInputs];\n    for (AVAudioSessionPortDescription* route in routes)\n    {\n        if ([bluetoothRoutes containsObject:route.portType])\n        {\n            [[AVAudioSession sharedInstance] setPreferredInput:route\n                                                         error:nil];\n            break;\n        }\n    }\n    \n}\n\n#pragma mark - System interruptions and audio route changes\n\n- (void) onInterruptionEvent:(NSNotification *) notification\n{\n    OT_AUDIO_DEBUG(@\"onInterruptionEvent %@\",notification);\n    \n    NSDictionary *interruptionDict = notification.userInfo;\n    NSInteger interruptionType =\n    [[interruptionDict valueForKey:AVAudioSessionInterruptionTypeKey]\n     integerValue];\n    \n    dispatch_async(_safetyQueue, ^() {\n        [self handleInterruptionEvent:interruptionType];\n    });\n}\n\n- (void) handleInterruptionEvent:(NSInteger) interruptionType\n{\n    @synchronized(self) {\n        OT_AUDIO_DEBUG(@\"handleInterruptionEvent %ld\",(long)interruptionType);\n        switch (interruptionType) {\n            case AVAudioSessionInterruptionTypeBegan:\n            {\n                OT_AUDIO_DEBUG(@\"AVAudioSessionInterruptionTypeBegan\");\n                if(recording)\n                {\n                    // DONT change the order of the following as\n                    // stopCapture sets isRecorderInterrupted to NO\n                    [self stopCapture];\n                    isRecorderInterrupted = YES;\n                }\n                if(playing)\n                {\n                    // DONT change the order of the following as\n                    // stopRendering sets isPlayerInterrupted to NO\n                    [self stopRendering];\n                    isPlayerInterrupted = YES;\n                }\n            }\n                break;\n                \n            case AVAudioSessionInterruptionTypeEnded:\n            {\n                OT_AUDIO_DEBUG(@\"AVAudioSessionInterruptionTypeEnded\");\n                // Reconfigure audio session with highest priority device\n                [self configureAudioSessionWithDesiredAudioRoute:\n                 AUDIO_DEVICE_BLUETOOTH];\n                if(isRecorderInterrupted)\n                {\n                    if([self startCapture] == YES)\n                    {\n                        isRecorderInterrupted = NO;\n                        _restartRetryCount = 0;\n                    } else\n                    {\n                        _restartRetryCount++;\n                        if(_restartRetryCount < 3)\n                        {\n                            dispatch_after(\n                                           dispatch_time(\n                                                         DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),\n                                           _safetyQueue, ^{\n                                               [self handleInterruptionEvent:\n                                                AVAudioSessionInterruptionTypeEnded];\n                                           });\n                        } else // This shouldn't happen!\n                        {\n                            // When a call get resumed, we get first audio interruption notification from iOS\n                            // but the audio fails, since iOS holds the audio session until user presses \"Unhold call\",\n                            // When user press \"Unhold call\" we post a fake interruption notification from \"didActivate\" audioSession callback\n                            // So for the second time, we need to keep isRecorderInterrupted and isPlayerInterrupted to YES.\n                            // The reason for this hack is, we don't want to modify the audio driver much to avoid future audio driver\n                            // upgrades from iOS SDK internal driver.\n                            //isRecorderInterrupted = NO;\n                            //isPlayerInterrupted = NO;\n                            _restartRetryCount = 0;\n                            NSLog(@\"ERROR[OpenTok]:Unable to acquire audio session\");\n                        }\n                        return;\n                    }\n                }\n                \n                if(isPlayerInterrupted)\n                {\n                    isPlayerInterrupted = NO;\n                    [self startRendering];\n                }\n                \n            }\n                break;\n                \n            default:\n                OT_AUDIO_DEBUG(@\"Audio Session Interruption Notification\"\n                               \" case default.\");\n                break;\n        }\n    }\n}\n\n- (void) onRouteChangeEvent:(NSNotification *) notification\n{\n    OT_AUDIO_DEBUG(@\"onRouteChangeEvent %@\",notification);\n    dispatch_async(_safetyQueue, ^() {\n        [self handleRouteChangeEvent:notification];\n    });\n}\n\n- (void) handleRouteChangeEvent:(NSNotification *) notification\n{\n    NSDictionary *interruptionDict = notification.userInfo;\n    NSInteger routeChangeReason =\n    [[interruptionDict valueForKey:AVAudioSessionRouteChangeReasonKey]\n     integerValue];\n    \n    // We'll receive a routeChangedEvent when the audio unit starts; don't\n    // process events we caused internally.\n    if (AVAudioSessionRouteChangeReasonRouteConfigurationChange ==\n        routeChangeReason)\n    {\n        return;\n    }\n    \n    if(routeChangeReason == AVAudioSessionRouteChangeReasonOverride ||\n       routeChangeReason == AVAudioSessionRouteChangeReasonCategoryChange)\n    {\n        NSString *oldOutputDeviceName = nil;\n        NSString *currentOutputDeviceName = nil;\n        \n        AVAudioSessionRouteDescription* oldRouteDesc =\n        [interruptionDict valueForKey:AVAudioSessionRouteChangePreviousRouteKey];\n        NSArray<AVAudioSessionPortDescription*>* outputs =\n        [oldRouteDesc outputs];\n        \n        if(outputs.count > 0)\n        {\n            AVAudioSessionPortDescription *portDesc =\n            (AVAudioSessionPortDescription *)[outputs objectAtIndex:0];\n            oldOutputDeviceName = [portDesc portName];\n        }\n        \n        if([[[AVAudioSession sharedInstance] currentRoute] outputs].count > 0)\n        {\n            currentOutputDeviceName = [[[[[AVAudioSession sharedInstance] currentRoute] outputs]\n                                        objectAtIndex:0] portName];\n        }\n        \n        // we need check this because some times we will receive category change\n        // with the same device.\n        if([oldOutputDeviceName isEqualToString:currentOutputDeviceName] ||\n           currentOutputDeviceName == nil ||  oldOutputDeviceName == nil) {\n            return;\n        }\n        OT_AUDIO_DEBUG(@\"routeChanged: old=%@ new=%@\",\n                       oldOutputDeviceName, currentOutputDeviceName);\n    }\n    \n    @synchronized(self) {\n        // We've made it here, there's been a legit route change.\n        // Restart the audio units with correct sample rate\n        _isResetting = YES;\n        \n        if (recording)\n        {\n            [self stopCapture];\n            [self disposeRecordUnit];\n            [self startCapture];\n        }\n        \n        if (playing)\n        {\n            [self stopRendering];\n            [self disposePlayoutUnit];\n            [self startRendering];\n        }\n        \n        _isResetting = NO;\n    }\n    \n}\n\n/* When ringer is off, we dont get interruption ended callback\n as mentioned in apple doc : \"There is no guarantee that a begin\n interruption will have an end interruption.\"\n The only caveat here is, some times we get two callbacks from interruption\n handler as well as from here which we handle synchronously with safteyQueue\n */\n- (void) appDidBecomeActive:(NSNotification *) notification\n{\n    OT_AUDIO_DEBUG(@\"appDidBecomeActive %@\",notification);\n    dispatch_async(_safetyQueue, ^{\n        [self handleInterruptionEvent:AVAudioSessionInterruptionTypeEnded];\n    });\n}\n\n- (void) setupListenerBlocks\n{\n    if(!areListenerBlocksSetup)\n    {\n        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];\n        \n        [center addObserver:self\n                   selector:@selector(onInterruptionEvent:)\n                       name:AVAudioSessionInterruptionNotification object:nil];\n        \n        [center addObserver:self\n                   selector:@selector(onRouteChangeEvent:)\n                       name:AVAudioSessionRouteChangeNotification object:nil];\n        \n        [center addObserver:self\n                   selector:@selector(appDidBecomeActive:)\n                       name:UIApplicationDidBecomeActiveNotification\n                     object:nil];\n        \n        areListenerBlocksSetup = YES;\n    }\n}\n\n- (void) removeObservers\n{\n    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];\n    [center removeObserver:self];\n    areListenerBlocksSetup = NO;\n}\n\n#pragma mark - native audio callbacks\n\nstatic void update_recording_delay(OTDefaultAudioDevice* device) {\n    \n    device->_recordingDelayMeasurementCounter++;\n    \n    if (device->_recordingDelayMeasurementCounter >= 100) {\n        // Update HW and OS delay every second, unlikely to change\n        \n        device->_recordingDelayHWAndOS = 0;\n        \n        AVAudioSession *mySession = [AVAudioSession sharedInstance];\n        \n        // HW input latency\n        NSTimeInterval interval = [mySession inputLatency];\n        \n        device->_recordingDelayHWAndOS += (int)(interval * 1000000);\n        \n        // HW buffer duration\n        interval = [mySession IOBufferDuration];\n        device->_recordingDelayHWAndOS += (int)(interval * 1000000);\n        \n        device->_recordingDelayHWAndOS += (int)(device->_recording_AudioUnitProperty_Latency * 1000000);\n        \n        // To ms\n        device->_recordingDelayHWAndOS =\n        (device->_recordingDelayHWAndOS - 500) / 1000;\n        \n        // Reset counter\n        device->_recordingDelayMeasurementCounter = 0;\n    }\n    \n    device->_recordingDelay = device->_recordingDelayHWAndOS;\n}\n\nstatic OSStatus recording_cb(void *ref_con,\n                             AudioUnitRenderActionFlags *action_flags,\n                             const AudioTimeStamp *time_stamp,\n                             UInt32 bus_num,\n                             UInt32 num_frames,\n                             AudioBufferList *data)\n{\n    \n    OTDefaultAudioDevice *dev = (__bridge OTDefaultAudioDevice*) ref_con;\n    \n    if (!dev->buffer_list || num_frames > dev->buffer_num_frames)\n    {\n        if (dev->buffer_list) {\n            free(dev->buffer_list->mBuffers[0].mData);\n            free(dev->buffer_list);\n        }\n        \n        dev->buffer_list =\n        (AudioBufferList*)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer));\n        dev->buffer_list->mNumberBuffers = 1;\n        dev->buffer_list->mBuffers[0].mNumberChannels = 1;\n        \n        dev->buffer_list->mBuffers[0].mDataByteSize = num_frames*sizeof(UInt16);\n        dev->buffer_list->mBuffers[0].mData = malloc(num_frames*sizeof(UInt16));\n        \n        dev->buffer_num_frames = num_frames;\n        dev->buffer_size = dev->buffer_list->mBuffers[0].mDataByteSize;\n    }\n    \n    OSStatus status;\n    status = AudioUnitRender(dev->recording_voice_unit,\n                             action_flags,\n                             time_stamp,\n                             1,\n                             num_frames,\n                             dev->buffer_list);\n    \n    if (status != noErr) {\n        CheckError(status, @\"AudioUnitRender\");\n    }\n    \n    if (dev->recording) {\n        \n        // Some sample code to generate a sine wave instead of use the mic\n        //        static double startingFrameCount = 0;\n        //        double j = startingFrameCount;\n        //        double cycleLength = kSampleRate. / 880.0;\n        //        int frame = 0;\n        //        for (frame = 0; frame < num_frames; ++frame)\n        //        {\n        //            int16_t* data = (int16_t*)dev->buffer_list->mBuffers[0].mData;\n        //            Float32 sample = (Float32)sin (2 * M_PI * (j / cycleLength));\n        //            (data)[frame] = (sample * 32767.0f);\n        //            j += 1.0;\n        //            if (j > cycleLength)\n        //                j -= cycleLength;\n        //        }\n        //        startingFrameCount = j;\n        [dev->_audioBus writeCaptureData:dev->buffer_list->mBuffers[0].mData\n                         numberOfSamples:num_frames];\n    }\n    // some ocassions, AudioUnitRender only renders part of the buffer and then next\n    // call to the AudioUnitRender fails with smaller buffer.\n    if (dev->buffer_size != dev->buffer_list->mBuffers[0].mDataByteSize)\n        dev->buffer_list->mBuffers[0].mDataByteSize = dev->buffer_size;\n    \n    update_recording_delay(dev);\n    \n    return noErr;\n}\n\nstatic void update_playout_delay(OTDefaultAudioDevice* device) {\n    device->_playoutDelayMeasurementCounter++;\n    \n    if (device->_playoutDelayMeasurementCounter >= 100) {\n        // Update HW and OS delay every second, unlikely to change\n        \n        device->_playoutDelay = 0;\n        \n        AVAudioSession *mySession = [AVAudioSession sharedInstance];\n        \n        // HW output latency\n        NSTimeInterval interval = [mySession outputLatency];\n        \n        device->_playoutDelay += (int)(interval * 1000000);\n        \n        // HW buffer duration\n        interval = [mySession IOBufferDuration];\n        device->_playoutDelay += (int)(interval * 1000000);\n        \n        device->_playoutDelay += (int)(device->_playout_AudioUnitProperty_Latency * 1000000);\n        \n        // To ms\n        device->_playoutDelay = (device->_playoutDelay - 500) / 1000;\n        \n        // Reset counter\n        device->_playoutDelayMeasurementCounter = 0;\n    }\n}\n\nstatic OSStatus playout_cb(void *ref_con,\n                           AudioUnitRenderActionFlags *action_flags,\n                           const AudioTimeStamp *time_stamp,\n                           UInt32 bus_num,\n                           UInt32 num_frames,\n                           AudioBufferList *buffer_list)\n{\n    OTDefaultAudioDevice *dev = (__bridge OTDefaultAudioDevice*) ref_con;\n    \n    if (!dev->playing) { return 0; }\n    \n    uint32_t count =\n    [dev->_audioBus readRenderData:buffer_list->mBuffers[0].mData\n                   numberOfSamples:num_frames];\n    \n    if (count != num_frames) {\n        //TODO: Not really an error, but conerning. Network issues?\n    }\n    \n    update_playout_delay(dev);\n    \n    return 0;\n}\n\n#pragma mark - BlueTooth\n\n- (BOOL)isBluetoothDevice:(NSString*)portType {\n    \n    return ([portType isEqualToString:AVAudioSessionPortBluetoothA2DP] ||\n            [portType isEqualToString:AVAudioSessionPortBluetoothHFP]);\n}\n\n\n- (BOOL)detectCurrentRoute\n{\n    // called on startup to initialize the devices that are available...\n    OT_AUDIO_DEBUG(@\"detect current route\");\n    \n    AVAudioSession *audioSession = [AVAudioSession sharedInstance];\n    \n    _headsetDeviceAvailable = _bluetoothDeviceAvailable = NO;\n    \n    //ios 8.0 complains about Deactivating an audio session that has running\n    // I/O. All I/O should be stopped or paused prior to deactivating the audio\n    // session. Looks like we can get away by not using the setActive call\n    if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@\"7.0\")) {\n        // close down our current session...\n        [audioSession setActive:NO error:nil];\n        \n        // start a new audio session. Without activation, the default route will\n        // always be (inputs: null, outputs: Speaker)\n        [audioSession setActive:YES error:nil];\n    }\n    \n    // Check for current route\n    AVAudioSessionRouteDescription *currentRoute = [audioSession currentRoute];\n    for (AVAudioSessionPortDescription *output in currentRoute.outputs) {\n        if ([[output portType] isEqualToString:AVAudioSessionPortHeadphones]) {\n            _headsetDeviceAvailable = YES;\n        } else if ([self isBluetoothDevice:[output portType]]) {\n            _bluetoothDeviceAvailable = YES;\n        }\n    }\n    \n    if (_headsetDeviceAvailable) {\n        OT_AUDIO_DEBUG(@\"Current route is Headset\");\n    }\n    \n    if (_bluetoothDeviceAvailable) {\n        OT_AUDIO_DEBUG(@\"Current route is Bluetooth\");\n    }\n    \n    if(!_bluetoothDeviceAvailable && !_headsetDeviceAvailable) {\n        OT_AUDIO_DEBUG(@\"Current route is device speaker\");\n    }\n    \n    return YES;\n}\n\n- (BOOL)configureAudioSessionWithDesiredAudioRoute:(NSString*)desiredAudioRoute\n{\n    OT_AUDIO_DEBUG(@\"configureAudioSessionWithDesiredAudioRoute %@\",desiredAudioRoute);\n    \n    AVAudioSession *audioSession = [AVAudioSession sharedInstance];\n    NSError *err;\n    \n    //ios 8.0 complains about Deactivating an audio session that has running\n    // I/O. All I/O should be stopped or paused prior to deactivating the audio\n    // session. Looks like we can get away by not using the setActive call\n    if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@\"7.0\")) {\n        // close down our current session...\n        [audioSession setActive:NO error:nil];\n    }\n    \n    if ([AUDIO_DEVICE_BLUETOOTH isEqualToString:desiredAudioRoute]) {\n        [self setBluetoothAsPrefferedInputDevice];\n    }\n    \n    if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@\"7.0\")) {\n        // Set our session to active...\n        if (![audioSession setActive:YES error:&err]) {\n            NSLog(@\"unable to set audio session active: %@\", err);\n            return NO;\n        }\n    }\n    \n    if ([AUDIO_DEVICE_SPEAKER isEqualToString:desiredAudioRoute]) {\n        // replace AudiosessionSetProperty (deprecated from iOS7) with\n        // AVAudioSession overrideOutputAudioPort\n#if !(TARGET_OS_TV)\n        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker\n                                        error:&err];\n#endif\n    } else\n    {\n        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone\n                                        error:&err];\n    }\n    \n    return YES;\n}\n\n- (BOOL)setupAudioUnit:(AudioUnit *)voice_unit playout:(BOOL)isPlayout;\n{\n    OSStatus result;\n    \n    mach_timebase_info(&info);\n    \n    if (!self.isAudioSessionSetup)\n    {\n        [self setupAudioSession];\n        self.isAudioSessionSetup = YES;\n    }\n    \n    UInt32 bytesPerSample = sizeof(SInt16);\n    stream_format.mFormatID    = kAudioFormatLinearPCM;\n    stream_format.mFormatFlags =\n    kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;\n    stream_format.mBytesPerPacket  = bytesPerSample;\n    stream_format.mFramesPerPacket = 1;\n    stream_format.mBytesPerFrame   = bytesPerSample;\n    stream_format.mChannelsPerFrame= 1;\n    stream_format.mBitsPerChannel  = 8 * bytesPerSample;\n    stream_format.mSampleRate = (Float64) kSampleRate;\n    \n    AudioComponentDescription audio_unit_description;\n    audio_unit_description.componentType = kAudioUnitType_Output;\n    \n#if !(TARGET_OS_TV)\n    audio_unit_description.componentSubType = kAudioUnitSubType_VoiceProcessingIO;\n#else\n    audio_unit_description.componentSubType = kAudioUnitSubType_RemoteIO;\n#endif\n    \n    audio_unit_description.componentManufacturer = kAudioUnitManufacturer_Apple;\n    audio_unit_description.componentFlags = 0;\n    audio_unit_description.componentFlagsMask = 0;\n    \n    AudioComponent found_vpio_unit_ref =\n    AudioComponentFindNext(NULL, &audio_unit_description);\n    \n    result = AudioComponentInstanceNew(found_vpio_unit_ref, voice_unit);\n    \n    if (CheckError(result, @\"setupAudioUnit.AudioComponentInstanceNew\")) {\n        return NO;\n    }\n    \n    if (!isPlayout)\n    {\n        UInt32 enable_input = 1;\n        AudioUnitSetProperty(*voice_unit, kAudioOutputUnitProperty_EnableIO,\n                             kAudioUnitScope_Input, kInputBus, &enable_input,\n                             sizeof(enable_input));\n        AudioUnitSetProperty(*voice_unit, kAudioUnitProperty_StreamFormat,\n                             kAudioUnitScope_Output, kInputBus,\n                             &stream_format, sizeof (stream_format));\n        AURenderCallbackStruct input_callback;\n        input_callback.inputProc = recording_cb;\n        input_callback.inputProcRefCon = (__bridge void *)(self);\n        \n        AudioUnitSetProperty(*voice_unit,\n                             kAudioOutputUnitProperty_SetInputCallback,\n                             kAudioUnitScope_Global, kInputBus, &input_callback,\n                             sizeof(input_callback));\n        UInt32 flag = 0;\n        AudioUnitSetProperty(*voice_unit, kAudioUnitProperty_ShouldAllocateBuffer,\n                             kAudioUnitScope_Output, kInputBus, &flag,\n                             sizeof(flag));\n        // Disable Output on record\n        UInt32 enable_output = 0;\n        AudioUnitSetProperty(*voice_unit, kAudioOutputUnitProperty_EnableIO,\n                             kAudioUnitScope_Output, kOutputBus, &enable_output,\n                             sizeof(enable_output));\n        \n    } else\n    {\n        UInt32 enable_output = 1;\n        AudioUnitSetProperty(*voice_unit, kAudioOutputUnitProperty_EnableIO,\n                             kAudioUnitScope_Output, kOutputBus, &enable_output,\n                             sizeof(enable_output));\n        AudioUnitSetProperty(*voice_unit, kAudioUnitProperty_StreamFormat,\n                             kAudioUnitScope_Input, kOutputBus,\n                             &stream_format, sizeof (stream_format));\n        // Disable Input on playout\n        UInt32 enable_input = 0;\n        AudioUnitSetProperty(*voice_unit, kAudioOutputUnitProperty_EnableIO,\n                             kAudioUnitScope_Input, kInputBus, &enable_input,\n                             sizeof(enable_input));\n        [self setPlayOutRenderCallback:*voice_unit];\n    }\n    \n    Float64 f64 = 0;\n    UInt32 size = sizeof(f64);\n    OSStatus latency_result = AudioUnitGetProperty(*voice_unit,\n                                                   kAudioUnitProperty_Latency,\n                                                   kAudioUnitScope_Global,\n                                                   0, &f64, &size);\n    if (!isPlayout)\n    {\n        _recording_AudioUnitProperty_Latency = (0 == latency_result) ? f64 : 0;\n    }\n    else\n    {\n        _playout_AudioUnitProperty_Latency = (0 == latency_result) ? f64 : 0;\n    }\n    \n    // Initialize the Voice-Processing I/O unit instance.\n    result = AudioUnitInitialize(*voice_unit);\n    if (CheckError(result, @\"setupAudioUnit.AudioUnitInitialize\")) {\n        return NO;\n    }\n    \n    [self setBluetoothAsPrefferedInputDevice];\n    return YES;\n}\n\n- (BOOL)setPlayOutRenderCallback:(AudioUnit)unit\n{\n    AURenderCallbackStruct render_callback;\n    render_callback.inputProc = playout_cb;;\n    render_callback.inputProcRefCon = (__bridge void *)(self);\n    OSStatus result = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback,\n                                           kAudioUnitScope_Input, kOutputBus, &render_callback,\n                                           sizeof(render_callback));\n    return (result == 0);\n}\n\n@end\n"
  },
  {
    "path": "CallKit/CallKitDemo/ProviderDelegate.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tCallKit provider delegate class, which conforms to CXProviderDelegate protocol\n*/\n\nimport Foundation\nimport UIKit\nimport CallKit\nimport AVFoundation\nimport OpenTok\n\nfinal class ProviderDelegate: NSObject, CXProviderDelegate {\n\n    let callManager: SpeakerboxCallManager\n    private let provider: CXProvider\n\n    init(callManager: SpeakerboxCallManager) {\n        self.callManager = callManager\n        provider = CXProvider(configuration: type(of: self).providerConfiguration)\n\n        super.init()\n\n        provider.setDelegate(self, queue: nil)\n    }\n\n    /// The app's provider configuration, representing its CallKit capabilities\n    static var providerConfiguration: CXProviderConfiguration {\n        let localizedName = NSLocalizedString(\"CallKitDemo\", comment: \"Name of application\")\n        let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)\n\n        providerConfiguration.supportsVideo = false\n\n        providerConfiguration.maximumCallsPerCallGroup = 1\n\n        providerConfiguration.supportedHandleTypes = [.phoneNumber]\n\n        providerConfiguration.iconTemplateImageData = #imageLiteral(resourceName: \"IconMask\").pngData()\n\n        providerConfiguration.ringtoneSound = \"Ringtone.caf\"\n        \n        return providerConfiguration\n    }\n\n    // MARK: Incoming Calls\n\n    /// Use CXProvider to report the incoming call to the system\n    func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {\n        // Construct a CXCallUpdate describing the incoming call, including the caller.\n        let update = CXCallUpdate()\n        update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)\n        update.hasVideo = hasVideo\n\n        // pre-heat the AVAudioSession\n        //OTAudioDeviceManager.setAudioDevice(OTDefaultAudioDevice.sharedInstance())\n        \n        // Report the incoming call to the system\n        provider.reportNewIncomingCall(with: uuid, update: update) { error in\n            /*\n                Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)\n                since calls may be \"denied\" for various legitimate reasons. See CXErrorCodeIncomingCallError.\n             */\n            if error == nil {\n                let call = SpeakerboxCall(uuid: uuid)\n                call.handle = handle\n\n                self.callManager.addCall(call)\n            }\n            \n            completion?(error as NSError?)\n        }\n    }\n\n    // MARK: CXProviderDelegate\n\n    func providerDidReset(_ provider: CXProvider) {\n        print(\"Provider did reset\")\n        /*\n            End any ongoing calls if the provider resets, and remove them from the app's list of calls,\n            since they are no longer valid.\n         */\n    }\n\n    var outgoingCall: SpeakerboxCall?\n    func provider(_ provider: CXProvider, perform action: CXStartCallAction) {\n        // Create & configure an instance of SpeakerboxCall, the app's model class representing the new outgoing call.\n        let call = SpeakerboxCall(uuid: action.callUUID, isOutgoing: true)\n        call.handle = action.handle.value\n\n        /*\n            Configure the audio session, but do not start call audio here, since it must be done once\n            the audio session has been activated by the system after having its priority elevated.\n         */\n        // https://forums.developer.apple.com/thread/64544\n        // we can't configure the audio session here for the case of launching it from locked screen\n        // instead, we have to pre-heat the AVAudioSession by configuring as early as possible, didActivate do not get called otherwise\n        // please look for  * pre-heat the AVAudioSession *\n        configureAudioSession()\n        \n        /*\n            Set callback blocks for significant events in the call's lifecycle, so that the CXProvider may be updated\n            to reflect the updated state.\n         */\n        call.hasStartedConnectingDidChange = { [weak self] in\n            self?.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)\n        }\n        call.hasConnectedDidChange = { [weak self] in\n            self?.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectDate)\n        }\n\n        self.outgoingCall = call\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n\n    var answerCall: SpeakerboxCall?\n    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        /*\n            Configure the audio session, but do not start call audio here, since it must be done once\n            the audio session has been activated by the system after having its priority elevated.\n         */\n        \n        // https://forums.developer.apple.com/thread/64544\n        // we can't configure the audio session here for the case of launching it from locked screen\n        // instead, we have to pre-heat the AVAudioSession by configuring as early as possible, didActivate do not get called otherwise\n        // please look for  * pre-heat the AVAudioSession *\n        configureAudioSession()\n\n        self.answerCall = call\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n\n    \n    func provider(_ provider: CXProvider, perform action: CXEndCallAction) {\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        // Trigger the call to be ended via the underlying network service.\n        call.endCall()\n\n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n\n        // Remove the ended call from the app's list of calls.\n        callManager.removeCall(call)\n    }\n\n    func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        // Update the SpeakerboxCall's underlying hold state.\n        call.isOnHold = action.isOnHold\n\n        // Stop or start audio in response to holding or unholding the call.\n        call.isMuted = call.isOnHold\n\n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n    \n    func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n        \n        call.isMuted = action.isMuted\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n\n    func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {\n        print(\"Timed out \\(#function)\")\n\n        // React to the action timeout if necessary, such as showing an error UI.\n    }\n\n    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {\n        print(\"Received \\(#function)\")\n        \n        // If we are returning from a hold state\n        if answerCall?.hasConnected ?? false {\n            //configureAudioSession()\n            // See more details on how this works in the OTDefaultAudioDevice.m method handleInterruptionEvent\n            sendFakeAudioInterruptionNotificationToStartAudioResources();\n            return\n        }\n        if outgoingCall?.hasConnected ?? false {\n            //configureAudioSession()\n            // See more details on how this works in the OTDefaultAudioDevice.m method handleInterruptionEvent\n            sendFakeAudioInterruptionNotificationToStartAudioResources()\n            return\n        }\n        \n        // Start call audio media, now that the audio session has been activated after having its priority boosted.\n        outgoingCall?.startCall(withAudioSession: audioSession) { [weak self] success in\n            guard let outgoingCall = self?.outgoingCall else { return }\n            if success {\n                self?.callManager.addCall(outgoingCall)\n                self?.outgoingCall?.startAudio()\n            } else {\n                self?.callManager.end(call: outgoingCall)\n            }\n        }\n        \n        answerCall?.answerCall(withAudioSession: audioSession) { success in\n            if success {\n                self.answerCall?.startAudio()\n            }\n        }\n    }\n\n    func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {\n        print(\"Received \\(#function)\")\n\n        /*\n             Restart any non-call related audio now that the app's audio session has been\n             de-activated after having its priority restored to normal.\n         */\n        if outgoingCall?.isOnHold ?? false || answerCall?.isOnHold ?? false {\n            print(\"Call is on hold. Do not terminate any call\")\n            return\n        }\n        \n        outgoingCall?.endCall()\n        outgoingCall = nil\n        answerCall?.endCall()\n        answerCall = nil\n        callManager.removeAllCalls()\n    }\n    \n    func sendFakeAudioInterruptionNotificationToStartAudioResources() {\n        var userInfo = Dictionary<AnyHashable, Any>()\n        let interrupttioEndedRaw = AVAudioSession.InterruptionType.ended.rawValue\n        userInfo[AVAudioSessionInterruptionTypeKey] = interrupttioEndedRaw\n        NotificationCenter.default.post(name: AVAudioSession.interruptionNotification, object: self, userInfo: userInfo)\n    }\n    \n    func configureAudioSession() {\n        // See https://forums.developer.apple.com/thread/64544\n        let session = AVAudioSession.sharedInstance()\n        do {\n            try session.setCategory(AVAudioSession.Category.playAndRecord, mode: .default)\n            try session.setActive(true)\n            try session.setMode(AVAudioSession.Mode.voiceChat)\n            try session.setPreferredSampleRate(44100.0)\n            try session.setPreferredIOBufferDuration(0.005)\n        } catch {\n            print(error)\n        }\n    }\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo/SpeakerboxCall.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tModel class representing a single call\n*/\n\nimport Foundation\nimport OpenTok\n\nfinal class SpeakerboxCall: NSObject {\n\n    // MARK: Metadata Properties\n\n    let uuid: UUID\n    let isOutgoing: Bool\n    var handle: String?\n\n    // MARK: Call State Properties\n\n    var connectingDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasStartedConnectingDidChange?()\n        }\n    }\n    var connectDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasConnectedDidChange?()\n        }\n    }\n    var endDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasEndedDidChange?()\n        }\n    }\n    var isOnHold = false {\n        didSet {\n            publisher?.publishAudio = !isOnHold\n            stateDidChange?()\n        }\n    }\n    \n    var isMuted = false {\n        didSet {\n            publisher?.publishAudio = !isMuted\n        }\n    }\n\n    // MARK: State change callback blocks\n\n    var stateDidChange: (() -> Void)?\n    var hasStartedConnectingDidChange: (() -> Void)?\n    var hasConnectedDidChange: (() -> Void)?\n    var hasEndedDidChange: (() -> Void)?\n    var audioChange: (() -> Void)?\n\n    // MARK: Derived Properties\n\n    var hasStartedConnecting: Bool {\n        get {\n            return connectingDate != nil\n        }\n        set {\n            connectingDate = newValue ? Date() : nil\n        }\n    }\n    var hasConnected: Bool {\n        get {\n            return connectDate != nil\n        }\n        set {\n            connectDate = newValue ? Date() : nil\n        }\n    }\n    var hasEnded: Bool {\n        get {\n            return endDate != nil\n        }\n        set {\n            endDate = newValue ? Date() : nil\n        }\n    }\n    var duration: TimeInterval {\n        guard let connectDate = connectDate else {\n            return 0\n        }\n\n        return Date().timeIntervalSince(connectDate)\n    }\n\n    // MARK: Initialization\n\n    init(uuid: UUID, isOutgoing: Bool = false) {\n        self.uuid = uuid\n        self.isOutgoing = isOutgoing\n    }\n\n    // MARK: Actions\n    var session: OTSession?\n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n    \n    var canStartCall: ((Bool) -> Void)?\n    func startCall(withAudioSession audioSession: AVAudioSession, completion: ((_ success: Bool) -> Void)?) {\n        OTAudioDeviceManager.setAudioDevice(OTDefaultAudioDevice.sharedInstance(with: audioSession))\n        if session == nil {\n            session = OTSession(apiKey: apiKey, sessionId: sessionId, delegate: self)\n        }\n        canStartCall = completion\n        \n        var error: OTError?\n        hasStartedConnecting = true\n        session?.connect(withToken: token, error: &error)\n        if error != nil {\n            print(error!)\n        }\n    }\n    \n    var canAnswerCall: ((Bool) -> Void)?\n    func answerCall(withAudioSession audioSession: AVAudioSession, completion: ((_ success: Bool) -> Void)?) {\n        OTAudioDeviceManager.setAudioDevice(OTDefaultAudioDevice.sharedInstance(with: audioSession))\n        if session == nil {\n            session = OTSession(apiKey: apiKey, sessionId: sessionId, delegate: self)\n        }\n        \n        canAnswerCall = completion\n        \n        var error: OTError?\n        hasStartedConnecting = true\n        session?.connect(withToken: token, error: &error)\n        if error != nil {\n            print(error!)\n        }\n    }\n    \n    func startAudio() {\n        if publisher == nil {\n            let settings = OTPublisherSettings()\n            settings.name = UIDevice.current.name\n            settings.audioTrack = true\n            settings.videoTrack = false\n            publisher = OTPublisher.init(delegate: self, settings: settings)\n        }\n        \n        var error: OTError?\n        session?.publish(publisher!, error: &error)\n        if error != nil {\n            print(error!)\n        }\n    }\n    \n    func endCall() {\n        /*\n         Simulate the end taking effect immediately, since\n         the example app is not backed by a real network service\n         */\n        if let publisher = publisher {\n            var error: OTError?\n            session?.unpublish(publisher, error: &error)\n            if error != nil {\n                print(error!)\n            }\n        }\n        publisher = nil\n        \n        if let session = session {\n            var error: OTError?\n            session.disconnect(&error)\n            if error != nil {\n                print(error!)\n            }\n        }\n        session = nil\n        \n        hasEnded = true\n    }\n}\n\nextension SpeakerboxCall: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(#function)\n        \n        hasConnected = true\n        canStartCall?(true)\n        canAnswerCall?(true)\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func sessionDidBeginReconnecting(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func sessionDidReconnect(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(#function, error)\n        \n        hasConnected = false\n        canStartCall?(false)\n        canAnswerCall?(false)\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(#function)\n        subscriber = OTSubscriber.init(stream: stream, delegate: self)\n        subscriber?.subscribeToVideo = false\n        if let subscriber = subscriber {\n            var error: OTError?\n            session.subscribe(subscriber, error: &error)\n            if error != nil {\n                print(error!)\n            }\n        }\n    }\n    \n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(#function)\n    }\n}\n\nextension SpeakerboxCall: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(#function)\n    }\n}\n\nextension SpeakerboxCall: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {\n        print(#function)\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(#function)\n    }\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo/SpeakerboxCallManager.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tManager of SpeakerboxCalls, which demonstrates using a CallKit CXCallController to request actions on calls\n*/\n\nimport UIKit\nimport CallKit\nimport OpenTok\n\nfinal class SpeakerboxCallManager: NSObject {\n    \n    enum Call: String {\n        case start = \"startCall\"\n        case end = \"endCall\"\n        case hold = \"holdCall\"\n    }\n\n    let callController = CXCallController()\n\n    // MARK: Actions\n\n    func startCall(handle: String, video: Bool = false) {        \n        let handle = CXHandle(type: .phoneNumber, value: handle)\n        let startCallAction = CXStartCallAction(call: UUID(), handle: handle)\n\n        startCallAction.isVideo = video\n\n        let transaction = CXTransaction()\n        transaction.addAction(startCallAction)\n\n        requestTransaction(transaction, action: Call.start.rawValue)\n    }\n\n    func end(call: SpeakerboxCall) {\n        let endCallAction = CXEndCallAction(call: call.uuid)\n        let transaction = CXTransaction()\n        transaction.addAction(endCallAction)\n\n        requestTransaction(transaction, action: Call.end.rawValue)\n    }\n\n    func setHeld(call: SpeakerboxCall, onHold: Bool) {\n        let setHeldCallAction = CXSetHeldCallAction(call: call.uuid, onHold: onHold)\n        let transaction = CXTransaction()\n        transaction.addAction(setHeldCallAction)\n\n        requestTransaction(transaction, action: Call.hold.rawValue)\n    }\n\n    private func requestTransaction(_ transaction: CXTransaction, action: String = \"\") {\n        callController.request(transaction) { error in\n            if let error = error {\n                print(\"Error requesting transaction: \\(error)\")\n            } else {\n                print(\"Requested transaction \\(action) successfully\")\n            }\n        }\n    }\n\n    // MARK: Call Management\n\n    static let CallsChangedNotification = Notification.Name(\"CallManagerCallsChangedNotification\") \n\n    private(set) var calls = [SpeakerboxCall]()\n\n    func callWithUUID(uuid: UUID) -> SpeakerboxCall? {\n        guard let index = calls.index(where: { $0.uuid == uuid }) else {\n            return nil\n        }\n        return calls[index]\n    }\n\n    func addCall(_ call: SpeakerboxCall) {\n        calls.append(call)\n\n        call.stateDidChange = { [weak self] in\n            self?.postCallsChangedNotification()\n        }\n\n        postCallsChangedNotification(userInfo: [\"action\": Call.start.rawValue])\n    }\n\n    func removeCall(_ call: SpeakerboxCall) {\n        calls = calls.filter {$0 === call}\n        postCallsChangedNotification(userInfo: [\"action\": Call.end.rawValue])\n    }\n\n    func removeAllCalls() {\n        calls.removeAll()\n        postCallsChangedNotification(userInfo: [\"action\": Call.end.rawValue])\n    }\n\n    private func postCallsChangedNotification(userInfo: [String: Any]? = nil) {\n        NotificationCenter.default.post(name: type(of: self).CallsChangedNotification, object: self, userInfo: userInfo)\n    }\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  CallKitDemo\n//\n//  Created by Xi Huang on 6/5/17.\n//  Copyright © 2017 Tokbox, Inc. All rights reserved.\n//\n\nimport UIKit\n\nclass ViewController: UIViewController {\n    \n    fileprivate final let displayCaller = \"Lucas Huang\"\n    fileprivate final let makeACallText = \"Make a call\"\n    fileprivate final let unholdCallText = \"Unhold Call\"\n    fileprivate final let simulateIncomingCallText = \"Simulate Call\"\n    fileprivate final let simulateIncomingCallThreeSecondsText = \"Simulate Call after 3s(Background)\"\n    fileprivate final let endCallText = \"End call\"\n\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        \n        NotificationCenter.default.addObserver(self, selector: #selector(handleCallsChangedNotification(notification:)), name: SpeakerboxCallManager.CallsChangedNotification, object: nil)\n    }\n    \n    override func viewDidDisappear(_ animated: Bool) {\n        super.viewDidDisappear(animated)\n        \n        NotificationCenter.default.removeObserver(self)\n    }\n    \n    @IBOutlet weak var callButton: UIButton!\n    @IBOutlet weak var simulateCallButton: UIButton!\n    @IBOutlet weak var simulateCallButton2: UIButton!\n    \n    @IBAction func receiveCallLucas(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if simulateCallButton.titleLabel?.text == simulateIncomingCallText {\n            appdelegate.displayIncomingCall(uuid: UUID(), handle: displayCaller)\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            callButton.isEnabled = false\n            simulateCallButton2.isEnabled = false\n        }\n        else {\n            endCall()\n            sender.setTitle(simulateIncomingCallText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            callButton.isEnabled = true\n            simulateCallButton2.isEnabled = true\n        }\n    }\n    \n    @IBAction func receiveCallLucasAfterThreeSeconds(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if sender.titleLabel?.text == simulateIncomingCallThreeSecondsText {\n            \n            let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)\n            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {\n                appdelegate.displayIncomingCall(uuid: UUID(), handle: \"Lucas Huang\", hasVideo: false) { _ in\n                    UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)\n                }\n            }\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            callButton.isEnabled = false\n            simulateCallButton.isEnabled = false\n        }\n        else {\n            endCall()\n            sender.setTitle(simulateIncomingCallThreeSecondsText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            callButton.isEnabled = true\n            simulateCallButton.isEnabled = true\n        }\n    }\n    \n    @IBAction func callButtonPressed(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if sender.titleLabel?.text == makeACallText {\n            appdelegate.callManager.startCall(handle: displayCaller)\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            simulateCallButton.isEnabled = false\n            simulateCallButton2.isEnabled = false\n        } else if sender.titleLabel?.text == unholdCallText { // This state set when user receives another call\n            appdelegate.callManager.setHeld(call: appdelegate.callManager.calls[0], onHold: false)\n        }\n        else {\n            endCall()\n            sender.setTitle(makeACallText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            simulateCallButton.isEnabled = true\n            simulateCallButton2.isEnabled = true\n        }\n    }\n    \n    @objc func handleCallsChangedNotification(notification: NSNotification) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n\n        if (appdelegate.callManager.calls.count > 0)\n        {\n            let call = appdelegate.callManager.calls[0]\n            if call.isOnHold {\n                callButton.setTitle(unholdCallText, for: .normal)\n            } else if call.session != nil {\n                callButton.setTitle(endCallText, for: .normal)\n                callButton.setTitleColor(.red, for: .normal)\n            }\n            \n            if let action = notification.userInfo?[\"action\"] as? String, action == SpeakerboxCallManager.Call.end.rawValue {\n                callButton.setTitle(makeACallText, for: .normal)\n                callButton.setTitleColor(.white, for: .normal)\n                callButton.isEnabled = true\n                simulateCallButton.setTitle(simulateIncomingCallText, for: .normal)\n                simulateCallButton.setTitleColor(.white, for: .normal)\n                simulateCallButton.isEnabled = true\n                simulateCallButton2.setTitle(simulateIncomingCallThreeSecondsText, for: .normal)\n                simulateCallButton2.setTitleColor(.white, for: .normal)\n                simulateCallButton2.isEnabled = true\n            }\n        }\n    }\n    \n    fileprivate func endCall() {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        /*\n         End any ongoing calls if the provider resets, and remove them from the app's list of calls,\n         since they are no longer valid.\n         */\n        for call in appdelegate.callManager.calls {\n            appdelegate.callManager.end(call: call)\n        }\n    }\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA00A84251F3A772400B2862E /* OTDefaultAudioDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = A00A84221F3A772400B2862E /* OTDefaultAudioDevice.m */; };\n\t\tA04D825E1EEB1E3E00EBA4CA /* SpeakerboxCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */; };\n\t\tA04D825F1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */; };\n\t\tA04D82611EEB1EB000EBA4CA /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */; };\n\t\tA062C6241EE5FAA200FD64A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A062C6231EE5FAA200FD64A3 /* AppDelegate.swift */; };\n\t\tA062C6261EE5FAA200FD64A3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A062C6251EE5FAA200FD64A3 /* ViewController.swift */; };\n\t\tA062C6291EE5FAA200FD64A3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A062C6271EE5FAA200FD64A3 /* Main.storyboard */; };\n\t\tA062C62B1EE5FAA200FD64A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A062C62A1EE5FAA200FD64A3 /* Assets.xcassets */; };\n\t\tA062C62E1EE5FAA200FD64A3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */; };\n\t\tA0B080C81EF9BD4D0082691D /* Ringtone.caf in Resources */ = {isa = PBXBuildFile; fileRef = A0B080C71EF9BD4A0082691D /* Ringtone.caf */; };\n\t\tA0F2087A1EEF442E00104C6C /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = A0F208791EEF442E00104C6C /* Podfile */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA00A84201F3A772400B2862E /* CallKitDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"CallKitDemo-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tA00A84211F3A772400B2862E /* OTDefaultAudioDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTDefaultAudioDevice.h; sourceTree = \"<group>\"; };\n\t\tA00A84221F3A772400B2862E /* OTDefaultAudioDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTDefaultAudioDevice.m; sourceTree = \"<group>\"; };\n\t\tA04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeakerboxCall.swift; sourceTree = \"<group>\"; };\n\t\tA04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeakerboxCallManager.swift; sourceTree = \"<group>\"; };\n\t\tA04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA062C6201EE5FAA200FD64A3 /* CallKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CallKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tA062C6231EE5FAA200FD64A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA062C6251EE5FAA200FD64A3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tA062C6281EE5FAA200FD64A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA062C62A1EE5FAA200FD64A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA062C62D1EE5FAA200FD64A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA062C62F1EE5FAA200FD64A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA0B080C71EF9BD4A0082691D /* Ringtone.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Ringtone.caf; sourceTree = \"<group>\"; };\n\t\tA0F208791EEF442E00104C6C /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };\n\t\tA0F2087B1EEF449800104C6C /* CallKitDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CallKitDemo.entitlements; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tA062C61D1EE5FAA200FD64A3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA062C6171EE5FAA200FD64A3 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA0F208791EEF442E00104C6C /* Podfile */,\n\t\t\t\tA062C6221EE5FAA200FD64A3 /* CallKitDemo */,\n\t\t\t\tA062C6211EE5FAA200FD64A3 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C6211EE5FAA200FD64A3 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C6201EE5FAA200FD64A3 /* CallKitDemo.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C6221EE5FAA200FD64A3 /* CallKitDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA00A84211F3A772400B2862E /* OTDefaultAudioDevice.h */,\n\t\t\t\tA00A84221F3A772400B2862E /* OTDefaultAudioDevice.m */,\n\t\t\t\tA0B080C71EF9BD4A0082691D /* Ringtone.caf */,\n\t\t\t\tA0F2087B1EEF449800104C6C /* CallKitDemo.entitlements */,\n\t\t\t\tA062C6231EE5FAA200FD64A3 /* AppDelegate.swift */,\n\t\t\t\tA04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */,\n\t\t\t\tA062C6251EE5FAA200FD64A3 /* ViewController.swift */,\n\t\t\t\tA04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */,\n\t\t\t\tA04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */,\n\t\t\t\tA062C6271EE5FAA200FD64A3 /* Main.storyboard */,\n\t\t\t\tA062C62A1EE5FAA200FD64A3 /* Assets.xcassets */,\n\t\t\t\tA062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */,\n\t\t\t\tA062C62F1EE5FAA200FD64A3 /* Info.plist */,\n\t\t\t\tA00A84201F3A772400B2862E /* CallKitDemo-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = CallKitDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tA062C61F1EE5FAA200FD64A3 /* CallKitDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = A062C6321EE5FAA200FD64A3 /* Build configuration list for PBXNativeTarget \"CallKitDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tA062C61C1EE5FAA200FD64A3 /* Sources */,\n\t\t\t\tA062C61D1EE5FAA200FD64A3 /* Frameworks */,\n\t\t\t\tA062C61E1EE5FAA200FD64A3 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CallKitDemo;\n\t\t\tproductName = CallKitDemo;\n\t\t\tproductReference = A062C6201EE5FAA200FD64A3 /* CallKitDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tA062C6181EE5FAA200FD64A3 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0830;\n\t\t\t\tLastUpgradeCheck = 0900;\n\t\t\t\tORGANIZATIONNAME = \"Tokbox, Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tA062C61F1EE5FAA200FD64A3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3.2;\n\t\t\t\t\t\tLastSwiftMigration = 0830;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.BackgroundModes = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.Push = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = A062C61B1EE5FAA200FD64A3 /* Build configuration list for PBXProject \"CallKitDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = A062C6171EE5FAA200FD64A3;\n\t\t\tproductRefGroup = A062C6211EE5FAA200FD64A3 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tA062C61F1EE5FAA200FD64A3 /* CallKitDemo */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tA062C61E1EE5FAA200FD64A3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA0B080C81EF9BD4D0082691D /* Ringtone.caf in Resources */,\n\t\t\t\tA062C62E1EE5FAA200FD64A3 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tA062C62B1EE5FAA200FD64A3 /* Assets.xcassets in Resources */,\n\t\t\t\tA0F2087A1EEF442E00104C6C /* Podfile in Resources */,\n\t\t\t\tA062C6291EE5FAA200FD64A3 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tA062C61C1EE5FAA200FD64A3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA062C6261EE5FAA200FD64A3 /* ViewController.swift in Sources */,\n\t\t\t\tA04D825F1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift in Sources */,\n\t\t\t\tA062C6241EE5FAA200FD64A3 /* AppDelegate.swift in Sources */,\n\t\t\t\tA00A84251F3A772400B2862E /* OTDefaultAudioDevice.m in Sources */,\n\t\t\t\tA04D825E1EEB1E3E00EBA4CA /* SpeakerboxCall.swift in Sources */,\n\t\t\t\tA04D82611EEB1EB000EBA4CA /* ProviderDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA062C6271EE5FAA200FD64A3 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C6281EE5FAA200FD64A3 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C62D1EE5FAA200FD64A3 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tA062C6301EE5FAA200FD64A3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA062C6311EE5FAA200FD64A3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tA062C6331EE5FAA200FD64A3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = CallKitDemo/CallKitDemo.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = CallKitDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.CallKitDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"CallKitDemo/CallKitDemo-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA062C6341EE5FAA200FD64A3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = CallKitDemo/CallKitDemo.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = CallKitDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.CallKitDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"CallKitDemo/CallKitDemo-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tA062C61B1EE5FAA200FD64A3 /* Build configuration list for PBXProject \"CallKitDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA062C6301EE5FAA200FD64A3 /* Debug */,\n\t\t\t\tA062C6311EE5FAA200FD64A3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tA062C6321EE5FAA200FD64A3 /* Build configuration list for PBXNativeTarget \"CallKitDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA062C6331EE5FAA200FD64A3 /* Debug */,\n\t\t\t\tA062C6341EE5FAA200FD64A3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = A062C6181EE5FAA200FD64A3 /* Project object */;\n}\n"
  },
  {
    "path": "CallKit/CallKitDemo.xcodeproj/xcshareddata/xcschemes/CallKitDemo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0900\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n               BuildableName = \"CallKitDemo.app\"\n               BlueprintName = \"CallKitDemo\"\n               ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "CallKit/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 OpenTok\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "CallKit/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'CallKitDemo' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "CallKit/README.md",
    "content": "![logo](./tokbox-logo.png)\n\n\n\n## CallKit Integration with OpenTok\nA sample app to demonstrate how to integrate the [CallKit](https://developer.apple.com/documentation/callkit) into OpenTok iOS SDK. This sample app is built based on the [SpeakerBox](https://developer.apple.com/library/content/samplecode/Speakerbox/Introduction/Intro.html) app from [WWDC 2016 CallKit Session](https://developer.apple.com/videos/play/wwdc2016/230/)\n\n### Install the project files\n\nUse CocoaPods to install the project files and dependencies.\n\n1. Install CocoaPods as described in [CocoaPods Getting Started](https://guides.cocoapods.org/using/getting-started.html#getting-started).\n1. In Terminal, `cd` to your project directory and type `pod install`. (Sometimes, `pod update` is magical)\n1. Reopen your project in Xcode using the new `*.xcworkspace` file.\n\n### Configure and build the app\n\nConfigure the sample app code. Then, build and run the app.\n\n1. The application **requires** values for **API Key**, **Session ID**, and **Token**. In the sample, you can get these values at the [OpenTok Developer Dashboard](https://dashboard.tokbox.com/). For production deployment, you must generate the **Session ID** and **Token** values using one of the [OpenTok Server SDKs](https://tokbox.com/developer/sdks/server/).\n\n1. Replace the following empty strings with the corresponding **API Key**, **Session ID**, and **Token** values in `AppDelegate.swift`:\n    ```swift\n      let apiKey = \"\"\n      let sessionId = \"\"\n      let token = \"\"\n    ```\n\n1. Use Xcode to build and run the app on an iOS simulator or device.\n\n### Exploring the sample app\n\n![demo](./demo.png)\n\n  1. **Make a call**: \n\nThe iOS system boosts the call priority of the app. Then, the app starts publishing to OpenTok platform. You won't notice any differences until you go to the home screen. Two ways to verify:\n  - A badge in home screen indicating an ongoing VoIP call.\n  - An incoming native phone call will not interrupt the current VoIP call, instead it shows the option menu.\n  \n  ***You will need a device to test the followings***\n\n  2. **Simulate an incoming call**\n\nThe native incoming call screen appears. Upon acceptance, the iOS system opens the app and boosts the call priority. Then, the app starts publishing to OpenTok platform.\n\n![unlock1](./unlock1.png) ---> ![unlock2](./unlock2.png)\n\n  3. **Simulate an incoming call after 3s(Background)** (After clicking the button, please lock your cell phone to test this scenario.)\n\nThe system wakes up your cell phone by making a native calling screen appear. Upon acceptance (a slider is shown instead of two buttons for the locked screen), the phone stays locked and boosts the call priority. Then, the app (which runs in the background during that time) starts publishing to OpenTok platform. \n\n![lock1](./lock1.png) ---> ![lock2](./lock2.png)\n\n  4. **Without simulation, use a push server or [NWPusher](https://github.com/noodlewerk/NWPusher) to call**\n\nThis requires a few more steps to test:\n\n    - create your certificate\n    - configure your push notification backend or NWPusher\n    - locate your device token for testing (launch the app and get it from the console)\n    - send a remote notification from your backend or NWPusher\n\n\n**Notice**: You might want to use [OpenTok.js Sample App](https://github.com/opentok/opentok-web-samples/tree/master/Basic%20Video%20Chat) to test the sample app together.\n\n### Exploring the codes\n\nA `CXProvider` object is responsible for reporting out-of-band notifications that occur to the system. To create one, you first need to initialize a `CXProviderConfiguration` object, which encapsulates the behaviors and capabilities of calls, to pass on to the `CXProvider` initializer. In order to receive telephony events of the provider, the provider needs to specify an object conforming to the `CXProviderDelegate` protocol.\n\n```swift\n// create a provider configuration\nlet localizedName = NSLocalizedString(\"CallKitDemo\", comment: \"Name of application\")\nlet providerConfiguration = CXProviderConfiguration(localizedName: localizedName)\nproviderConfiguration.supportsVideo = false\nproviderConfiguration.maximumCallsPerCallGroup = 1\nproviderConfiguration.supportedHandleTypes = [.phoneNumber]\nproviderConfiguration.iconTemplateImageData = UIImagePNGRepresentation(#imageLiteral(resourceName: \"IconMask\"))\nproviderConfiguration.ringtoneSound = \"Ringtone.caf\"\n\n// set up a provider\nprovider = CXProvider(configuration: providerConfiguration)\nprovider.setDelegate(self, queue: nil)\n```\n\nThe `CXProviderDelegate` protocol defines events of the telephony provider (`CXProvider`) such as the call starting, the call being put on hold, or the provider’s audio session is activated.\n\n```swift\n// MARK: CXProviderDelegate\nfunc providerDidReset(_ provider: CXProvider) {\n    print(\"Provider did reset\")\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXStartCallAction) {\n    print(\"Provider performs the start call action\")\n\n    /*\n      Configure the audio session, but do not start call audio here, since it must be done once\n      the audio session has been activated by the system after having its priority elevated.\n    */\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {\n    print(\"Provider performs the answer call action\")\n\n    /*\n      Configure the audio session, but do not start call audio here, since it must be done once\n      the audio session has been activated by the system after having its priority elevated.\n    */\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXEndCallAction) {\n    print(\"Provider performs the end call action\")\n\n    // Trigger the call to be ended via the underlying network service.\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {\n    print(\"Provider performs the hold call action\")\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {\n    print(\"Provider performs the mute call action\")\n}\n``` \n\nThe following methods indicate whether your VoIP call has been successfully priority boosted or recovered.\n\n```swift\nfunc provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {\n    print(\"Timed out \\(#function)\")\n    // React to the action timeout if necessary, such as showing an error UI.\n}\n\nfunc provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {\n    // Start call audio media, now that the audio session has been activated after having its priority boosted.\n}\n\nfunc provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {\n    /*\n        Restart any non-call related audio now that the app's audio session has been\n        de-activated after having its priority restored to normal.\n    */\n}\n```\n\nLet's explore how to make a call and answer a call on behalf of a user. To do that, we need a `CXCallController` object to interact with the system. \n\nThe `CXCallController` object takes a `CXTransaction` object to request a telephony action (which will later trigger delegate methods above if succeed). To specify a telephony action in a transaction, you need to create your desired action object and associate them with the transaction. Each telephony action has a corresponding `CXAction` class such as `CXEndCallAction` for ending a call, `CXSetHeldCallAction` for setting a call on hold. \n\nOnce you have it all ready, invoke the `request(_:completion:)` by passing a ready transaction object. Here's how you start a call:\n\n```swift\n// create a CXAction\nlet startCallAction = CXStartCallAction(call: UUID(), handle: CXHandle(type: .phoneNumber, value: handle))\n\n// create a transaction\nlet transaction = CXTransaction()\ntransaction.addAction(startCallAction)\n\n// create a label\nlet action = \"startCall\"\n\ncallController.request(transaction) { error in\n    if let error = error {\n        print(\"Error requesting transaction: \\(error)\")\n    } else {\n        print(\"Requested transaction \\(action) successfully\")\n    }\n}\n```\n\nAs for answering a call, the `CallKit` framework provides a convenient API to present a native calling UI like the screen-shot below. By invoking `reportNewIncomingCall(with:update:completion:)` on the provider, you will have the same experience as receiving a native phone call. Often, this piece of code works with VoIP remote notification to make calls to a device/person like WhatsApp, WeChat, and Messenger etc.\n\n```swift\n// Construct a CXCallUpdate describing the incoming call, including the caller.\nlet update = CXCallUpdate()\nupdate.remoteHandle = CXHandle(type: .phoneNumber, value: handle)\n\n// Report the incoming call to the system\nprovider.reportNewIncomingCall(with: uuid, update: update) { error in\n    /*\n      Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)\n      since calls may be \"denied\" for various legitimate reasons. See CXErrorCodeIncomingCallError.\n    */\n}\n```\n\n![call](./call.jpeg)\n\n\n### A glitch\n\nThere is a small [issue](https://forums.developer.apple.com/thread/64544) when accepting a call from a locked screen. The underlying audio session does not get activated propertly inside the CallKit framework. Apple's engineers propose a workaround by setting up the audio session as early as possible to make the case work out temporarily: \n\n```\nthen a workaround would be to configure your app's audio session (call `configureAudioSession()`) earlier in your app's lifecycle, before the `-provider:performAnswerCallAction:` method is invoked.\n```\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  CallKitDemo\n//\n//  Created by Xi Huang on 6/5/17.\n//  Copyright © 2017 Tokbox, Inc. All rights reserved.\n//\n\nimport UIKit\nimport PushKit\nimport CallKit\nimport OpenTok\n\nlet apiKey = \"\"\nlet sessionId = \"\"\nlet token = \"\"\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n    \n    let pushRegistry = PKPushRegistry(queue: DispatchQueue.main)\n    let callManager = SpeakerboxCallManager()\n    var providerDelegate: ProviderDelegate?\n\n    // Trigger VoIP registration on launch\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {\n        let sessionManager = OTAudioDeviceManager.currentAudioSessionManager()\n        sessionManager?.enableCallingServicesMode()\n        \n        providerDelegate = ProviderDelegate(callManager: callManager, sessionManager: sessionManager)\n        \n        pushRegistry.delegate = self\n        pushRegistry.desiredPushTypes = [.voIP]\n        \n        return true\n    }\n}\n\nextension AppDelegate: PKPushRegistryDelegate {\n    \n    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {\n        print(\"\\(#function) voip token: \\(credentials.token)\")\n        \n        let deviceToken = credentials.token.reduce(\"\", {$0 + String(format: \"%02X\", $1) })\n        print(\"\\(#function) token is: \\(deviceToken)\")\n    }\n\n    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {\n        \n        print(\"\\(#function) incoming voip notfication: \\(payload.dictionaryPayload)\")\n        if let uuidString = payload.dictionaryPayload[\"UUID\"] as? String,\n            let handle = payload.dictionaryPayload[\"handle\"] as? String,\n            let uuid = UUID(uuidString: uuidString) {\n                            \n            // display incoming call UI when receiving incoming voip notification\n            let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)\n            self.displayIncomingCall(uuid: uuid, handle: handle, hasVideo: false) { _ in\n                UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)\n            }\n        }\n    }\n    \n    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {\n        print(\"\\(#function) token invalidated\")\n    }\n        \n    /// Display the incoming call to the user\n    func displayIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {\n        providerDelegate?.reportIncomingCall(uuid: uuid, handle: handle, hasVideo: hasVideo, completion: completion)\n    }\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Assets.xcassets/IconMask.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-40.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-80.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"IconMask-120.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Assets.xcassets/baseHeroMount.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"baseHeroMount.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"baseHeroMount@2x.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\",\n      \"filename\" : \"baseHeroMount@3x.png\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"zeplin\",\n    \"version\" : \"1\"\n  }\n}"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16C67\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"CallKitDemo\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"baseHeroMount\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YYx-UX-emU\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"647\"/>\n                            </imageView>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M5B-6m-yHD\">\n                                <rect key=\"frame\" x=\"143\" y=\"318.5\" width=\"89\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Simulate Call\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"receiveCallLucas:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"8EM-RY-UL5\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g8T-fv-bWg\">\n                                <rect key=\"frame\" x=\"68\" y=\"356.5\" width=\"239\" height=\"30\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                <state key=\"normal\" title=\"Simulate Call after 3s(Background)\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"receiveCallLucasAfterThreeSeconds:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"cEH-h5-VOU\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9aI-yW-7Tw\">\n                                <rect key=\"frame\" x=\"149\" y=\"280.5\" width=\"77\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Make a call\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <state key=\"disabled\">\n                                    <color key=\"titleColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"callButtonPressed:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"eRQ-rc-Kp9\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"YYx-UX-emU\" secondAttribute=\"trailing\" id=\"3jK-fK-jae\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"centerY\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerY\" id=\"5Go-8s-H2G\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"top\" secondItem=\"9aI-yW-7Tw\" secondAttribute=\"bottom\" constant=\"8\" id=\"D14-vC-v4H\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"YYx-UX-emU\" secondAttribute=\"bottom\" id=\"Fga-mw-vE3\"/>\n                            <constraint firstItem=\"g8T-fv-bWg\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"J1U-YB-kys\"/>\n                            <constraint firstItem=\"g8T-fv-bWg\" firstAttribute=\"top\" secondItem=\"M5B-6m-yHD\" secondAttribute=\"bottom\" constant=\"8\" id=\"S8a-NF-fyJ\"/>\n                            <constraint firstItem=\"M5B-6m-yHD\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"TpI-O1-PZx\"/>\n                            <constraint firstItem=\"YYx-UX-emU\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" id=\"jn7-Kc-DzS\"/>\n                            <constraint firstItem=\"YYx-UX-emU\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"myS-Ve-QB6\"/>\n                            <constraint firstItem=\"9aI-yW-7Tw\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"rra-Ar-7og\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"callButton\" destination=\"9aI-yW-7Tw\" id=\"Kh9-cg-IdH\"/>\n                        <outlet property=\"simulateCallButton\" destination=\"M5B-6m-yHD\" id=\"U2Q-QK-ta3\"/>\n                        <outlet property=\"simulateCallButton2\" destination=\"g8T-fv-bWg\" id=\"ABY-0C-tDn\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"32.799999999999997\" y=\"93.103448275862078\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"baseHeroMount\" width=\"374\" height=\"667\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/CallKitDemo.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>aps-environment</key>\n\t<string>development</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleURLTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>CFBundleURLName</key>\n\t\t\t<string>$(PRODUCT_BUNDLE_IDENTIFIER).url-scheme.dial</string>\n\t\t\t<key>CFBundleURLSchemes</key>\n\t\t\t<array>\n\t\t\t\t<string>callkitdemo</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string>$(PRODUCT_NAME) uses camera</string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string>$(PRODUCT_NAME) uses microphone</string>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>audio</string>\n\t\t<string>fetch</string>\n\t\t<string>remote-notification</string>\n\t\t<string>voip</string>\n\t</array>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/ProviderDelegate.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tCallKit provider delegate class, which conforms to CXProviderDelegate protocol\n*/\n\nimport Foundation\nimport UIKit\nimport CallKit\nimport AVFoundation\nimport OpenTok\nimport Combine\n\nfinal class ProviderDelegate: NSObject, CXProviderDelegate {\n\n    let callManager: SpeakerboxCallManager\n    private let provider: CXProvider\n    private let sessionManager: OTAudioSessionManager?\n    let muteSubject = PassthroughSubject<Bool, Never>()\n    private var cancellable: AnyCancellable?\n\n    init(callManager: SpeakerboxCallManager, sessionManager: OTAudioSessionManager?) {\n        self.callManager = callManager\n        self.sessionManager = sessionManager\n        provider = CXProvider(configuration: type(of: self).providerConfiguration)\n\n        super.init()\n\n        provider.setDelegate(self, queue: nil)\n\n        setupMuteThrottle()\n    }\n    \n    /// The app's provider configuration, representing its CallKit capabilities\n    static var providerConfiguration: CXProviderConfiguration {\n        let localizedName = NSLocalizedString(\"CallKitDemo\", comment: \"Name of application\")\n        let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)\n\n        providerConfiguration.supportsVideo = false\n        \n        providerConfiguration.maximumCallsPerCallGroup = 1\n        \n        providerConfiguration.maximumCallGroups = 1\n        \n        providerConfiguration.supportedHandleTypes = [.phoneNumber]\n\n        providerConfiguration.iconTemplateImageData = #imageLiteral(resourceName: \"IconMask\").pngData()\n\n        providerConfiguration.ringtoneSound = \"Ringtone.caf\"\n        \n        return providerConfiguration\n    }\n\n    // MARK: Incoming Calls\n\n    /// Use CXProvider to report the incoming call to the system\n    func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {\n        // Construct a CXCallUpdate describing the incoming call, including the caller.\n        let update = CXCallUpdate()\n        update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)\n        update.hasVideo = hasVideo\n        update.supportsHolding = true\n        \n        // pre-heat the AVAudioSession\n        // Report the incoming call to the system\n        provider.reportNewIncomingCall(with: uuid, update: update) { error in\n            /*\n                Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)\n                since calls may be \"denied\" for various legitimate reasons. See CXErrorCodeIncomingCallError.\n             */\n            if error == nil {\n                let call = SpeakerboxCall(uuid: uuid)\n                call.handle = handle\n\n                self.callManager.addCall(call)\n            }\n            \n            completion?(error as NSError?)\n        }\n    }\n\n    // MARK: CXProviderDelegate\n\n    func providerDidBegin(_ provider: CXProvider) {\n        print(\"Provider did begin\")\n    }\n    \n    func providerDidReset(_ provider: CXProvider) {\n        print(\"Provider did reset\")\n        /*\n            End any ongoing calls if the provider resets, and remove them from the app's list of calls,\n            since they are no longer valid.\n         */\n    }\n\n    var outgoingCall: SpeakerboxCall?\n    func provider(_ provider: CXProvider, perform action: CXStartCallAction) {\n        print(\"Received perform CXStartCallAction \\(action.callUUID)\")\n        // Create & configure an instance of SpeakerboxCall, the app's model class representing the new outgoing call.\n        let call = SpeakerboxCall(uuid: action.callUUID, isOutgoing: true)\n        call.handle = action.handle.value\n\n        /*\n            Configure the audio session, but do not start call audio here, since it must be done once\n            the audio session has been activated by the system after having its priority elevated.\n         */\n        // https://forums.developer.apple.com/thread/64544\n        // we can't configure the audio session here for the case of launching it from locked screen\n        // instead, we have to pre-heat the AVAudioSession by configuring as early as possible, didActivate do not get called otherwise\n        // please look for  * pre-heat the AVAudioSession *\n        sessionManager?.preconfigureAudioSessionForCall(withMode: .voiceChat)\n        \n        /*\n            Set callback blocks for significant events in the call's lifecycle, so that the CXProvider may be updated\n            to reflect the updated state.\n         */\n        call.hasStartedConnectingDidChange = { [weak self] in\n            self?.setupHold(to: call.uuid)\n            self?.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)\n        }\n        call.hasConnectedDidChange = { [weak self] in\n            self?.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectDate)\n        }\n        call.callDidEnd = { [weak self] reason in\n            self?.provider.reportCall(with: call.uuid, endedAt: nil, reason: reason)\n        }\n        self.outgoingCall = call\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n\n    var answerCall: SpeakerboxCall?\n    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {\n        print(\"Received perform CXAnswerCallAction\")\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        /*\n            Configure the audio session, but do not start call audio here, since it must be done once\n            the audio session has been activated by the system after having its priority elevated.\n         */\n        \n        // https://forums.developer.apple.com/thread/64544\n        // we can't configure the audio session here for the case of launching it from locked screen\n        // instead, we have to pre-heat the AVAudioSession by configuring as early as possible, didActivate do not get called otherwise\n        // please look for  * pre-heat the AVAudioSession *\n        sessionManager?.preconfigureAudioSessionForCall(withMode: .voiceChat)\n        \n        self.answerCall = call\n        \n        call.callDidEnd = { [weak self] reason in\n            self?.provider.reportCall(with: call.uuid, endedAt: Date(), reason: reason)\n        }\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n\n    \n    func provider(_ provider: CXProvider, perform action: CXEndCallAction) {\n        print(\"Received perform CXEndCallAction\")\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        // Trigger the call to be ended via the underlying network service.\n        call.endCall()\n\n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n\n        call.stateDidChange = nil\n        call.hasStartedConnectingDidChange = nil\n        call.hasConnectedDidChange = nil\n        call.hasEndedDidChange = nil\n        call.audioChange = nil\n        call.callDidEnd = nil\n        \n        // Remove the ended call from the app's list of calls.\n        callManager.removeCall(call)\n    }\n\n    func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {\n        print(\"Received perform CXSetHeldCallAction \\(action.isOnHold)\")\n        // Retrieve the SpeakerboxCall instance corresponding to the action's call UUID\n        guard let call = callManager.callWithUUID(uuid: action.callUUID) else {\n            action.fail()\n            return\n        }\n\n        // Update the SpeakerboxCall's underlying hold state.\n        call.isOnHold = action.isOnHold\n\n        // Stop or start audio in response to holding or unholding the call.\n        updateMuteState(call.isOnHold)\n        \n        // Signal to the system that the action has been successfully performed.\n        action.fulfill()\n    }\n    \n    func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {\n        print(\"Received perform CXSetMutedCallAction \\(action.isMuted)\")\n        \n        updateMuteState(action.isMuted)\n        \n        action.fulfill()\n    }\n\n    func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {\n        print(\"Timed out \\(#function)\")\n\n        // React to the action timeout if necessary, such as showing an error UI.\n    }\n\n    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {\n        print(\"Received didActivate\")\n        sessionManager?.audioSessionDidActivate(audioSession)\n        \n        // If we are returning from a hold state\n        if answerCall?.hasConnected ?? false {\n            return\n        }\n        if outgoingCall?.hasConnected ?? false {\n            return\n        }\n        \n        // Start call audio media, now that the audio session has been activated after having its priority boosted.\n        outgoingCall?.startCall(withAudioSession: audioSession) { [weak self] success in\n            guard let outgoingCall = self?.outgoingCall else { return }\n            if success {\n                self?.callManager.addCall(outgoingCall)\n                self?.outgoingCall?.startAudio()\n            } else {\n                self?.callManager.end(call: outgoingCall)\n            }\n        }\n        \n        answerCall?.answerCall(withAudioSession: audioSession) { success in\n            if success {\n                self.answerCall?.startAudio()\n            }\n        }\n    }\n\n    func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {\n        print(\"Received didDeactivate\")\n        sessionManager?.audioSessionDidDeactivate(audioSession)\n        \n        /*\n             Restart any non-call related audio now that the app's audio session has been\n             de-activated after having its priority restored to normal.\n         */\n        if outgoingCall?.isOnHold ?? false || answerCall?.isOnHold ?? false {\n            print(\"Call is on hold. Do not terminate any call\")\n            return\n        }\n        \n        outgoingCall?.endCall()\n        outgoingCall = nil\n        answerCall?.endCall()\n        answerCall = nil\n        callManager.removeAllCalls()\n    }\n    \n    // MARK: Helpers\n    \n    func setupHold(to callUUID: UUID) {\n        let update = CXCallUpdate()\n        update.supportsHolding = true\n        update.hasVideo = false\n        provider.reportCall(with: callUUID, updated: update)\n    }\n    \n    func setupMuteThrottle() {\n        cancellable = muteSubject\n            .throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)\n            .sink { [weak self] isMuted in\n                self?.applyMuteState(isMuted)\n            }\n    }\n    \n    func updateMuteState(_ isMuted: Bool) {\n        muteSubject.send(isMuted)\n    }\n    \n    private func applyMuteState(_ isMuted: Bool) {\n        print(\"applyMuteState \\(isMuted)\")\n        answerCall?.isMuted = isMuted\n        outgoingCall?.isMuted = isMuted\n    }\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/SpeakerboxCall.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tModel class representing a single call\n*/\n\nimport Foundation\nimport OpenTok\nimport CallKit\n\nfinal class SpeakerboxCall: NSObject {\n\n    // MARK: Metadata Properties\n\n    let uuid: UUID\n    let isOutgoing: Bool\n    var handle: String?\n\n    // MARK: Call State Properties\n\n    var connectingDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasStartedConnectingDidChange?()\n        }\n    }\n    var connectDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasConnectedDidChange?()\n        }\n    }\n    var endDate: Date? {\n        didSet {\n            stateDidChange?()\n            hasEndedDidChange?()\n        }\n    }\n    var isOnHold = false {\n        didSet {\n            stateDidChange?()\n        }\n    }\n    \n    var isMuted = false {\n        didSet {\n            publisher?.publishAudio = !isMuted\n        }\n    }\n\n    // MARK: State change callback blocks\n\n    var stateDidChange: (() -> Void)?\n    var hasStartedConnectingDidChange: (() -> Void)?\n    var hasConnectedDidChange: (() -> Void)?\n    var hasEndedDidChange: (() -> Void)?\n    var audioChange: (() -> Void)?\n    var callDidEnd: ((CXCallEndedReason) -> Void)?\n    \n    // MARK: Derived Properties\n\n    var hasStartedConnecting: Bool {\n        get {\n            return connectingDate != nil\n        }\n        set {\n            connectingDate = newValue ? Date() : nil\n        }\n    }\n    var hasConnected: Bool {\n        get {\n            return connectDate != nil\n        }\n        set {\n            connectDate = newValue ? Date() : nil\n        }\n    }\n    var hasEnded: Bool {\n        get {\n            return endDate != nil\n        }\n        set {\n            endDate = newValue ? Date() : nil\n        }\n    }\n    var duration: TimeInterval {\n        guard let connectDate = connectDate else {\n            return 0\n        }\n\n        return Date().timeIntervalSince(connectDate)\n    }\n\n    // MARK: Initialization\n\n    init(uuid: UUID, isOutgoing: Bool = false) {\n        self.uuid = uuid\n        self.isOutgoing = isOutgoing\n    }\n\n    // MARK: Actions\n    var session: OTSession?\n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n    \n    func assertSessionParams() {\n        assert(!apiKey.isEmpty, \"Empty API key, session will not be instantiated\")\n        assert(!sessionId.isEmpty, \"Empty Session ID, session will not be instantiated\")\n        assert(!token.isEmpty, \"Empty token, session will not connect\")\n    }\n    \n    var canStartCall: ((Bool) -> Void)?\n    func startCall(withAudioSession audioSession: AVAudioSession, completion: ((_ success: Bool) -> Void)?) {\n        if session == nil {\n            assertSessionParams()\n            session = OTSession(apiKey: apiKey, sessionId: sessionId, delegate: self)\n        }\n        canStartCall = completion\n        \n        var error: OTError?\n        hasStartedConnecting = true\n        session?.connect(withToken: token, error: &error)\n        if let error = error {\n            print(error)\n            callDidEnd?(.failed)\n        }\n    }\n    \n    var canAnswerCall: ((Bool) -> Void)?\n    func answerCall(withAudioSession audioSession: AVAudioSession, completion: ((_ success: Bool) -> Void)?) {\n        if session == nil {\n            assertSessionParams()\n            session = OTSession(apiKey: apiKey, sessionId: sessionId, delegate: self)\n        }\n        \n        canAnswerCall = completion\n        \n        var error: OTError?\n        hasStartedConnecting = true\n        session?.connect(withToken: token, error: &error)\n        if let error = error {\n            print(error)\n            callDidEnd?(.failed)\n        }\n    }\n    \n    func startAudio() {\n        if publisher == nil {\n            let settings = OTPublisherSettings()\n            settings.name = UIDevice.current.name\n            settings.audioTrack = true\n            settings.videoTrack = false\n            publisher = OTPublisher(delegate: self, settings: settings)\n        }\n        \n        var error: OTError?\n        session?.publish(publisher!, error: &error)\n        if let error = error {\n            print(error)\n            \n            if let session = session {\n                var error: OTError?\n                session.disconnect(&error)\n                if let error = error {\n                    print(error)\n                }\n            }\n            \n            callDidEnd?(.failed)\n        }\n    }\n    \n    func endCall() {\n        /*\n         Simulate the end taking effect immediately, since\n         the example app is not backed by a real network service\n         */\n        if let publisher = publisher {\n            var error: OTError?\n            session?.unpublish(publisher, error: &error)\n            if error != nil {\n                print(error!)\n            }\n        }\n        publisher = nil\n        \n        if let session = session {\n            var error: OTError?\n            session.disconnect(&error)\n            if let error = error {\n                print(error)\n            }\n        }\n        session = nil\n        \n        hasEnded = true\n    }\n}\n\nextension SpeakerboxCall: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(#function)\n        \n        hasConnected = true\n        canStartCall?(true)\n        canAnswerCall?(true)\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func sessionDidBeginReconnecting(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func sessionDidReconnect(_ session: OTSession) {\n        print(#function)\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(#function, error)\n        \n        hasConnected = false\n        canStartCall?(false)\n        canAnswerCall?(false)\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(#function)\n        subscriber = OTSubscriber.init(stream: stream, delegate: self)\n        subscriber?.subscribeToVideo = false\n        if let subscriber = subscriber {\n            var error: OTError?\n            session.subscribe(subscriber, error: &error)\n            if error != nil {\n                print(error!)\n            }\n        }\n    }\n    \n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(#function)\n    }\n}\n\nextension SpeakerboxCall: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(#function)\n        callDidEnd?(.failed)\n    }\n}\n\nextension SpeakerboxCall: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {\n        print(#function)\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(#function)\n        callDidEnd?(.failed)\n    }\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/SpeakerboxCallManager.swift",
    "content": "/*\n\tCopyright (C) 2016 Apple Inc. All Rights Reserved.\n\tSee LICENSE.txt for this sample’s licensing information\n\t\n\tAbstract:\n\tManager of SpeakerboxCalls, which demonstrates using a CallKit CXCallController to request actions on calls\n*/\n\nimport UIKit\nimport CallKit\nimport OpenTok\n\nfinal class SpeakerboxCallManager: NSObject {\n    \n    enum Call: String {\n        case start = \"startCall\"\n        case end = \"endCall\"\n        case hold = \"holdCall\"\n    }\n\n    let callController = CXCallController()\n\n    // MARK: Actions\n\n    func startCall(handle: String, video: Bool = false) {\n        print(\"SpeakerboxCallManager: startCall\")\n        let handle = CXHandle(type: .phoneNumber, value: handle)\n        let startCallAction = CXStartCallAction(call: UUID(), handle: handle)\n\n        startCallAction.isVideo = video\n\n        let transaction = CXTransaction()\n        transaction.addAction(startCallAction)\n\n        requestTransaction(transaction, action: Call.start.rawValue)\n    }\n\n    func end(call: SpeakerboxCall) {\n        print(\"SpeakerboxCallManager: end\")\n        let endCallAction = CXEndCallAction(call: call.uuid)\n        let transaction = CXTransaction()\n        transaction.addAction(endCallAction)\n\n        requestTransaction(transaction, action: Call.end.rawValue)\n    }\n\n    func setHeld(call: SpeakerboxCall, onHold: Bool) {\n        print(\"SpeakerboxCallManager: setHeld \\(onHold)\")\n        let setHeldCallAction = CXSetHeldCallAction(call: call.uuid, onHold: onHold)\n        let transaction = CXTransaction()\n        transaction.addAction(setHeldCallAction)\n\n        requestTransaction(transaction, action: Call.hold.rawValue)\n    }\n\n    private func requestTransaction(_ transaction: CXTransaction, action: String = \"\") {\n        callController.request(transaction) { error in\n            if let error = error {\n                print(\"Error requesting transaction: \\(error)\")\n            } else {\n                print(\"Requested transaction \\(action) successfully\")\n            }\n        }\n    }\n\n    // MARK: Call Management\n\n    static let CallsChangedNotification = Notification.Name(\"CallManagerCallsChangedNotification\") \n\n    private(set) var calls = [SpeakerboxCall]()\n\n    func callWithUUID(uuid: UUID) -> SpeakerboxCall? {\n        guard let index = calls.index(where: { $0.uuid == uuid }) else {\n            return nil\n        }\n        return calls[index]\n    }\n\n    func addCall(_ call: SpeakerboxCall) {\n        calls.append(call)\n\n        call.stateDidChange = { [weak self] in\n            self?.postCallsChangedNotification()\n        }\n\n        postCallsChangedNotification(userInfo: [\"action\": Call.start.rawValue])\n    }\n\n    func removeCall(_ call: SpeakerboxCall) {\n        calls = calls.filter {$0 === call}\n        postCallsChangedNotification(userInfo: [\"action\": Call.end.rawValue])\n    }\n\n    func removeAllCalls() {\n        calls.removeAll()\n        postCallsChangedNotification(userInfo: [\"action\": Call.end.rawValue])\n    }\n\n    private func postCallsChangedNotification(userInfo: [String: Any]? = nil) {\n        NotificationCenter.default.post(name: type(of: self).CallsChangedNotification, object: self, userInfo: userInfo)\n    }\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  CallKitDemo\n//\n//  Created by Xi Huang on 6/5/17.\n//  Copyright © 2017 Tokbox, Inc. All rights reserved.\n//\n\nimport UIKit\n\nclass ViewController: UIViewController {\n    \n    fileprivate final let displayCaller = \"Lucas Huang\"\n    fileprivate final let makeACallText = \"Make a call\"\n    fileprivate final let unholdCallText = \"Unhold Call\"\n    fileprivate final let simulateIncomingCallText = \"Simulate Call\"\n    fileprivate final let simulateIncomingCallThreeSecondsText = \"Simulate Call after 3s(Background)\"\n    fileprivate final let endCallText = \"End call\"\n\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        \n        NotificationCenter.default.addObserver(self, selector: #selector(handleCallsChangedNotification(notification:)), name: SpeakerboxCallManager.CallsChangedNotification, object: nil)\n    }\n    \n    override func viewDidDisappear(_ animated: Bool) {\n        super.viewDidDisappear(animated)\n        \n        NotificationCenter.default.removeObserver(self)\n    }\n    \n    @IBOutlet weak var callButton: UIButton!\n    @IBOutlet weak var simulateCallButton: UIButton!\n    @IBOutlet weak var simulateCallButton2: UIButton!\n    \n    @IBAction func receiveCallLucas(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if simulateCallButton.titleLabel?.text == simulateIncomingCallText {\n            appdelegate.displayIncomingCall(uuid: UUID(), handle: displayCaller)\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            callButton.isEnabled = false\n            simulateCallButton2.isEnabled = false\n        }\n        else {\n            endCall()\n            sender.setTitle(simulateIncomingCallText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            callButton.isEnabled = true\n            simulateCallButton2.isEnabled = true\n        }\n    }\n    \n    @IBAction func receiveCallLucasAfterThreeSeconds(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if sender.titleLabel?.text == simulateIncomingCallThreeSecondsText {\n            \n            let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)\n            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {\n                appdelegate.displayIncomingCall(uuid: UUID(), handle: \"Lucas Huang\", hasVideo: false) { _ in\n                    UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)\n                }\n            }\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            callButton.isEnabled = false\n            simulateCallButton.isEnabled = false\n        }\n        else {\n            endCall()\n            sender.setTitle(simulateIncomingCallThreeSecondsText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            callButton.isEnabled = true\n            simulateCallButton.isEnabled = true\n        }\n    }\n    \n    @IBAction func callButtonPressed(_ sender: UIButton) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        if sender.titleLabel?.text == makeACallText {\n            appdelegate.callManager.startCall(handle: displayCaller)\n            sender.setTitle(endCallText, for: .normal)\n            sender.setTitleColor(.red, for: .normal)\n            simulateCallButton.isEnabled = false\n            simulateCallButton2.isEnabled = false\n        } else if sender.titleLabel?.text == unholdCallText { // This state set when user receives another call\n            appdelegate.callManager.setHeld(call: appdelegate.callManager.calls[0], onHold: false)\n        }\n        else {\n            endCall()\n            sender.setTitle(makeACallText, for: .normal)\n            sender.setTitleColor(.white, for: .normal)\n            simulateCallButton.isEnabled = true\n            simulateCallButton2.isEnabled = true\n        }\n    }\n    \n    @objc func handleCallsChangedNotification(notification: NSNotification) {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n\n        if (appdelegate.callManager.calls.count > 0)\n        {\n            let call = appdelegate.callManager.calls[0]\n            if call.isOnHold {\n                callButton.setTitle(unholdCallText, for: .normal)\n            } else if call.session != nil {\n                callButton.setTitle(endCallText, for: .normal)\n                callButton.setTitleColor(.red, for: .normal)\n            }\n            \n            if let action = notification.userInfo?[\"action\"] as? String, action == SpeakerboxCallManager.Call.end.rawValue {\n                callButton.setTitle(makeACallText, for: .normal)\n                callButton.setTitleColor(.white, for: .normal)\n                callButton.isEnabled = true\n                simulateCallButton.setTitle(simulateIncomingCallText, for: .normal)\n                simulateCallButton.setTitleColor(.white, for: .normal)\n                simulateCallButton.isEnabled = true\n                simulateCallButton2.setTitle(simulateIncomingCallThreeSecondsText, for: .normal)\n                simulateCallButton2.setTitleColor(.white, for: .normal)\n                simulateCallButton2.isEnabled = true\n            }\n        }\n    }\n    \n    fileprivate func endCall() {\n        guard let appdelegate = UIApplication.shared.delegate as? AppDelegate else {\n            \n            print(\"appdelegate is missing\")\n            return\n        }\n        \n        /*\n         End any ongoing calls if the provider resets, and remove them from the app's list of calls,\n         since they are no longer valid.\n         */\n        for call in appdelegate.callManager.calls {\n            appdelegate.callManager.end(call: call)\n        }\n    }\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 60;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t373FD26FC719771DA1FE9296 /* Pods_CallKitDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBCC6CE434A3AA747DD39696 /* Pods_CallKitDemo.framework */; };\n\t\tA04D825E1EEB1E3E00EBA4CA /* SpeakerboxCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */; };\n\t\tA04D825F1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */; };\n\t\tA04D82611EEB1EB000EBA4CA /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */; };\n\t\tA062C6241EE5FAA200FD64A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A062C6231EE5FAA200FD64A3 /* AppDelegate.swift */; };\n\t\tA062C6261EE5FAA200FD64A3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A062C6251EE5FAA200FD64A3 /* ViewController.swift */; };\n\t\tA062C6291EE5FAA200FD64A3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A062C6271EE5FAA200FD64A3 /* Main.storyboard */; };\n\t\tA062C62B1EE5FAA200FD64A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A062C62A1EE5FAA200FD64A3 /* Assets.xcassets */; };\n\t\tA062C62E1EE5FAA200FD64A3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */; };\n\t\tA0B080C81EF9BD4D0082691D /* Ringtone.caf in Resources */ = {isa = PBXBuildFile; fileRef = A0B080C71EF9BD4A0082691D /* Ringtone.caf */; };\n\t\tA0F2087A1EEF442E00104C6C /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = A0F208791EEF442E00104C6C /* Podfile */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t6276A9694A42BCF2E7D4265A /* Pods-CallKitDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CallKitDemo.debug.xcconfig\"; path = \"Target Support Files/Pods-CallKitDemo/Pods-CallKitDemo.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t6FA799CB2DE9E21C00977B46 /* OpenTok.xcframework */ = {isa = PBXFileReference; expectedSignature = \"AppleDeveloperProgram:PR6C39UQ38:Vonage\"; lastKnownFileType = wrapper.xcframework; name = OpenTok.xcframework; path = Pods/OTXCFramework/OpenTok.xcframework; sourceTree = \"<group>\"; };\n\t\t6FA799E12DE9F8A200977B46 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };\n\t\t6FA799E32DE9F8C400977B46 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };\n\t\t6FA799E52DE9F8CE00977B46 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };\n\t\t6FA799E72DE9F8D600977B46 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };\n\t\t6FA799E92DE9F8DF00977B46 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; };\n\t\t6FA799EB2DE9F8E800977B46 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };\n\t\t6FA799ED2DE9F8F000977B46 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };\n\t\t6FA799EF2DE9F8F700977B46 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };\n\t\t6FA799F12DE9F8FD00977B46 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };\n\t\t6FA799F32DE9F90400977B46 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };\n\t\t6FA799F52DE9F90B00977B46 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };\n\t\t6FA799F72DE9F91400977B46 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };\n\t\t6FA799F92DE9F92C00977B46 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };\n\t\t78944A861D86C7478ADBE4CE /* Pods-CallKitDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CallKitDemo.release.xcconfig\"; path = \"Target Support Files/Pods-CallKitDemo/Pods-CallKitDemo.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tA04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeakerboxCall.swift; sourceTree = \"<group>\"; };\n\t\tA04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeakerboxCallManager.swift; sourceTree = \"<group>\"; };\n\t\tA04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA062C6201EE5FAA200FD64A3 /* CallKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CallKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tA062C6231EE5FAA200FD64A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA062C6251EE5FAA200FD64A3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tA062C6281EE5FAA200FD64A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA062C62A1EE5FAA200FD64A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA062C62D1EE5FAA200FD64A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA062C62F1EE5FAA200FD64A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA0B080C71EF9BD4A0082691D /* Ringtone.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Ringtone.caf; sourceTree = \"<group>\"; };\n\t\tA0F208791EEF442E00104C6C /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };\n\t\tA0F2087B1EEF449800104C6C /* CallKitDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CallKitDemo.entitlements; sourceTree = \"<group>\"; };\n\t\tFBCC6CE434A3AA747DD39696 /* Pods_CallKitDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CallKitDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tA062C61D1EE5FAA200FD64A3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t373FD26FC719771DA1FE9296 /* Pods_CallKitDemo.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t053AFDF26B19C87AB193D03C /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6276A9694A42BCF2E7D4265A /* Pods-CallKitDemo.debug.xcconfig */,\n\t\t\t\t78944A861D86C7478ADBE4CE /* Pods-CallKitDemo.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t6FA799CA2DE9E21C00977B46 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6FA799F92DE9F92C00977B46 /* Network.framework */,\n\t\t\t\t6FA799F72DE9F91400977B46 /* AVFoundation.framework */,\n\t\t\t\t6FA799F52DE9F90B00977B46 /* AudioToolbox.framework */,\n\t\t\t\t6FA799F32DE9F90400977B46 /* CoreFoundation.framework */,\n\t\t\t\t6FA799F12DE9F8FD00977B46 /* CoreGraphics.framework */,\n\t\t\t\t6FA799EF2DE9F8F700977B46 /* CoreMedia.framework */,\n\t\t\t\t6FA799ED2DE9F8F000977B46 /* CoreTelephony.framework */,\n\t\t\t\t6FA799EB2DE9F8E800977B46 /* CoreVideo.framework */,\n\t\t\t\t6FA799E92DE9F8DF00977B46 /* GLKit.framework */,\n\t\t\t\t6FA799E72DE9F8D600977B46 /* OpenGLES.framework */,\n\t\t\t\t6FA799E52DE9F8CE00977B46 /* QuartzCore.framework */,\n\t\t\t\t6FA799E32DE9F8C400977B46 /* SystemConfiguration.framework */,\n\t\t\t\t6FA799E12DE9F8A200977B46 /* VideoToolbox.framework */,\n\t\t\t\t6FA799CB2DE9E21C00977B46 /* OpenTok.xcframework */,\n\t\t\t\tFBCC6CE434A3AA747DD39696 /* Pods_CallKitDemo.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C6171EE5FAA200FD64A3 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA0F208791EEF442E00104C6C /* Podfile */,\n\t\t\t\tA062C6221EE5FAA200FD64A3 /* CallKitDemo */,\n\t\t\t\t6FA799CA2DE9E21C00977B46 /* Frameworks */,\n\t\t\t\tA062C6211EE5FAA200FD64A3 /* Products */,\n\t\t\t\t053AFDF26B19C87AB193D03C /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C6211EE5FAA200FD64A3 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C6201EE5FAA200FD64A3 /* CallKitDemo.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C6221EE5FAA200FD64A3 /* CallKitDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA0B080C71EF9BD4A0082691D /* Ringtone.caf */,\n\t\t\t\tA0F2087B1EEF449800104C6C /* CallKitDemo.entitlements */,\n\t\t\t\tA062C6231EE5FAA200FD64A3 /* AppDelegate.swift */,\n\t\t\t\tA04D82601EEB1EB000EBA4CA /* ProviderDelegate.swift */,\n\t\t\t\tA062C6251EE5FAA200FD64A3 /* ViewController.swift */,\n\t\t\t\tA04D825C1EEB1E3E00EBA4CA /* SpeakerboxCall.swift */,\n\t\t\t\tA04D825D1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift */,\n\t\t\t\tA062C6271EE5FAA200FD64A3 /* Main.storyboard */,\n\t\t\t\tA062C62A1EE5FAA200FD64A3 /* Assets.xcassets */,\n\t\t\t\tA062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */,\n\t\t\t\tA062C62F1EE5FAA200FD64A3 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = CallKitDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tA062C61F1EE5FAA200FD64A3 /* CallKitDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = A062C6321EE5FAA200FD64A3 /* Build configuration list for PBXNativeTarget \"CallKitDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t008B415415CD40B490AEF13B /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tA062C61C1EE5FAA200FD64A3 /* Sources */,\n\t\t\t\tA062C61D1EE5FAA200FD64A3 /* Frameworks */,\n\t\t\t\tA062C61E1EE5FAA200FD64A3 /* Resources */,\n\t\t\t\t6E75212811E76BF4FAF2A9DB /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CallKitDemo;\n\t\t\tproductName = CallKitDemo;\n\t\t\tproductReference = A062C6201EE5FAA200FD64A3 /* CallKitDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tA062C6181EE5FAA200FD64A3 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0830;\n\t\t\t\tLastUpgradeCheck = 0900;\n\t\t\t\tORGANIZATIONNAME = \"Tokbox, Inc.\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tA062C61F1EE5FAA200FD64A3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3.2;\n\t\t\t\t\t\tLastSwiftMigration = 0830;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.BackgroundModes = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.Push = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = A062C61B1EE5FAA200FD64A3 /* Build configuration list for PBXProject \"CallKitDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = A062C6171EE5FAA200FD64A3;\n\t\t\tproductRefGroup = A062C6211EE5FAA200FD64A3 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tA062C61F1EE5FAA200FD64A3 /* CallKitDemo */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tA062C61E1EE5FAA200FD64A3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA0B080C81EF9BD4D0082691D /* Ringtone.caf in Resources */,\n\t\t\t\tA062C62E1EE5FAA200FD64A3 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tA062C62B1EE5FAA200FD64A3 /* Assets.xcassets in Resources */,\n\t\t\t\tA0F2087A1EEF442E00104C6C /* Podfile in Resources */,\n\t\t\t\tA062C6291EE5FAA200FD64A3 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t008B415415CD40B490AEF13B /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-CallKitDemo-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t6E75212811E76BF4FAF2A9DB /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CallKitDemo/Pods-CallKitDemo-resources.sh\",\n\t\t\t\t\"${PODS_CONFIGURATION_BUILD_DIR}/OTXCFramework/OTPrivacyResources.bundle\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/OTPrivacyResources.bundle\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-CallKitDemo/Pods-CallKitDemo-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tA062C61C1EE5FAA200FD64A3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA062C6261EE5FAA200FD64A3 /* ViewController.swift in Sources */,\n\t\t\t\tA04D825F1EEB1E3E00EBA4CA /* SpeakerboxCallManager.swift in Sources */,\n\t\t\t\tA062C6241EE5FAA200FD64A3 /* AppDelegate.swift in Sources */,\n\t\t\t\tA04D825E1EEB1E3E00EBA4CA /* SpeakerboxCall.swift in Sources */,\n\t\t\t\tA04D82611EEB1EB000EBA4CA /* ProviderDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA062C6271EE5FAA200FD64A3 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C6281EE5FAA200FD64A3 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA062C62C1EE5FAA200FD64A3 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA062C62D1EE5FAA200FD64A3 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tA062C6301EE5FAA200FD64A3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA062C6311EE5FAA200FD64A3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tA062C6331EE5FAA200FD64A3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 6276A9694A42BCF2E7D4265A /* Pods-CallKitDemo.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = CallKitDemo/CallKitDemo.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = PR6C39UQ38;\n\t\t\t\tINFOPLIST_FILE = CallKitDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.CallKitDemo2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA062C6341EE5FAA200FD64A3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 78944A861D86C7478ADBE4CE /* Pods-CallKitDemo.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = CallKitDemo/CallKitDemo.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = PR6C39UQ38;\n\t\t\t\tINFOPLIST_FILE = CallKitDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.CallKitDemo2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tA062C61B1EE5FAA200FD64A3 /* Build configuration list for PBXProject \"CallKitDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA062C6301EE5FAA200FD64A3 /* Debug */,\n\t\t\t\tA062C6311EE5FAA200FD64A3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tA062C6321EE5FAA200FD64A3 /* Build configuration list for PBXNativeTarget \"CallKitDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA062C6331EE5FAA200FD64A3 /* Debug */,\n\t\t\t\tA062C6341EE5FAA200FD64A3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = A062C6181EE5FAA200FD64A3 /* Project object */;\n}\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/CallKitDemo.xcodeproj/xcshareddata/xcschemes/CallKitDemo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0900\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n               BuildableName = \"CallKitDemo.app\"\n               BlueprintName = \"CallKitDemo\"\n               ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"A062C61F1EE5FAA200FD64A3\"\n            BuildableName = \"CallKitDemo.app\"\n            BlueprintName = \"CallKitDemo\"\n            ReferencedContainer = \"container:CallKitDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 OpenTok\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'CallKitDemo' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/README.md",
    "content": "![logo](./tokbox-logo.png)\n\n\n\n## CallKit Integration with OpenTok\nA sample app to demonstrate how to integrate the [CallKit](https://developer.apple.com/documentation/callkit) into OpenTok iOS SDK. This sample app is built based on the [SpeakerBox](https://developer.apple.com/library/content/samplecode/Speakerbox/Introduction/Intro.html) app from [WWDC 2016 CallKit Session](https://developer.apple.com/videos/play/wwdc2016/230/).\n\nFor more information, see [this documentation](https://tokbox.com/developer/guides/mobile/ios/#user-content-call-kit).\n### Install the project files\n\nUse CocoaPods to install the project files and dependencies.\n\n1. Install CocoaPods as described in [CocoaPods Getting Started](https://guides.cocoapods.org/using/getting-started.html#getting-started).\n1. In Terminal, `cd` to your project directory and type `pod install`. (Sometimes, `pod update` is magical)\n1. Reopen your project in Xcode using the new `*.xcworkspace` file.\n\n### Configure and build the app\n\nConfigure the sample app code. Then, build and run the app.\n\n1. The application **requires** values for **API Key**, **Session ID**, and **Token**. In the sample, you can get these values at the [OpenTok Developer Dashboard](https://dashboard.tokbox.com/). For production deployment, you must generate the **Session ID** and **Token** values using one of the [OpenTok Server SDKs](https://tokbox.com/developer/sdks/server/).\n\n1. Replace the following empty strings with the corresponding **API Key**, **Session ID**, and **Token** values in `AppDelegate.swift`:\n    ```swift\n      let apiKey = \"\"\n      let sessionId = \"\"\n      let token = \"\"\n    ```\n\n1. Use Xcode to build and run the app on an iOS simulator or device.\n\n### Exploring the sample app\n\n![demo](./demo.png)\n\n  1. **Make a call**: \n\nThe iOS system boosts the call priority of the app. Then, the app starts publishing to OpenTok platform. You won't notice any differences until you go to the home screen. Two ways to verify:\n  - A badge in home screen indicating an ongoing VoIP call.\n  - An incoming native phone call will not interrupt the current VoIP call, instead it shows the option menu.\n  \n  ***You will need a device to test the followings***\n\n  2. **Simulate an incoming call**\n\nThe native incoming call screen appears. Upon acceptance, the iOS system opens the app and boosts the call priority. Then, the app starts publishing to OpenTok platform.\n\n![unlock1](./unlock1.png) ---> ![unlock2](./unlock2.png)\n\n  3. **Simulate an incoming call after 3s(Background)** (After clicking the button, please lock your cell phone to test this scenario.)\n\nThe system wakes up your cell phone by making a native calling screen appear. Upon acceptance (a slider is shown instead of two buttons for the locked screen), the phone stays locked and boosts the call priority. Then, the app (which runs in the background during that time) starts publishing to OpenTok platform. \n\n![lock1](./lock1.png) ---> ![lock2](./lock2.png)\n\n4. **Or use the provided pu.sh script to simulate an incoming call**\n\nYou will need to generate an APNs enabled P8 key in the Certificates, Identifiers & Profiles in the [Apple developer site](https://developer.apple.com/account/resources/authkeys/list).\n\nModify the parameters in the script:\n- TEAMID: Your developer account team ID\n- KEYID: Key ID that is shown in the Apple developer auth keys list\n- SECRET: Path to the P8 key, like \"~/example/AuthKey_XXXXXXXXX.p8\"\n- BUNDLEID: the bundle ID of the app, followed by .voip, like \"com.org.app.voip\"\n- DEVICETOKEN: VoIP push token provided by PushKit\n\nRun the script in the terminal app.\n\n\n**Notice**: You might want to use [OpenTok.js Sample App](https://github.com/opentok/opentok-web-samples/tree/master/Basic%20Video%20Chat) to test the sample app together.\n\n### Exploring the code\n\nFor activating the native OpenTok CallKit support you will need to enable calling services mode. The `OTAudioDeviceManager.currentAudioSessionManager` instance notifies to the SDK that should not try to activate the audio sessions, instead it will wait for the the app audio session activation and deactivation events.\n\nIt’s recommended that you configure the calling services mode in the application start, for example in the `AppDelegate` `didFinishLaunchingWithOptions`method.\n\n```swift\nlet sessionManager = OTAudioDeviceManager.currentAudioSessionManager()\nsessionManager?.enableCallingServicesMode()\n```\n\nA `CXProvider` object is responsible for reporting out-of-band notifications that occur to the system. To create one, you first need to initialize a `CXProviderConfiguration` object, which encapsulates the behaviors and capabilities of calls, to pass on to the `CXProvider` initializer. In order to receive telephony events of the provider, the provider needs to specify an object conforming to the `CXProviderDelegate` protocol.\n\n```swift\n// create a provider configuration\nlet localizedName = NSLocalizedString(\"CallKitDemo\", comment: \"Name of application\")\nlet providerConfiguration = CXProviderConfiguration(localizedName: localizedName)\nproviderConfiguration.supportsVideo = false\nproviderConfiguration.maximumCallsPerCallGroup = 1\nproviderConfiguration.supportedHandleTypes = [.phoneNumber]\nproviderConfiguration.iconTemplateImageData = UIImagePNGRepresentation(#imageLiteral(resourceName: \"IconMask\"))\nproviderConfiguration.ringtoneSound = \"Ringtone.caf\"\n\n// set up a provider\nprovider = CXProvider(configuration: providerConfiguration)\nprovider.setDelegate(self, queue: nil)\n```\n\nThe `CXProviderDelegate` protocol defines events of the telephony provider (`CXProvider`) such as the call starting, the call being put on hold, or the provider’s audio session is activated. CallKit requires a `preheating` stage where the developer has to set up the required `AudioSession` configuration. The configuration is done for you by calling \n\n```swift\npreconfigureAudioSessionForCall(withMode: .voiceChat)\nor\npreconfigureAudioSessionForCall(withMode: .videoChat)\n```\n[VoiceChat](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode-swift.struct/voicechat) mode is commonly used for audio only apps like the Phone app.\n[VideoChat](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode-swift.struct/videochat) mode is commonly used for video conferencing apps like Facetime.\n\nYou will need to notify to the SDK about the audio session configuration stages as well as activations and deactivations in the CXProvider delegate callbacks as seen below:\n\n```swift\n\nlet sessionManager = OTAudioDeviceManager.currentAudioSessionManager()\n\n// MARK: CXProviderDelegate\nfunc providerDidReset(_ provider: CXProvider) {\n    print(\"Provider did reset\")\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXStartCallAction) {\n    print(\"Provider performs the start call action\")\n    // Pre-heating stage for outgoing calls\n    sessionManager?.preconfigureAudioSessionForCall(withMode: .videoChat)\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {\n    print(\"Provider performs the answer call action\")\n    // Pre-heating stage for incoming calls\n    sessionManager?.preconfigureAudioSessionForCall(withMode: .videoChat)\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXEndCallAction) {\n    print(\"Provider performs the end call action\")\n\n    // Trigger the call to be ended via the underlying network service.\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {\n    print(\"Provider performs the hold call action\")\n\n    // You may want to mute/unmute the publisher here\n}\n\nfunc provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {\n    print(\"Provider performs the mute call action\")\n\n    // You may want to mute/unmute the publisher here\n}\n``` \n\nThe following methods indicate whether your VoIP call has been successfully priority boosted or recovered.\n\n```swift\nfunc provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {\n    print(\"Timed out \\(#function)\")\n    // React to the action timeout if necessary, such as showing an error UI.\n}\n\nfunc provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {\n    // Start call audio media, now that the audio session has been activated after having its priority boosted.\n    sessionManager?.audioSessionDidActivate(audioSession)\n}\n\nfunc provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {\n    /*\n        Restart any non-call related audio now that the app's audio session has been\n        de-activated after having its priority restored to normal.\n    */\n    sessionManager?.audioSessionDidDeactivate(audioSession)\n}\n```\n\nLet's explore how to make a call and answer a call on behalf of a user. To do that, we need a `CXCallController` object to interact with the system. \n\nThe `CXCallController` object takes a `CXTransaction` object to request a telephony action (which will later trigger delegate methods above if succeed). To specify a telephony action in a transaction, you need to create your desired action object and associate them with the transaction. Each telephony action has a corresponding `CXAction` class such as `CXEndCallAction` for ending a call, `CXSetHeldCallAction` for setting a call on hold. \n\nOnce you have it all ready, invoke the `request(_:completion:)` by passing a ready transaction object. Here's how you start a call:\n\n```swift\n// create a CXAction\nlet startCallAction = CXStartCallAction(call: UUID(), handle: CXHandle(type: .phoneNumber, value: handle))\n\n// create a transaction\nlet transaction = CXTransaction()\ntransaction.addAction(startCallAction)\n\n// create a label\nlet action = \"startCall\"\n\ncallController.request(transaction) { error in\n    if let error = error {\n        print(\"Error requesting transaction: \\(error)\")\n    } else {\n        print(\"Requested transaction \\(action) successfully\")\n    }\n}\n```\n\nAs for answering a call, the `CallKit` framework provides a convenient API to present a native calling UI like the screen-shot below. By invoking `reportNewIncomingCall(with:update:completion:)` on the provider, you will have the same experience as receiving a native phone call. Often, this piece of code works with VoIP remote notification to make calls to a device/person like WhatsApp, WeChat, and Messenger etc.\n\n```swift\n// Construct a CXCallUpdate describing the incoming call, including the caller.\nlet update = CXCallUpdate()\nupdate.remoteHandle = CXHandle(type: .phoneNumber, value: handle)\n\n// Report the incoming call to the system\nprovider.reportNewIncomingCall(with: uuid, update: update) { error in\n    /*\n      Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error)\n      since calls may be \"denied\" for various legitimate reasons. See CXErrorCodeIncomingCallError.\n    */\n}\n```\n\n![call](./call.jpeg)"
  },
  {
    "path": "CallKit-with-native-OpenTok-support/pu.sh",
    "content": "#!/bin/bash\n\nPAYLOAD=\"\"\n\nuuid=$(uuidgen | tr '[:upper:]' '[:lower:]')\n\nif [ -z \"$1\" ]\n  then\n    PAYLOAD=\"{\\\"aps\\\":{\\\"content-available\\\" : 1}, \\\"UUID\\\":\\\"$uuid\\\", \\\"handle\\\":\\\"Ford Prefect\\\"}\"\n  else \n    PAYLOAD=$(<$1)\nfi\n\nTEAMID=\"\"\nKEYID=\"p8 key name here\"\nSECRET=\"p8 file path\"\nBUNDLEID=\"com.vonage.CallKitDemo.voip\"\nDEVICETOKEN=\"your device voip token\"\n\nfunction base64URLSafe {\n  openssl base64 -e -A | tr -- '+/' '-_' | tr -d =\n}\n\nfunction sign {\n  printf \"$1\"| openssl dgst -binary -sha256 -sign \"$SECRET\" | base64URLSafe\n}\n\ntime=$(date +%s)\nheader=$(printf '{ \"alg\": \"ES256\", \"kid\": \"%s\" }' \"$KEYID\" | base64URLSafe)\nclaims=$(printf '{ \"iss\": \"%s\", \"iat\": %d }' \"$TEAMID\" \"$time\" | base64URLSafe)\njwt=\"$header.$claims.$(sign $header.$claims)\"\n\n# Development server: api.sandbox.push.apple.com:443\nENDPOINT=https://api.sandbox.push.apple.com:443\n# \n# Production server: api.push.apple.com:443\n# Uncomment URL below to send pushes to production server\n# ENDPOINT=https://api.push.apple.com:443\n# \nURLPATH=/3/device/\n\nURL=$ENDPOINT$URLPATH$DEVICETOKEN\n\ncurl -v \\\n   --http2 \\\n   --header \"authorization: bearer $jwt\" \\\n   --header \"apns-topic: ${BUNDLEID}\" \\\n   --header \"apns-push-type: voip\" \\\n   --header \"apns-priority: 10\" \\\n   --data \"${PAYLOAD}\" \\\n   \"${URL}\"\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  4.Custom-Audio-Driver\n//\n//  Created by Roberto Perez Cubero on 21/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n}\n\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/DefaultAudioDevice.swift",
    "content": "//\n//  DefaultAudioDevice.swift\n//  4.Custom-Audio-Driver\n//\n//  Created by Roberto Perez Cubero on 21/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport Foundation\nimport OpenTok\n\nclass DefaultAudioDevice: NSObject {\n#if targetEnvironment(simulator)\n    static let kSampleRate: UInt16 = 44100\n#else\n    static let kSampleRate: UInt16 = 48000\n#endif\n    static let kOutputBus = AudioUnitElement(0)\n    static let kInputBus = AudioUnitElement(1)\n    static let kAudioDeviceHeadset = \"AudioSessionManagerDevice_Headset\"\n    static let kAudioDeviceBluetooth = \"AudioSessionManagerDevice_Bluetooth\"\n    static let kAudioDeviceSpeaker = \"AudioSessionManagerDevice_Speaker\"\n    static let kToMicroSecond: Double = 1000000\n    static let kMaxPlayoutDelay: UInt8 = 150\n    static let kMaxRecordingDelay: UInt16 = 500\n    \n    var audioFormat = OTAudioFormat()\n    let safetyQueue = DispatchQueue(label: \"ot-audio-driver\")\n\n    var deviceAudioBus: OTAudioBus?\n    \n    func setAudioBus(_ audioBus: OTAudioBus?) -> Bool {\n        deviceAudioBus = audioBus\n        audioFormat = OTAudioFormat()\n        audioFormat.sampleRate = DefaultAudioDevice.kSampleRate\n        audioFormat.numChannels = 1\n        return true\n    }\n    \n    var bufferList: UnsafeMutablePointer<AudioBufferList>?\n    var bufferSize: UInt32 = 0\n    var bufferNumFrames: UInt32 = 0\n    var playoutAudioUnitPropertyLatency: Float64 = 0\n    var playoutDelayMeasurementCounter: UInt32 = 0\n    var recordingDelayMeasurementCounter: UInt32 = 0\n    var recordingDelay: UInt32 = 0\n    var recordingAudioUnitPropertyLatency: Float64 = 0\n    var playoutDelay: UInt32 = 0\n    var playing = false\n    var playoutInitialized = false\n    var recording = false\n    var recordingInitialized = false\n    var interruptedPlayback = false\n    var isRecorderInterrupted = false\n    var isPlayerInterrupted = false\n    var isResetting = false\n    var restartRetryCount = 0\n    fileprivate var recordingVoiceUnit: AudioUnit?\n    fileprivate var playoutVoiceUnit: AudioUnit?\n    \n    fileprivate var previousAVAudioSessionCategory: AVAudioSession.Category?\n    fileprivate var avAudioSessionMode: AVAudioSession.Mode?\n    fileprivate var avAudioSessionPreffSampleRate = Double(0)\n    fileprivate var avAudioSessionChannels = 0\n    fileprivate var isAudioSessionSetup = false\n    \n    var areListenerBlocksSetup = false\n    var streamFormat = AudioStreamBasicDescription()\n\n    override init() {\n        audioFormat.sampleRate = DefaultAudioDevice.kSampleRate\n        audioFormat.numChannels = 1\n    }\n    \n    deinit {\n        tearDownAudio()\n        removeObservers()\n    }\n    \n    \n    fileprivate func restartAudio() {\n        safetyQueue.async {\n            self.doRestartAudio(numberOfAttempts: 3)\n        }\n    }\n    \n    fileprivate func restartAudioAfterInterruption() {\n        if isRecorderInterrupted {\n            if startCapture() {\n                isRecorderInterrupted = false\n                restartRetryCount = 0\n            } else {\n                restartRetryCount += 1\n                if restartRetryCount < 3 {\n                    safetyQueue.asyncAfter(deadline: DispatchTime.now(), execute: { [unowned self] in\n                        self.restartAudioAfterInterruption()\n                    })\n                } else {\n                    isRecorderInterrupted = false\n                    isPlayerInterrupted = false\n                    restartRetryCount = 0\n                    print(\"ERROR[OpenTok]:Unable to acquire audio session\")\n                }\n            }\n        }\n        if isPlayerInterrupted {\n            isPlayerInterrupted = false\n            let _ = startRendering()\n        }\n    }\n    \n    fileprivate func doRestartAudio(numberOfAttempts: Int) {\n        isResetting = true\n        if recording {\n            let _ = stopCapture()\n            disposeAudioUnit(audioUnit: &recordingVoiceUnit)\n            let _ = startCapture()\n        }\n        \n        if playing {\n            let _ = self.stopRendering()\n            disposeAudioUnit(audioUnit: &playoutVoiceUnit)\n            let _ = self.startRendering()\n        }\n        isResetting = false\n    }\n    \n    fileprivate func setupAudioUnit(withPlayout playout: Bool) -> Bool {\n        if !isAudioSessionSetup {\n            setupAudioSession()\n            isAudioSessionSetup = true\n        }\n        \n        let bytesPerSample = UInt32(MemoryLayout<Int16>.size)\n        streamFormat.mFormatID = kAudioFormatLinearPCM\n        streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked\n        streamFormat.mBytesPerPacket = bytesPerSample\n        streamFormat.mFramesPerPacket = 1\n        streamFormat.mBytesPerFrame = bytesPerSample\n        streamFormat.mChannelsPerFrame = 1\n        streamFormat.mBitsPerChannel = 8 * bytesPerSample\n        streamFormat.mSampleRate = Float64(DefaultAudioDevice.kSampleRate)\n        \n        var audioUnitDescription = AudioComponentDescription()\n        audioUnitDescription.componentType = kAudioUnitType_Output\n        audioUnitDescription.componentSubType = kAudioUnitSubType_VoiceProcessingIO\n        audioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple\n        audioUnitDescription.componentFlags = 0\n        audioUnitDescription.componentFlagsMask = 0\n        \n        let foundVpioUnitRef = AudioComponentFindNext(nil, &audioUnitDescription)\n        let result: OSStatus = {\n            if playout {\n                return AudioComponentInstanceNew(foundVpioUnitRef!, &playoutVoiceUnit)\n            } else {\n                return AudioComponentInstanceNew(foundVpioUnitRef!, &recordingVoiceUnit)\n            }\n        }()\n        \n        if result != noErr {\n            print(\"Error seting up audio unit\")\n            return false\n        }\n        \n        var value: UInt32 = 1\n        if playout {\n            AudioUnitSetProperty(playoutVoiceUnit!, kAudioOutputUnitProperty_EnableIO,\n                                 kAudioUnitScope_Output, DefaultAudioDevice.kOutputBus, &value,\n                                 UInt32(MemoryLayout<UInt32>.size))\n            \n            AudioUnitSetProperty(playoutVoiceUnit!, kAudioUnitProperty_StreamFormat,\n                                 kAudioUnitScope_Input, DefaultAudioDevice.kOutputBus, &streamFormat,\n                                 UInt32(MemoryLayout<AudioStreamBasicDescription>.size))\n            // Disable Input on playout\n            var enableInput = 0\n            AudioUnitSetProperty(playoutVoiceUnit!, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,\n                                 DefaultAudioDevice.kInputBus, &enableInput, UInt32(MemoryLayout<UInt32>.size))\n        } else {\n            AudioUnitSetProperty(recordingVoiceUnit!, kAudioOutputUnitProperty_EnableIO,\n                                 kAudioUnitScope_Input, DefaultAudioDevice.kInputBus, &value,\n                                 UInt32(MemoryLayout<UInt32>.size))\n            AudioUnitSetProperty(recordingVoiceUnit!, kAudioUnitProperty_StreamFormat,\n                                 kAudioUnitScope_Output, DefaultAudioDevice.kInputBus, &streamFormat,\n                                 UInt32(MemoryLayout<AudioStreamBasicDescription>.size))\n            // Disable Output on record\n            var enableOutput = 0\n            AudioUnitSetProperty(recordingVoiceUnit!, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,\n                                 DefaultAudioDevice.kOutputBus, &enableOutput, UInt32(MemoryLayout<UInt32>.size))\n        }\n        \n        if playout {\n            setupPlayoutCallback()\n        } else {\n            setupRecordingCallback()\n        }\n        \n        setBluetoothAsPreferredInputDevice()\n        \n        return true\n    }\n    \n    fileprivate func setupPlayoutCallback() {\n        let selfPointer = Unmanaged.passUnretained(self).toOpaque()\n        var renderCallback = AURenderCallbackStruct(inputProc: renderCb, inputProcRefCon: selfPointer)\n        AudioUnitSetProperty(playoutVoiceUnit!,\n                             kAudioUnitProperty_SetRenderCallback,\n                             kAudioUnitScope_Input,\n                             DefaultAudioDevice.kOutputBus,\n                             &renderCallback,\n                             UInt32(MemoryLayout<AURenderCallbackStruct>.size))\n        \n    }\n    \n    fileprivate func setupRecordingCallback() {\n        let selfPointer = Unmanaged.passUnretained(self).toOpaque()\n        var inputCallback = AURenderCallbackStruct(inputProc: recordCb, inputProcRefCon: selfPointer)\n        AudioUnitSetProperty(recordingVoiceUnit!,\n                             kAudioOutputUnitProperty_SetInputCallback,\n                             kAudioUnitScope_Global,\n                             DefaultAudioDevice.kInputBus,\n                             &inputCallback,\n                             UInt32(MemoryLayout<AURenderCallbackStruct>.size))\n        \n        var value = 0\n        AudioUnitSetProperty(recordingVoiceUnit!,\n                             kAudioUnitProperty_ShouldAllocateBuffer,\n                             kAudioUnitScope_Output,\n                             DefaultAudioDevice.kInputBus,\n                             &value,\n                             UInt32(MemoryLayout<UInt32>.size))\n    }\n    \n    fileprivate func disposeAudioUnit(audioUnit: inout AudioUnit?) {\n        if let unit = audioUnit {\n            AudioUnitUninitialize(unit)\n            AudioComponentInstanceDispose(unit)\n        }\n        audioUnit = nil\n    }\n    \n    fileprivate func tearDownAudio() {\n        print(\"Destoying audio units\")\n        disposeAudioUnit(audioUnit: &playoutVoiceUnit)\n        disposeAudioUnit(audioUnit: &recordingVoiceUnit)\n        freeupAudioBuffers()\n        \n        let session = AVAudioSession.sharedInstance()\n        do {\n            guard let previousAVAudioSessionCategory = previousAVAudioSessionCategory else { return }\n            try session.setCategory(previousAVAudioSessionCategory, mode: .default)\n            guard let avAudioSessionMode = avAudioSessionMode else { return }\n            try session.setMode(avAudioSessionMode)\n            try session.setPreferredSampleRate(avAudioSessionPreffSampleRate)\n            try session.setPreferredInputNumberOfChannels(avAudioSessionChannels)\n            \n            isAudioSessionSetup = false\n        } catch {\n            print(\"Error reseting AVAudioSession\")\n        }\n    }\n    \n    fileprivate func freeupAudioBuffers() {\n        if var data = bufferList?.pointee, data.mBuffers.mData != nil {\n            data.mBuffers.mData?.assumingMemoryBound(to: UInt16.self).deallocate()\n            data.mBuffers.mData = nil\n        }\n        \n        if let list = bufferList {\n            list.deallocate()\n        }\n        \n        bufferList = nil\n        bufferNumFrames = 0\n    }\n}\n\n// MARK: - Audio Device Implementation\nextension DefaultAudioDevice: OTAudioDevice {\n    func  captureFormat() ->  OTAudioFormat {\n        return audioFormat\n    }\n    func renderFormat() -> OTAudioFormat {\n        return audioFormat\n    }\n    func renderingIsAvailable() -> Bool {\n        return true\n    }\n    func renderingIsInitialized() -> Bool {\n        return playoutInitialized\n    }\n    func isRendering() -> Bool {\n        return playing\n    }\n    func isCapturing() -> Bool {\n        return recording\n    }\n    func estimatedRenderDelay() -> UInt16 {\n        return UInt16(min(self.playoutDelay, UInt32(DefaultAudioDevice.kMaxPlayoutDelay)))\n    }\n    func estimatedCaptureDelay() -> UInt16 {\n        return UInt16(min(self.recordingDelay, UInt32(DefaultAudioDevice.kMaxRecordingDelay)))\n    }\n    func captureIsAvailable() -> Bool {\n        return true\n    }\n    func captureIsInitialized() -> Bool {\n        return recordingInitialized\n    }\n    \n    func initializeRendering() -> Bool {\n        if playing { return false }\n        \n        playoutInitialized = true\n        return playoutInitialized\n    }\n    \n    func startRendering() -> Bool {\n        if playing { return true }\n        playing = true\n        if playoutVoiceUnit == nil {\n            playing = setupAudioUnit(withPlayout: true)\n            if !playing {\n                return false\n            }\n        }\n        \n        let result = AudioOutputUnitStart(playoutVoiceUnit!)\n        \n        if result != noErr {\n            print(\"Error creaing rendering unit\")\n            playing = false\n        }\n        return playing\n    }\n    \n    func stopRendering() -> Bool {\n        if !playing {\n            return true\n        }\n        \n        playing = false\n        \n        let result = AudioOutputUnitStop(playoutVoiceUnit!)\n        if result != noErr {\n            print(\"Error creaing playout unit\")\n            return false\n        }\n        \n        if !recording && !isPlayerInterrupted && !isResetting {\n            tearDownAudio()\n        }\n        \n        return true\n    }\n    \n    \n    func initializeCapture() -> Bool {\n        if recording { return false }\n        \n        recordingInitialized = true\n        return recordingInitialized\n    }\n    \n    func startCapture() -> Bool {\n        if recording {\n            return true\n        }\n        \n        recording = true\n        \n        if recordingVoiceUnit == nil {\n            recording = setupAudioUnit(withPlayout: false)\n            \n            if !recording {\n                return false\n            }\n        }\n        \n        let result = AudioOutputUnitStart(recordingVoiceUnit!)\n        if result != noErr {\n            recording = false\n        }\n        \n        return recording\n    }\n    \n    func stopCapture() -> Bool {\n        if !recording {\n            return true\n        }\n        \n        recording = false\n        \n        let result = AudioOutputUnitStop(recordingVoiceUnit!)\n        \n        if result != noErr {\n            return false\n        }\n        \n        freeupAudioBuffers()\n        \n        if !playing && !isRecorderInterrupted && !isResetting {\n            tearDownAudio()\n        }\n        \n        return true\n    }\n    \n}\n\n// MARK: - AVAudioSession\nextension DefaultAudioDevice {\n    @objc func onInterruptionEvent(notification: Notification) {\n        let type = notification.userInfo?[AVAudioSessionInterruptionTypeKey]\n        safetyQueue.async {\n            self.handleInterruptionEvent(type: type as? Int)\n        }\n    }\n    \n    fileprivate func handleInterruptionEvent(type: Int?) {\n        guard let interruptionType = type else {\n            return\n        }\n        \n        switch  UInt(interruptionType) {\n        case AVAudioSession.InterruptionType.began.rawValue:\n            if recording {\n                isRecorderInterrupted = true\n                let _ = stopCapture()\n            }\n            if playing {\n                isPlayerInterrupted = true\n                let _ = stopRendering()\n            }\n        case AVAudioSession.InterruptionType.ended.rawValue:\n            configureAudioSessionWithDesiredAudioRoute(desiredAudioRoute: DefaultAudioDevice.kAudioDeviceBluetooth)\n            restartAudioAfterInterruption()\n        default:\n            break\n        }\n    }\n    \n    @objc func onRouteChangeEvent(notification: Notification) {\n        safetyQueue.async {\n            self.handleRouteChangeEvent(notification: notification)\n        }\n    }\n    \n    @objc func appDidBecomeActive(notification: Notification) {\n        safetyQueue.async {\n            self.handleInterruptionEvent(type: Int(AVAudioSession.InterruptionType.ended.rawValue))\n        }\n    }\n    \n    fileprivate func handleRouteChangeEvent(notification: Notification) {\n        guard let reason = notification.userInfo?[AVAudioSessionRouteChangeReasonKey] as? UInt else {\n            return\n        }\n        \n        if reason == AVAudioSession.RouteChangeReason.routeConfigurationChange.rawValue {\n            return\n        }\n        \n        if reason == AVAudioSession.RouteChangeReason.override.rawValue ||\n            reason == AVAudioSession.RouteChangeReason.categoryChange.rawValue {\n            \n            let oldRouteDesc = notification.userInfo?[AVAudioSessionRouteChangePreviousRouteKey] as! AVAudioSessionRouteDescription\n            let outputs = oldRouteDesc.outputs\n            var oldOutputDeviceName: String? = nil\n            var currentOutputDeviceName: String? = nil\n            \n            if outputs.count > 0 {\n                let portDesc = outputs[0]\n                oldOutputDeviceName = portDesc.portName\n            }\n            \n            if AVAudioSession.sharedInstance().currentRoute.outputs.count > 0 {\n                currentOutputDeviceName = AVAudioSession.sharedInstance().currentRoute.outputs[0].portName\n            }\n            \n            if oldOutputDeviceName == currentOutputDeviceName || currentOutputDeviceName == nil || oldOutputDeviceName == nil {\n                return\n            }\n            \n            restartAudio()\n        }\n    }\n    \n    fileprivate func setupListenerBlocks() {\n        if areListenerBlocksSetup {\n            return\n        }\n        \n        let notificationCenter = NotificationCenter.default\n        \n        notificationCenter.addObserver(self, selector: #selector(DefaultAudioDevice.onInterruptionEvent),\n                                       name: AVAudioSession.interruptionNotification, object: nil)\n        notificationCenter.addObserver(self, selector: #selector(DefaultAudioDevice.onRouteChangeEvent(notification:)),\n                                       name: AVAudioSession.routeChangeNotification, object: nil)\n        notificationCenter.addObserver(self, selector: #selector(DefaultAudioDevice.appDidBecomeActive(notification:)),\n                                       name: UIApplication.didBecomeActiveNotification, object: nil)\n        \n        areListenerBlocksSetup = true\n    }\n    \n    fileprivate func removeObservers() {\n        NotificationCenter.default.removeObserver(self)\n        areListenerBlocksSetup = false\n    }\n    \n    fileprivate func setupAudioSession() {\n        let session = AVAudioSession.sharedInstance()\n        \n        previousAVAudioSessionCategory = session.category\n        avAudioSessionMode = session.mode\n        avAudioSessionPreffSampleRate = session.preferredSampleRate\n        avAudioSessionChannels = session.inputNumberOfChannels\n        do {\n            try session.setPreferredSampleRate(Double(DefaultAudioDevice.kSampleRate))\n            try session.setPreferredIOBufferDuration(0.01)\n            let audioOptions = AVAudioSession.CategoryOptions.mixWithOthers.rawValue |\n                AVAudioSession.CategoryOptions.allowBluetooth.rawValue |\n                AVAudioSession.CategoryOptions.defaultToSpeaker.rawValue\n            try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.videoChat, options: AVAudioSession.CategoryOptions(rawValue: audioOptions))\n            setupListenerBlocks()\n            \n            try session.setActive(true)\n        } catch let err as NSError {\n            print(\"Error setting up audio session \\(err)\")\n        } catch {\n            print(\"Error setting up audio session\")\n        }\n    }\n}\n\n// MARK: - Audio Route functions\nextension DefaultAudioDevice {\n    fileprivate func setBluetoothAsPreferredInputDevice() {\n        let btRoutes = [AVAudioSession.Port.bluetoothA2DP, AVAudioSession.Port.bluetoothLE, AVAudioSession.Port.bluetoothHFP]\n        AVAudioSession.sharedInstance().availableInputs?.forEach({ el in\n            if btRoutes.contains(el.portType) {\n                do {\n                    try AVAudioSession.sharedInstance().setPreferredInput(el)\n                } catch {\n                    print(\"Error setting BT as preferred input device\")\n                }\n            }\n        })\n    }\n    \n    fileprivate func configureAudioSessionWithDesiredAudioRoute(desiredAudioRoute: String) {\n        let session = AVAudioSession.sharedInstance()\n        \n        if desiredAudioRoute == DefaultAudioDevice.kAudioDeviceBluetooth {\n            setBluetoothAsPreferredInputDevice()\n        }\n        do {\n            if desiredAudioRoute == DefaultAudioDevice.kAudioDeviceSpeaker {\n                try session.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)\n            } else {\n                try session.overrideOutputAudioPort(AVAudioSession.PortOverride.none)\n            }\n        } catch let err as NSError {\n            print(\"Error setting audio route: \\(err)\")\n        }\n    }\n}\n\n// MARK: - Render and Record C Callbacks\nfunc renderCb(inRefCon:UnsafeMutableRawPointer,\n              ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,\n              inTimeStamp:UnsafePointer<AudioTimeStamp>,\n              inBusNumber:UInt32,\n              inNumberFrames:UInt32,\n              ioData:UnsafeMutablePointer<AudioBufferList>?) -> OSStatus\n{\n    let audioDevice: DefaultAudioDevice = Unmanaged.fromOpaque(inRefCon).takeUnretainedValue()\n    if !audioDevice.playing { return 0 }\n    \n    let _ = audioDevice.deviceAudioBus!.readRenderData((ioData?.pointee.mBuffers.mData)!, numberOfSamples: inNumberFrames)\n    updatePlayoutDelay(withAudioDevice: audioDevice)\n    \n    return noErr\n}\n\nfunc recordCb(inRefCon:UnsafeMutableRawPointer,\n              ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,\n              inTimeStamp:UnsafePointer<AudioTimeStamp>,\n              inBusNumber:UInt32,\n              inNumberFrames:UInt32,\n              ioData:UnsafeMutablePointer<AudioBufferList>?) -> OSStatus\n{\n    let audioDevice: DefaultAudioDevice = Unmanaged.fromOpaque(inRefCon).takeUnretainedValue()\n    if audioDevice.bufferList == nil || inNumberFrames > audioDevice.bufferNumFrames {\n        if audioDevice.bufferList != nil {\n            audioDevice.bufferList!.pointee.mBuffers.mData?\n                .assumingMemoryBound(to: UInt16.self).deallocate()\n            audioDevice.bufferList?.deallocate()\n        }\n        \n        audioDevice.bufferList = UnsafeMutablePointer<AudioBufferList>.allocate(capacity: 1)\n        audioDevice.bufferList?.pointee.mNumberBuffers = 1\n        audioDevice.bufferList?.pointee.mBuffers.mNumberChannels = 1\n        \n        audioDevice.bufferList?.pointee.mBuffers.mDataByteSize = inNumberFrames * UInt32(MemoryLayout<UInt16>.size)\n        audioDevice.bufferList?.pointee.mBuffers.mData = UnsafeMutableRawPointer(UnsafeMutablePointer<UInt16>.allocate(capacity: Int(inNumberFrames)))\n        audioDevice.bufferNumFrames = inNumberFrames\n        audioDevice.bufferSize = (audioDevice.bufferList?.pointee.mBuffers.mDataByteSize)!\n    }\n    \n    AudioUnitRender(audioDevice.recordingVoiceUnit!,\n                    ioActionFlags,\n                    inTimeStamp,\n                    1,\n                    inNumberFrames,\n                    audioDevice.bufferList!)\n    \n    if audioDevice.recording {\n        audioDevice.deviceAudioBus!.writeCaptureData((audioDevice.bufferList?.pointee.mBuffers.mData)!, numberOfSamples: inNumberFrames)\n    }\n    \n    if audioDevice.bufferSize != audioDevice.bufferList?.pointee.mBuffers.mDataByteSize {\n        audioDevice.bufferList?.pointee.mBuffers.mDataByteSize = audioDevice.bufferSize\n    }\n    \n    updateRecordingDelay(withAudioDevice: audioDevice)\n    \n    return noErr\n}\n\nfunc updatePlayoutDelay(withAudioDevice audioDevice: DefaultAudioDevice) {\n    audioDevice.playoutDelayMeasurementCounter += 1\n    if audioDevice.playoutDelayMeasurementCounter >= 100 {\n        // Update HW and OS delay every second, unlikely to change\n        audioDevice.playoutDelay = 0\n        let session = AVAudioSession.sharedInstance()\n        \n        // HW output latency\n        let interval = session.outputLatency\n        audioDevice.playoutDelay += UInt32(interval * DefaultAudioDevice.kToMicroSecond)\n        // HW buffer duration\n        let ioInterval = session.ioBufferDuration\n        audioDevice.playoutDelay += UInt32(ioInterval * DefaultAudioDevice.kToMicroSecond)\n        audioDevice.playoutDelay += UInt32(audioDevice.playoutAudioUnitPropertyLatency * DefaultAudioDevice.kToMicroSecond)\n        // To ms\n         audioDevice.playoutDelay = (audioDevice.playoutDelay - 500) / 1000\n\n        audioDevice.playoutDelayMeasurementCounter = 0\n    }\n}\n\nfunc updateRecordingDelay(withAudioDevice audioDevice: DefaultAudioDevice) {\n    audioDevice.recordingDelayMeasurementCounter += 1\n    \n    if audioDevice.recordingDelayMeasurementCounter >= 100 {\n        audioDevice.recordingDelay = 0\n        let session = AVAudioSession.sharedInstance()\n        let interval = session.inputLatency\n        \n        audioDevice.recordingDelay += UInt32(interval * DefaultAudioDevice.kToMicroSecond)\n        let ioInterval = session.ioBufferDuration\n        \n        audioDevice.recordingDelay += UInt32(ioInterval * DefaultAudioDevice.kToMicroSecond)\n        audioDevice.recordingDelay += UInt32(audioDevice.recordingAudioUnitPropertyLatency * DefaultAudioDevice.kToMicroSecond)\n        \n        audioDevice.recordingDelay = audioDevice.recordingDelay.advanced(by: -500) / 1000\n        \n        audioDevice.recordingDelayMeasurementCounter = 0\n    }\n}\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Custom-Audio-Driver\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n    let customAudioDevice = DefaultAudioDevice()\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        OTAudioDeviceManager.setAudioDevice(customAudioDevice)\n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    private func doConnect() {\n        var error: OTError?\n        defer {\n            process(error: error)\n        }        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError? = nil\n        defer {\n            process(error: error)\n        }\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        publisher = OTPublisher(delegate: self, settings: settings)\n        if let pub = publisher, let pubView = pub.view {\n            session.publish(pub, error: &error)\n            pubView.frame = CGRect(x: 0, y: 0, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(pubView)\n        }\n    }\n    \n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            process(error: error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func process(error err: OTError?) {\n        if let e = err {\n            showAlert(errorStr: e.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")        \n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        doSubscribe(stream)\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            subscriber?.view?.removeFromSuperview()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        subscriber?.view?.frame = CGRect(x: 0, y: kWidgetHeight, width: kWidgetWidth, height: kWidgetHeight)\n        if let subsView = subscriber?.view {\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA053761A1EB16D9700645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376111EB16D9700645696 /* AppDelegate.swift */; };\n\t\tA053761B1EB16D9700645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05376121EB16D9700645696 /* Assets.xcassets */; };\n\t\tA053761C1EB16D9700645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05376131EB16D9700645696 /* LaunchScreen.storyboard */; };\n\t\tA053761D1EB16D9700645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05376151EB16D9700645696 /* Main.storyboard */; };\n\t\tA053761E1EB16D9700645696 /* DefaultAudioDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376171EB16D9700645696 /* DefaultAudioDevice.swift */; };\n\t\tA05376201EB16D9700645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376191EB16D9700645696 /* ViewController.swift */; };\n\t\tA07707051EDF7B8300E8FB97 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A07707041EDF7B8300E8FB97 /* Default-568h@2x.png */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05376111EB16D9700645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05376121EB16D9700645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05376141EB16D9700645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05376161EB16D9700645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05376171EB16D9700645696 /* DefaultAudioDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultAudioDevice.swift; sourceTree = \"<group>\"; };\n\t\tA05376181EB16D9700645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05376191EB16D9700645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tA07707041EDF7B8300E8FB97 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"Default-568h@2x.png\"; sourceTree = \"<group>\"; };\n\t\tF882D72A1D92B85B00FD72FD /* Custom-Audio-Driver.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Custom-Audio-Driver.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF882D7271D92B85B00FD72FD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA05376101EB16D9700645696 /* Custom-Audio-Driver */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376111EB16D9700645696 /* AppDelegate.swift */,\n\t\t\t\tA05376121EB16D9700645696 /* Assets.xcassets */,\n\t\t\t\tA05376131EB16D9700645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05376151EB16D9700645696 /* Main.storyboard */,\n\t\t\t\tA05376171EB16D9700645696 /* DefaultAudioDevice.swift */,\n\t\t\t\tA05376181EB16D9700645696 /* Info.plist */,\n\t\t\t\tA05376191EB16D9700645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Custom-Audio-Driver\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF882D7211D92B85B00FD72FD = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA07707041EDF7B8300E8FB97 /* Default-568h@2x.png */,\n\t\t\t\tA05376101EB16D9700645696 /* Custom-Audio-Driver */,\n\t\t\t\tF882D72B1D92B85B00FD72FD /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF882D72B1D92B85B00FD72FD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF882D72A1D92B85B00FD72FD /* Custom-Audio-Driver.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF882D7291D92B85B00FD72FD /* Custom-Audio-Driver */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F882D73C1D92B85B00FD72FD /* Build configuration list for PBXNativeTarget \"Custom-Audio-Driver\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF882D7261D92B85B00FD72FD /* Sources */,\n\t\t\t\tF882D7271D92B85B00FD72FD /* Frameworks */,\n\t\t\t\tF882D7281D92B85B00FD72FD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Custom-Audio-Driver\";\n\t\t\tproductName = \"3.Custom-Audio-Driver\";\n\t\t\tproductReference = F882D72A1D92B85B00FD72FD /* Custom-Audio-Driver.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF882D7221D92B85B00FD72FD /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0800;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF882D7291D92B85B00FD72FD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F882D7251D92B85B00FD72FD /* Build configuration list for PBXProject \"Custom-Audio-Driver\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F882D7211D92B85B00FD72FD;\n\t\t\tproductRefGroup = F882D72B1D92B85B00FD72FD /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF882D7291D92B85B00FD72FD /* Custom-Audio-Driver */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF882D7281D92B85B00FD72FD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA053761D1EB16D9700645696 /* Main.storyboard in Resources */,\n\t\t\t\tA053761B1EB16D9700645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA07707051EDF7B8300E8FB97 /* Default-568h@2x.png in Resources */,\n\t\t\t\tA053761C1EB16D9700645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF882D7261D92B85B00FD72FD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05376201EB16D9700645696 /* ViewController.swift in Sources */,\n\t\t\t\tA053761E1EB16D9700645696 /* DefaultAudioDevice.swift in Sources */,\n\t\t\t\tA053761A1EB16D9700645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05376131EB16D9700645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376141EB16D9700645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05376151EB16D9700645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376161EB16D9700645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF882D73A1D92B85B00FD72FD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF882D73B1D92B85B00FD72FD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF882D73D1D92B85B00FD72FD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Custom-Audio-Driver/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Custom-Audio-Driver\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF882D73E1D92B85B00FD72FD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Custom-Audio-Driver/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Custom-Audio-Driver\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF882D7251D92B85B00FD72FD /* Build configuration list for PBXProject \"Custom-Audio-Driver\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF882D73A1D92B85B00FD72FD /* Debug */,\n\t\t\t\tF882D73B1D92B85B00FD72FD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF882D73C1D92B85B00FD72FD /* Build configuration list for PBXNativeTarget \"Custom-Audio-Driver\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF882D73D1D92B85B00FD72FD /* Debug */,\n\t\t\t\tF882D73E1D92B85B00FD72FD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F882D7221D92B85B00FD72FD /* Project object */;\n}\n"
  },
  {
    "path": "Custom-Audio-Driver/Custom-Audio-Driver.xcodeproj/xcshareddata/xcschemes/Custom-Audio-Driver.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F882D7291D92B85B00FD72FD\"\n               BuildableName = \"Custom-Audio-Driver.app\"\n               BlueprintName = \"Custom-Audio-Driver\"\n               ReferencedContainer = \"container:Custom-Audio-Driver.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F882D7291D92B85B00FD72FD\"\n            BuildableName = \"Custom-Audio-Driver.app\"\n            BlueprintName = \"Custom-Audio-Driver\"\n            ReferencedContainer = \"container:Custom-Audio-Driver.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F882D7291D92B85B00FD72FD\"\n            BuildableName = \"Custom-Audio-Driver.app\"\n            BlueprintName = \"Custom-Audio-Driver\"\n            ReferencedContainer = \"container:Custom-Audio-Driver.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F882D7291D92B85B00FD72FD\"\n            BuildableName = \"Custom-Audio-Driver.app\"\n            BlueprintName = \"Custom-Audio-Driver\"\n            ReferencedContainer = \"container:Custom-Audio-Driver.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Custom-Audio-Driver/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Custom-Audio-Driver' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Custom-Audio-Driver/README.md",
    "content": "Custom Audio Driver Sample App\n================================\n\nThis project implements a controller nearly identical to the hello world sample.\nThe entry point of new content is during the controllers `viewDidLoad()`\ncallback, where we set up an audio device before initializing our first OpenTok\nobject. It is important to note that audio device setup *must* occur before any\ninstance of OTSession or OTPublisher is initialized:\n\n```swift\nlet customAudioDevice = DefaultAudioDevice.sharedInstance\nOTAudioDeviceManager.setAudioDevice(customAudioDevice)\n```\n\n`DefaultAudioDevice` is a copy of the default device driver used in\nthe OpenTok iOS SDK. If no audio device is set prior to the first instantiation\nof OTSession, the default driver will be used. A common reason for a developer\nto look at this sample is to debug audio issues in their application. This is\nalso a good entry point for managing more complicated audio routing and\ncustomization of handling audio events on the device during the lifecycle of\nyour app.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nApplication Notes\n-----------------\n\n* `recording_cb` and `playout_cb` are the two main operator functions in the\n  audio graph once initialization has occurred and the session is active.\n  Setting breakpoints on these functions can be useful to verify that the audio\n  graph is indeed running and producing/consuming audio.\n\n* The callbacks `onRouteChangeEvent:` and `onInteruptionEvent:` are hooked into\n  the system events and listen for important audio events that developers may\n  wish to handle properly in different contexts of their app.\n\n* There are known constraints to sample rates and formats inherited from both\n  the WebRTC runtime and iOS. The rates chosen in the sample audio device are\n  known working configurations, but not everything will work. The simulator\n  needs to run at 44.1 kHz. Devices should stick between 8-32 kHz. This example\n  sticks to using unsigned 16-bit integers as the sample format. Your mileage\n  may vary with adjusting any of these.\n"
  },
  {
    "path": "Custom-Video-Driver/Custom-Video-Driver.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tF84DC3AD1D5C8B6400402BD9 /* ExampleVideoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84DC3AC1D5C8B6400402BD9 /* ExampleVideoCapture.swift */; };\n\t\tF84DC3AF1D5C8BF400402BD9 /* ExampleVideoRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */; };\n\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BB1D5C8A150081846D /* AppDelegate.swift */; };\n\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BD1D5C8A150081846D /* ViewController.swift */; };\n\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64BF1D5C8A150081846D /* Main.storyboard */; };\n\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C21D5C8A150081846D /* Assets.xcassets */; };\n\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C41D5C8A150081846D /* LaunchScreen.storyboard */; };\n\t\tF8C552001D635AFE00484097 /* EAGLVideoRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C551FF1D635AFE00484097 /* EAGLVideoRenderer.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tF84DC3AC1D5C8B6400402BD9 /* ExampleVideoCapture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleVideoCapture.swift; sourceTree = \"<group>\"; };\n\t\tF84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleVideoRender.swift; sourceTree = \"<group>\"; };\n\t\tF86C64B81D5C8A150081846D /* Custom-Video-Driver.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Custom-Video-Driver.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF86C64C01D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tF86C64C51D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C71D5C8A150081846D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tF8C551FF1D635AFE00484097 /* EAGLVideoRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EAGLVideoRenderer.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64B51D5C8A150081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tF86C64AF1D5C8A150081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64BA1D5C8A150081846D /* Lets-Build-OTPublisher */,\n\t\t\t\tF86C64B91D5C8A150081846D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64B91D5C8A150081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64B81D5C8A150081846D /* Custom-Video-Driver.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64BA1D5C8A150081846D /* Lets-Build-OTPublisher */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */,\n\t\t\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */,\n\t\t\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */,\n\t\t\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */,\n\t\t\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */,\n\t\t\t\tF86C64C71D5C8A150081846D /* Info.plist */,\n\t\t\t\tF84DC3AC1D5C8B6400402BD9 /* ExampleVideoCapture.swift */,\n\t\t\t\tF84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */,\n\t\t\t\tF8C551FF1D635AFE00484097 /* EAGLVideoRenderer.swift */,\n\t\t\t);\n\t\t\tpath = \"Lets-Build-OTPublisher\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64B71D5C8A150081846D /* Custom-Video-Driver */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"Custom-Video-Driver\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF86C64B41D5C8A150081846D /* Sources */,\n\t\t\t\tF86C64B51D5C8A150081846D /* Frameworks */,\n\t\t\t\tF86C64B61D5C8A150081846D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Custom-Video-Driver\";\n\t\t\tproductName = \"Lets-Build-OTPublisher\";\n\t\t\tproductReference = F86C64B81D5C8A150081846D /* Custom-Video-Driver.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64B01D5C8A150081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64B71D5C8A150081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"Custom-Video-Driver\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64AF1D5C8A150081846D;\n\t\t\tproductRefGroup = F86C64B91D5C8A150081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64B71D5C8A150081846D /* Custom-Video-Driver */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64B61D5C8A150081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */,\n\t\t\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64B41D5C8A150081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */,\n\t\t\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */,\n\t\t\t\tF8C552001D635AFE00484097 /* EAGLVideoRenderer.swift in Sources */,\n\t\t\t\tF84DC3AD1D5C8B6400402BD9 /* ExampleVideoCapture.swift in Sources */,\n\t\t\t\tF84DC3AF1D5C8BF400402BD9 /* ExampleVideoRender.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C01D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C51D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64C81D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64C91D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64CB1D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"COCOAPODS=1\",\n\t\t\t\t\t\"GLES_SILENCE_DEPRECATION=1\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Lets-Build-OTPublisher/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Lets-Build-OTPublisher\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64CC1D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"Lets-Build-OTPublisher/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Lets-Build-OTPublisher\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"Custom-Video-Driver\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64C81D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64C91D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"Custom-Video-Driver\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64CB1D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64CC1D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64B01D5C8A150081846D /* Project object */;\n}\n"
  },
  {
    "path": "Custom-Video-Driver/Custom-Video-Driver.xcodeproj/xcshareddata/xcschemes/Custom-Video-Driver.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n               BuildableName = \"Custom-Video-Driver.app\"\n               BlueprintName = \"Custom-Video-Driver\"\n               ReferencedContainer = \"container:Custom-Video-Driver.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Custom-Video-Driver.app\"\n            BlueprintName = \"Custom-Video-Driver\"\n            ReferencedContainer = \"container:Custom-Video-Driver.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Custom-Video-Driver.app\"\n            BlueprintName = \"Custom-Video-Driver\"\n            ReferencedContainer = \"container:Custom-Video-Driver.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Custom-Video-Driver.app\"\n            BlueprintName = \"Custom-Video-Driver\"\n            ReferencedContainer = \"container:Custom-Video-Driver.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n\n\n}\n\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16E195\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12086\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"__Custom_Video_Driver\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zee-CQ-GLa\">\n                                <rect key=\"frame\" x=\"124\" y=\"617\" width=\"127\" height=\"30\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"30\" id=\"pFD-ov-Knc\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"127\" id=\"rzH-e2-cxL\"/>\n                                </constraints>\n                                <state key=\"normal\" title=\"Toggle Camera\">\n                                    <color key=\"titleColor\" red=\"0.0\" green=\"0.47843137250000001\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"toggleCamera:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"84i-Wg-qRC\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"zee-CQ-GLa\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"AuW-yJ-KJF\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"zee-CQ-GLa\" secondAttribute=\"bottom\" constant=\"20\" id=\"g4N-TL-UpI\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"32.799999999999997\" y=\"36.431784107946029\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/EAGLVideoRenderer.swift",
    "content": "//\n//  EAGLVideoRenderer.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 16/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport GLKit\nimport OpenTok\n\nclass EAGLVideoRenderer {\n    static let kNumTextureSets: GLsizei  = 2\n    static let kNumTextures: GLsizei  = 3 * kNumTextureSets\n    \n    let vertexShader =\n        \"attribute vec2 position;\" +\n        \"attribute vec2 texcoord;\" +\n        \"varying vec2 v_texcoord;\" +\n        \"void main() {\" +\n        \"   gl_Position = vec4(position.x, position.y, 0.0, 1.0);\" +\n        \"   v_texcoord = texcoord;\" +\n        \"}\"\n    \n    let fragmentShader =\n        \"precision highp float;\" +\n        \"varying vec2 v_texcoord;\" +\n        \"uniform lowp sampler2D s_textureY;\" +\n        \"uniform lowp sampler2D s_textureU;\" +\n        \"uniform lowp sampler2D s_textureV;\" +\n        \"void main() {\" +\n        \"   float y, u, v, r, g, b;\" +\n        \"   y = texture2D(s_textureY, v_texcoord).r;\" +\n        \"   u = texture2D(s_textureU, v_texcoord).r;\" +\n        \"   v = texture2D(s_textureV, v_texcoord).r;\" +\n        \"   u = u - 0.5;\" +\n        \"   v = v - 0.5;\" +\n        \"   r = y + 1.403 * v;\" +\n        \"   g = y - 0.344 * u - 0.714 * v;\" +\n        \"   b = y + 1.770 * u;\" +\n        \"   gl_FragColor = vec4(r, g, b, 1.0);\" +\n        \"}\"\n    \n    fileprivate let context: EAGLContext\n    fileprivate var isInitialized = false\n    fileprivate var glProgram: GLuint = 0\n    fileprivate var position: GLuint = 0\n    fileprivate var texcoord: GLuint = 0\n    fileprivate var ySampler: GLint = 0\n    fileprivate var uSampler: GLint = 0\n    fileprivate var vSampler: GLint = 0\n    fileprivate var textures = [GLuint](repeating: GLuint(0), count: Int(kNumTextures))\n    fileprivate var vertexBuffer: GLuint = 0\n    fileprivate var vertices = [GLfloat](repeating: GLfloat(0), count: 16)\n    fileprivate var lastImageSize = CGSize(width: -1, height: -1)\n    fileprivate var lastViewportSize = CGSize(width: -1, height: -1)\n    fileprivate var flushVertices = false\n    var mirroring = false {\n        didSet {\n            flushVertices = true\n        }\n    }\n    fileprivate var intialized = false\n    var lastFrameTime = CMTimeValue(0)\n\n    init(context: EAGLContext) {\n        self.context = context\n    }\n    \n    func setupGL() {\n        if isInitialized { return }\n        \n        ensureGLContext()\n        \n        do {\n            try setupProgram()\n            setupTextures()\n            setupVertices()\n            glUseProgram(glProgram)\n            glPixelStorei(GLenum(GL_UNPACK_ALIGNMENT), 1)\n            glClearColor(0, 0, 0, 1)\n            isInitialized = true\n        } catch {\n            print(\"Error initializing OpenGL\")\n        }\n    }\n    \n    func teardownGL() {\n        if !isInitialized { return }\n        \n        ensureGLContext()\n        glDeleteProgram(glProgram)\n        glProgram = 0\n        glDeleteTextures(EAGLVideoRenderer.kNumTextures, &textures)\n        glDeleteBuffers(1, &vertexBuffer)\n        vertexBuffer = 0\n        isInitialized = false\n    }\n    \n    func drawFrame(frame f: OTVideoFrame, withViewport:CGRect) {\n        guard let frameFormat = f.format, isInitialized, lastFrameTime != f.timestamp.value\n            else {\n                return\n        }\n        \n        ensureGLContext()\n        \n        updateTextureSizesForFrame(frame: f)\n        updateTextureDataForFrame(frame: f)\n        \n        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))\n        let imageSize = CGSize(width: CGFloat(frameFormat.imageWidth), height: CGFloat(frameFormat.imageHeight))\n        if flushVertices {\n            flushVertices = false\n            updateVerticesWithViewportSize()\n        }\n        updateVerticesWithViewportSize(withViewport.size, imageSize: imageSize)\n        \n        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)\n        glBufferData(GLenum(GL_ARRAY_BUFFER), vertices.count * MemoryLayout<GLfloat>.size, vertices,\n                     GLenum(GL_DYNAMIC_DRAW))\n        glDrawArrays(GLenum(GL_TRIANGLE_FAN), 0, 4)\n        lastFrameTime = f.timestamp.value\n        lastDrawnWidth = frameFormat.imageWidth\n        lastDrawnHeight = frameFormat.imageHeight\n    }\n    \n    func clearFrame() {\n        if !isInitialized {\n            return\n        }\n        \n        ensureGLContext()\n        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))\n    }\n    \n    fileprivate func ensureGLContext() {\n        if EAGLContext.current() != context {\n            EAGLContext.setCurrent(context)\n        }\n    }\n    \n    fileprivate func createShader(_ type: GLenum, source: String) throws -> GLuint {\n        let shader = glCreateShader(type)\n        var cStringSource = (source as NSString).utf8String\n        glShaderSource(shader, 1, &cStringSource, nil)\n        glCompileShader(shader)\n        var compileStatus = GL_FALSE\n        glGetShaderiv(shader, GLenum(GL_COMPILE_STATUS), &compileStatus)\n        if compileStatus == GL_FALSE {\n            glDeleteShader(shader)\n            throw NSError(domain: \"opentok\", code: 100, userInfo: nil)            \n        }\n        return shader\n    }\n    \n    fileprivate func createProgram(_ vertexShader: GLuint, fragmentShader: GLuint) throws -> GLuint {\n        let program = glCreateProgram()\n        glAttachShader(program, vertexShader)\n        glAttachShader(program, fragmentShader)\n        glLinkProgram(program)\n        var status = GL_FALSE\n        glGetProgramiv(program, GLenum(GL_LINK_STATUS), &status)\n        if status == GL_FALSE {\n            glDeleteProgram(program)\n            throw NSError(domain: \"opentok\", code: 100, userInfo: nil)\n        }\n        return program\n    }\n    \n    fileprivate func getAttribLocation(_ program: GLuint, attrib: String) -> GLuint {\n        return GLuint(glGetAttribLocation(program, (attrib as NSString).utf8String))\n    }\n    \n    fileprivate func getUniformLocation(_ program: GLuint, location: String) -> GLint {\n        return glGetUniformLocation(program, (location as NSString).utf8String)\n    }\n    \n    fileprivate func setupProgram() throws {\n        let vertexShader = try createShader(GLenum(GL_VERTEX_SHADER), source: self.vertexShader)\n        let fragmentShader = try createShader(GLenum(GL_FRAGMENT_SHADER), source: self.fragmentShader)\n        glProgram = try createProgram(vertexShader, fragmentShader: fragmentShader)\n        \n        glDeleteShader(vertexShader)\n        glDeleteShader(fragmentShader)\n        \n        \n        position = getAttribLocation(glProgram, attrib: \"position\")\n        texcoord = getAttribLocation(glProgram, attrib: \"texcoord\")\n        ySampler = getUniformLocation(glProgram, location: \"s_textureY\")\n        uSampler = getUniformLocation(glProgram, location: \"s_textureU\")\n        vSampler = getUniformLocation(glProgram, location: \"s_textureV\")\n    }\n    \n    fileprivate func setupTextures() {\n        glGenTextures(EAGLVideoRenderer.kNumTextures, UnsafeMutablePointer(mutating: textures))\n        for (index, texture) in textures.enumerated() {\n            glActiveTexture(UInt32(GL_TEXTURE0.advanced(by: index)))\n            glBindTexture(GLenum(GL_TEXTURE_2D), texture)\n            glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_LINEAR);\n            glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GL_LINEAR);\n            glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GL_CLAMP_TO_EDGE);\n            glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GL_CLAMP_TO_EDGE);\n        }\n    }\n    \n    fileprivate func setupVertices() {\n        glGenBuffers(1, &vertexBuffer)\n        updateVerticesWithViewportSize()\n    }\n    \n    fileprivate func updateVerticesWithViewportSize(_ viewportSize: CGSize = CGSize(width: 1, height: 1),\n                                                imageSize: CGSize = CGSize(width: 1, height: 1))\n    {\n        if lastImageSize == imageSize && viewportSize == lastViewportSize {\n            return\n        }\n        \n        lastImageSize = imageSize\n        lastViewportSize = viewportSize\n        \n        let imageRatio = GLfloat(imageSize.width / imageSize.height)\n        let viewportRatio = GLfloat(viewportSize.width / viewportSize.height)\n        \n        var scaleX = GLfloat(1.0)\n        var scaleY = GLfloat(1.0)\n        \n        if imageRatio > viewportRatio {\n            scaleY = viewportRatio / imageRatio\n        } else {\n            scaleX = imageRatio / viewportRatio\n        }\n        \n        if mirroring { scaleX = -scaleX }\n        \n        vertices[0] = -1 * scaleX\n        vertices[1] = -1 * scaleY\n        vertices[2] = 0\n        vertices[3] = 1\n        vertices[4] = 1 * scaleX\n        vertices[5] = -1 * scaleY\n        vertices[6] = 1\n        vertices[7] = 1\n        vertices[8] = 1 * scaleX\n        vertices[9] = 1 * scaleY\n        vertices[10] = 1\n        vertices[11] = 0\n        vertices[12] = -1 * scaleX\n        vertices[13] = 1 * scaleY\n        vertices[14] = 0\n        vertices[15] = 0\n        \n        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)\n        glBufferData(GLenum(GL_ARRAY_BUFFER), vertices.count * MemoryLayout<GLfloat>.size, vertices,\n                     GLenum(GL_DYNAMIC_DRAW))\n        \n        // Read position attribute from |_vertices| with size of 2 and stride of 4\n        // beginning at the start of the array. The last argument indicates offset\n        // of data within |gVertices| as supplied to the vertex buffer.\n        glVertexAttribPointer(position, 2, GLenum(GL_FLOAT), UInt8(GL_FALSE), 4 * Int32(MemoryLayout<GLfloat>.size), nil)\n        glEnableVertexAttribArray(position)\n        \n        // Read texcoord attribute from |_vertices| with size of 2 and stride of 4\n        // beginning at the first texcoord in the array. The last argument indicates\n        // offset of data within |gVertices| as supplied to the vertex buffer.\n        \n        let ptr = UnsafeMutableRawPointer(bitPattern: MemoryLayout<GLfloat>.size * 2)\n        glVertexAttribPointer(texcoord,\n                              2,\n                              GLenum(GL_FLOAT),\n                              UInt8(GL_FALSE),\n                              Int32(4 * MemoryLayout<GLfloat>.size),\n                              ptr)\n        glEnableVertexAttribArray(texcoord)\n    }\n    \n    fileprivate var lastDrawnHeight = UInt32(0)\n    fileprivate var lastDrawnWidth = UInt32(0)\n    \n    fileprivate func updateTextureSizesForFrame(frame: OTVideoFrame) {\n        guard let frameFormat = frame.format, frameFormat.imageHeight != lastDrawnHeight,\n            frameFormat.imageWidth != lastDrawnWidth\n            else {\n                return\n        }\n        \n        let lumaWidth = GLsizei(frameFormat.imageWidth)\n        let lumaHeight = GLsizei(frameFormat.imageHeight)\n        let chromaWidth = GLsizei(frameFormat.imageWidth / 2)\n        let chromaHeight = GLsizei(frameFormat.imageHeight / 2)\n        \n        for i in 0..<EAGLVideoRenderer.kNumTextureSets {\n            glActiveTexture(GLenum(GL_TEXTURE0 + i * 3))\n            glTexImage2D(GLenum(GL_TEXTURE_2D),\n                         0,\n                         GL_LUMINANCE,\n                         lumaWidth,\n                         lumaHeight,\n                         0,\n                         GLenum(GL_LUMINANCE),\n                         GLenum(GL_UNSIGNED_BYTE),\n                         nil)\n            \n            glActiveTexture(GLenum(GL_TEXTURE0 + i * 3 + 1))\n            glTexImage2D(GLenum(GL_TEXTURE_2D),\n                         0,\n                         GL_LUMINANCE,\n                         chromaWidth,\n                         chromaHeight,\n                         0,\n                         GLenum(GL_LUMINANCE),\n                         GLenum(GL_UNSIGNED_BYTE),\n                         nil)\n            \n            glActiveTexture(GLenum(GL_TEXTURE0 + i * 3 + 2))\n            glTexImage2D(GLenum(GL_TEXTURE_2D),\n                         0,\n                         GL_LUMINANCE,\n                         chromaWidth,\n                         chromaHeight,\n                         0,\n                         GLenum(GL_LUMINANCE),\n                         GLenum(GL_UNSIGNED_BYTE),\n                         nil)\n        }\n    }\n    \n    fileprivate var currentTextureSet: GLint = 0\n    fileprivate func updateTextureDataForFrame(frame: OTVideoFrame) {\n        guard let frameFormat = frame.format\n            else {\n                return\n        }\n        let textureOffset = GLint(currentTextureSet * 3)\n        \n        glActiveTexture(GLenum(GL_TEXTURE0 + textureOffset))\n        glUniform1i(ySampler, textureOffset)\n        glTexImage2D(GLenum(GL_TEXTURE_2D),\n                     0,\n                     GL_LUMINANCE,\n                     GLsizei(frameFormat.imageWidth),\n                     GLsizei(frameFormat.imageHeight),\n                     0,\n                     GLenum(GL_LUMINANCE),\n                     GLenum(GL_UNSIGNED_BYTE),\n                     frame.planes?.pointer(at: 0))\n\n        glActiveTexture(GLenum(GL_TEXTURE0 + textureOffset + 1))\n        glUniform1i(uSampler, textureOffset + 1)\n        glTexImage2D(GLenum(GL_TEXTURE_2D),\n                     0,\n                     GL_LUMINANCE,\n                     GLsizei(frameFormat.imageWidth / 2),\n                     GLsizei(frameFormat.imageHeight / 2),\n                     0,\n                     GLenum(GL_LUMINANCE),\n                     GLenum(GL_UNSIGNED_BYTE),\n                     frame.planes?.pointer(at: 1))\n\n        glActiveTexture(GLenum(GL_TEXTURE0 + textureOffset + 2))\n        glUniform1i(vSampler, textureOffset + 2)\n        glTexImage2D(GLenum(GL_TEXTURE_2D),\n                     0,\n                     GL_LUMINANCE,\n                     GLsizei(frameFormat.imageWidth / 2),\n                     GLsizei(frameFormat.imageHeight / 2),\n                     0,\n                     GLenum(GL_LUMINANCE),\n                     GLenum(GL_UNSIGNED_BYTE),\n                     frame.planes?.pointer(at: 2))\n\n        currentTextureSet = (currentTextureSet + 1) % EAGLVideoRenderer.kNumTextureSets\n    }\n}\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoCapture.swift",
    "content": "//\n//  ExampleVideoCapture.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport OpenTok\nimport AVFoundation\n\nextension UIApplication {\n    func currentDeviceOrientation(cameraPosition pos: AVCaptureDevice.Position) -> OTVideoOrientation {\n        let orientation = statusBarOrientation\n        if pos == .front {\n            switch orientation {\n            case .landscapeLeft: return .up\n            case .landscapeRight: return .down\n            case .portrait: return .left\n            case .portraitUpsideDown: return .right\n            case .unknown: return .up\n            @unknown default: fatalError()\n            }\n        } else {\n            switch orientation {\n            case .landscapeLeft: return .down\n            case .landscapeRight: return .up\n            case .portrait: return .left\n            case .portraitUpsideDown: return .right\n            case .unknown: return .up\n            @unknown default: fatalError()\n            }\n        }\n    }\n}\n\nextension AVCaptureSession.Preset {\n    func dimensionForCapturePreset() -> (width: UInt32, height: UInt32) {\n        switch self {\n        case AVCaptureSession.Preset.cif352x288: return (352, 288)\n        case AVCaptureSession.Preset.vga640x480, AVCaptureSession.Preset.high: return (640, 480)\n        case AVCaptureSession.Preset.low: return (192, 144)\n        case AVCaptureSession.Preset.medium: return (480, 360)\n        case AVCaptureSession.Preset.hd1280x720: return (1280, 720)\n        default: return (352, 288)\n        }\n    }\n}\n\nprotocol FrameCapturerMetadataDelegate {\n    func finishPreparingFrame(_ videoFrame: OTVideoFrame?)\n}\n\nclass ExampleVideoCapture: NSObject, OTVideoCapture {\n    var videoContentHint: OTVideoContentHint\n    var captureSession: AVCaptureSession?\n    var videoInput: AVCaptureDeviceInput?\n    var videoOutput: AVCaptureVideoDataOutput?\n    \n    var videoCaptureConsumer: OTVideoCaptureConsumer?\n    \n    var delegate: FrameCapturerMetadataDelegate?\n    \n    var cameraPosition: AVCaptureDevice.Position {\n        get {\n            return videoInput?.device.position ?? .unspecified\n        }\n    }\n    \n    fileprivate var capturePreset: AVCaptureSession.Preset {\n        didSet {\n            (captureWidth, captureHeight) = capturePreset.dimensionForCapturePreset()\n        }\n    }\n    \n    fileprivate var captureWidth: UInt32\n    fileprivate var captureHeight: UInt32\n    fileprivate var capturing = false\n    fileprivate let videoFrame: OTVideoFrame\n    fileprivate var videoFrameOrientation: OTVideoOrientation = .left  //potrait\n    \n    let captureQueue: DispatchQueue\n    \n    fileprivate func updateFrameOrientation() {\n        DispatchQueue.main.async {\n            guard let inputDevice = self.videoInput else {\n                return;\n            }\n            self.videoFrameOrientation = UIApplication.shared.currentDeviceOrientation(cameraPosition: inputDevice.device.position)\n        }\n    }\n    \n    override init() {\n        self.videoContentHint = .none\n        capturePreset = AVCaptureSession.Preset.vga640x480\n        captureQueue = DispatchQueue(label: \"com.tokbox.VideoCapture\", attributes: [])\n        (captureWidth, captureHeight) = capturePreset.dimensionForCapturePreset()\n        videoFrame = OTVideoFrame(format: OTVideoFormat(nv12WithWidth: captureWidth, height: captureHeight))\n    }\n    \n    // MARK: - AVFoundation functions\n    fileprivate func setupAudioVideoSession() throws {\n        captureSession = AVCaptureSession()\n        captureSession?.beginConfiguration()\n\n        captureSession?.sessionPreset = capturePreset\n        captureSession?.usesApplicationAudioSession = false\n\n        // Configure Camera Input\n        guard let device = camera(withPosition: .front)\n            else {\n                print(\"Failed to acquire camera device for video\")\n                return\n        }\n        videoInput = try AVCaptureDeviceInput(device: device)\n        guard let videoInput = self.videoInput else {\n            print(\"There was an error creating videoInput\")\n            return\n        }\n        captureSession?.addInput(videoInput)\n        \n        // Configure Ouput\n        videoOutput = AVCaptureVideoDataOutput()\n        videoOutput?.alwaysDiscardsLateVideoFrames = true\n        videoOutput?.videoSettings = [\n            kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)\n        ]\n        videoOutput?.setSampleBufferDelegate(self, queue: captureQueue)\n        \n        guard let videoOutput = self.videoOutput else {\n            print(\"There was an error creating videoOutput\")\n            return\n        }\n        captureSession?.addOutput(videoOutput)\n        setFrameRate()\n        captureSession?.commitConfiguration()\n        \n        captureSession?.startRunning()\n    }\n    \n    fileprivate func frameRateRange(forFrameRate fps: Int) -> AVFrameRateRange? {\n        return videoInput?.device.activeFormat.videoSupportedFrameRateRanges.filter({ range in\n            return range.minFrameRate <= Double(fps) && Double(fps) <= range.maxFrameRate\n        }).first\n    }\n    \n    fileprivate func setFrameRate(fps: Int = 20) {\n        guard let _ = frameRateRange(forFrameRate: fps)\n            else {\n                print(\"Unsupported frameRate \\(fps)\")\n                return\n        }\n        \n        let desiredMinFps = CMTime(value: 1, timescale: CMTimeScale(fps))\n        let desiredMaxFps = CMTime(value: 1, timescale: CMTimeScale(fps))\n        \n        do {\n            try videoInput?.device.lockForConfiguration()\n            videoInput?.device.activeVideoMinFrameDuration = desiredMinFps\n            videoInput?.device.activeVideoMaxFrameDuration = desiredMaxFps\n        } catch {\n            print(\"Error setting framerate\")\n        }\n        \n    }\n    \n    fileprivate func camera(withPosition pos: AVCaptureDevice.Position) -> AVCaptureDevice? {\n        guard #available(iOS 10, *) else { return nil }\n        return AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: pos).devices.first\n    }\n    \n    fileprivate func updateCaptureFormat(width w: UInt32, height h: UInt32) {\n        captureWidth = w\n        captureHeight = h\n        videoFrame.format = OTVideoFormat.init(nv12WithWidth: w, height: h)\n    }\n\n    // MARK: - OTVideoCapture protocol\n    func initCapture() {\n        NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,\n                                               object: nil,\n                                               queue: .main,\n                                               using: { (_) in self.updateFrameOrientation() })\n        captureQueue.async {\n            do {\n                try self.setupAudioVideoSession()\n            } catch let error as NSError {\n                print(\"Error configuring AV Session: \\(error)\")\n            }\n        }\n    }\n    \n    func start() -> Int32 {\n        self.updateFrameOrientation()\n        self.capturing = true\n        return 0\n    }\n    \n    func stop() -> Int32 {\n        capturing = false\n        return 0\n    }\n    \n    func releaseCapture() {\n        let _ = stop()\n        videoOutput?.setSampleBufferDelegate(nil, queue: captureQueue)\n        captureQueue.sync {\n            self.captureSession?.stopRunning()\n        }\n        captureSession = nil\n        videoOutput = nil\n        videoInput = nil\n        \n        NotificationCenter.default.removeObserver(self,\n                                                  name: UIDevice.orientationDidChangeNotification,\n                                                  object: nil)\n    }\n    \n    func isCaptureStarted() -> Bool {\n        return capturing && (captureSession != nil)\n    }\n    \n    func captureSettings(_ videoFormat: OTVideoFormat) -> Int32 {\n        videoFormat.pixelFormat = .NV12\n        videoFormat.imageWidth = captureWidth\n        videoFormat.imageHeight = captureHeight\n        return 0\n    }\n    \n    fileprivate func frontFacingCamera() -> AVCaptureDevice? {\n        return camera(withPosition: .front)\n    }\n    \n    fileprivate func backFacingCamera() -> AVCaptureDevice? {\n        return camera(withPosition: .back)\n    }\n    \n    fileprivate var hasMultipleCameras: Bool {\n        guard #available(iOS 10, *) else { return false }\n        return AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .unspecified).devices.count > 1\n    }\n    \n    func setCameraPosition(_ position: AVCaptureDevice.Position) -> Bool {\n        guard let preset = captureSession?.sessionPreset else {\n            return false\n        }\n        \n        let newVideoInput: AVCaptureDeviceInput? = {\n            do {\n                if position == AVCaptureDevice.Position.back {\n                    guard let backFacingCamera = backFacingCamera() else { return nil }\n                    return try AVCaptureDeviceInput.init(device: backFacingCamera)\n                } else if position == AVCaptureDevice.Position.front {\n                    guard let frontFacingCamera = frontFacingCamera() else { return nil }\n                    return try AVCaptureDeviceInput.init(device: frontFacingCamera)\n                } else {\n                    return nil\n                }\n            } catch {\n                return nil\n            }\n        }()\n        \n        guard let newInput = newVideoInput else {\n            return false\n        }\n        \n        var success = true\n        \n        captureQueue.sync {\n            captureSession?.beginConfiguration()\n            guard let videoInput = self.videoInput else { return }\n            captureSession?.removeInput(videoInput)\n            \n            if captureSession?.canAddInput(newInput) ?? false {\n                captureSession?.addInput(newInput)\n                self.videoInput = newInput\n            } else {\n                success = false\n                captureSession?.addInput(videoInput)\n            }\n            \n            captureSession?.commitConfiguration()\n        }\n        \n        if success {\n            capturePreset = preset\n        }\n        \n        return success\n    }\n    \n    func toggleCameraPosition() -> Bool {\n        guard hasMultipleCameras else {\n            return false\n        }\n        \n        if  videoInput?.device.position == .front {\n            return setCameraPosition(.back)\n        } else {\n            return setCameraPosition(.front)\n        }\n    }\n}\n\nextension ExampleVideoCapture: AVCaptureVideoDataOutputSampleBufferDelegate {\n    func captureOutput(_ captureOutput: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {\n        print(\"Dropping frame\")\n    }\n    \n    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)\n    {\n        guard capturing,\n              let videoCaptureConsumer = videoCaptureConsumer,\n              let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)\n            else {\n                print(\"Error acquiring sample buffer\")\n                return\n        }\n        \n        let time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)\n        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))\n        \n        videoCaptureConsumer.consumeImageBuffer(imageBuffer, orientation: videoFrameOrientation, timestamp: time, metadata: videoFrame.metadata)\n        \n        CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))\n    }\n}\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoRender.swift",
    "content": "//\n//  ExampleVideoRender.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport OpenTok\nimport GLKit\n\nprotocol ExampleVideoRenderDelegate {\n    func renderer(_ renderer: ExampleVideoRender, didReceiveFrame videoFrame: OTVideoFrame)\n}\n\nclass ExampleVideoRender: UIView {\n    \n    var delegate: ExampleVideoRenderDelegate?\n    var mirroring: Bool = true {\n        didSet {\n            if let renderer = renderer {\n                renderer.mirroring = mirroring\n            }\n        }\n    }\n    \n    fileprivate var glContext: EAGLContext?\n    fileprivate var renderer: EAGLVideoRenderer?\n    fileprivate var glkView: GLKView?\n    fileprivate var frameLock: NSLock?\n    fileprivate var renderingEnabled: Bool = true\n    fileprivate var lastVideoFrame: OTVideoFrame?\n    fileprivate var displayLinkProxy: DisplayLinkProxy?\n    fileprivate var displayLink: CADisplayLink?\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        glContext = EAGLContext(api:.openGLES2)\n        renderer = EAGLVideoRenderer(context: glContext!)\n       \n        glkView = GLKView(frame: CGRect.zero, context: glContext!)\n        glkView?.drawableColorFormat = .RGBA8888\n        glkView?.drawableDepthFormat = .formatNone\n        glkView?.drawableStencilFormat = .formatNone\n        glkView?.drawableMultisample = .multisampleNone\n        glkView?.delegate = self;\n        glkView?.layer.masksToBounds = true;\n        addSubview(glkView!)\n        \n        frameLock = NSLock()\n        \n        NotificationCenter.default\n            .addObserver(self, selector: #selector(ExampleVideoRender.willResignActive),\n                         name: UIApplication.willResignActiveNotification, object: nil)\n        NotificationCenter.default\n            .addObserver(self, selector: #selector(ExampleVideoRender.didBecomeActive),\n                         name: UIApplication.didBecomeActiveNotification, object: nil)\n        \n        \n        displayLinkProxy = DisplayLinkProxy(glkView: glkView!, videoRender: self)\n        displayLink = CADisplayLink(target: displayLinkProxy!, selector:#selector(DisplayLinkProxy.displayLinkDidFire(_:)))\n        \n        if #available(iOS 10, *) {\n            displayLink!.preferredFramesPerSecond = 30\n        }\n        \n        displayLink!.add(to: RunLoop.main, forMode: RunLoop.Mode.common)\n        \n        renderer!.mirroring = mirroring\n        renderer!.setupGL()\n        \n        displayLink!.isPaused = false\n    }\n    \n    @objc func willResignActive() {\n        displayLink!.isPaused = true\n        glkView?.deleteDrawable()\n        renderer!.teardownGL()\n    }\n    \n    @objc func didBecomeActive() {\n        renderer!.setupGL()\n        displayLink!.isPaused = false\n    }\n    \n    var needsRendererUpdate: Bool {\n        get {\n            guard lastVideoFrame != nil else {\n                return false\n            }\n            return renderer?.lastFrameTime != lastVideoFrame?.timestamp.value\n        }\n    }\n        \n    required init?(coder aDecoder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    override func layoutSubviews() {\n        super.layoutSubviews()\n        glkView?.frame = bounds\n    }\n    \n    fileprivate func calculatePlaneSize(forFrame frame: OTVideoFrame)\n        -> (ySize: Int, uSize: Int, vSize: Int)\n    {\n        guard let frameFormat = frame.format\n            else {\n                return (0, 0 ,0)\n        }\n        let baseSize = Int(frameFormat.imageWidth * frameFormat.imageHeight) * MemoryLayout<GLubyte>.size\n        return (baseSize, baseSize / 4, baseSize / 4)\n    }\n}\n\nextension ExampleVideoRender: GLKViewDelegate {\n    \n    func glkView(_ view: GLKView, drawIn rect: CGRect) {\n        defer {\n            frameLock?.unlock()\n        }\n        frameLock?.lock()\n        //Coming from bg you will double render and deallocate will crash below. Hence check for lastVideoFrameRendered == false\n        guard let lastVideoFrame = lastVideoFrame\n            else {\n                return\n        }\n        \n        renderer?.drawFrame(frame: lastVideoFrame, withViewport: view.frame)\n        deallocateFrame(lastVideoFrame)\n        self.lastVideoFrame = nil\n    }\n    \n    func deallocateFrame(_ frame: OTVideoFrame?) -> Void {\n        guard let frame = frame else {\n            return\n        }\n        \n        let yPlane: UnsafeMutablePointer<GLubyte>? = frame.planes?.pointer(at: 0)?.assumingMemoryBound(to: GLubyte.self)\n        let uPlane: UnsafeMutablePointer<GLubyte>? = frame.planes?.pointer(at: 1)?.assumingMemoryBound(to: GLubyte.self)\n        let vPlane: UnsafeMutablePointer<GLubyte>? = frame.planes?.pointer(at: 2)?.assumingMemoryBound(to: GLubyte.self)\n        \n        yPlane?.deallocate()\n        uPlane?.deallocate()\n        vPlane?.deallocate()\n\n    }\n    \n}\n\nextension ExampleVideoRender: OTVideoRender {\n    func renderVideoFrame(_ frame: OTVideoFrame) {\n        if let fLock = frameLock, let format = frame.format {\n            fLock.lock()\n            assert(format.pixelFormat == .I420)\n\n            deallocateFrame(lastVideoFrame)\n            \n            lastVideoFrame = OTVideoFrame(format: format)\n            lastVideoFrame?.timestamp = frame.timestamp\n            \n            let planeSize = calculatePlaneSize(forFrame: frame)\n            let yPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.ySize)\n            let uPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.uSize)\n            let vPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.vSize)\n            \n            memcpy(yPlane, frame.planes?.pointer(at: 0), planeSize.ySize)\n            memcpy(uPlane, frame.planes?.pointer(at: 1), planeSize.uSize)\n            memcpy(vPlane, frame.planes?.pointer(at: 2), planeSize.vSize)\n            \n            lastVideoFrame?.planes?.addPointer(yPlane)\n            lastVideoFrame?.planes?.addPointer(uPlane)\n            lastVideoFrame?.planes?.addPointer(vPlane)\n    \n            fLock.unlock()\n            \n            if let delegate = delegate {\n                delegate.renderer(self, didReceiveFrame: frame)\n            }\n        }\n    }\n}\n\n\nclass DisplayLinkProxy {\n    var renderer: ExampleVideoRender\n    var view: GLKView\n    \n    init(glkView: GLKView, videoRender: ExampleVideoRender) {\n        renderer = videoRender\n        view = glkView\n    }\n    \n    @objc func displayLinkDidFire(_ displayLink: CADisplayLink) {\n        if renderer.needsRendererUpdate {\n            view.setNeedsDisplay()\n        }\n    }\n}\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Custom-Video-Driver/Lets-Build-OTPublisher/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\nlet kWidgetRatio: CGFloat = 1.333\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    \n    var subscriber: OTSubscriber?\n    \n    let captureSession = AVCaptureSession()\n    \n    let captureQueue = DispatchQueue(label: \"com.tokbox.VideoCapture\", attributes: [])\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError? = nil\n        defer {\n            processError(error)\n        }\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        \n        publisher = OTPublisher(delegate: self, settings: settings)\n        if let pub = publisher {\n            let videoRender = ExampleVideoRender()\n            pub.videoCapture = ExampleVideoCapture()\n            pub.videoRender = videoRender\n            session.publish(pub, error: &error)\n            \n            videoRender.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.width / kWidgetRatio)\n            view.addSubview(videoRender)\n        }\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            showAlert(errorStr: err.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n    \n    \n    @IBAction func toggleCamera(_ sender: Any) {\n        if let capturer = publisher?.videoCapture as? ExampleVideoCapture, let renderer = publisher?.videoRender as? ExampleVideoRender {\n            let _ = capturer.toggleCameraPosition()\n            renderer.mirroring = (capturer.cameraPosition == AVCaptureDevice.Position.front) ? true : false\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        subscriber?.view?.frame = CGRect(x: 0, y: view.frame.width / kWidgetRatio, width: view.frame.width, height: view.frame.width / kWidgetRatio)\n        if let subsView = subscriber?.view {\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\n"
  },
  {
    "path": "Custom-Video-Driver/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Custom-Video-Driver' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Custom-Video-Driver/README.md",
    "content": "Custom Video Driver Sample App\n==================================\n\nThis project uses the custom video driver features in the OpenTok iOS SDK.\nBy the end of a code review, you should have a basic understanding of the\ninternals of the video capture and render API, as well as how to start\nbuilding your own extensions to the core OTPublisherKit and OTSubscriberKit\nclasses.\n\nNote that this sample application is not supported in the XCode iOS Simulator\nbecause the custom video capturer needs to acquire video from an iOS device\ncamera.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\n### ExampleVideoRender\n\nBoth OTSubscriber and OTPublisher need an instance supporting the\n`OTVideoRender` protocol to display video contents. In short, the instance\nID that is set to the `videoRender` property will receive YUV frames (I420) as\nthey are captured (publisher) or as they are received (subscriber). Note that,\nalthough the publisher's `OTVideoCapture` interface can process multiple pixel\nformats, the images passed through the rendering callback will always be in the\nI420 YUV format.\n\nExampleVideoRender is a simplified swift version of the default video renderer\nfor the OpenTok iOS SDK. It is borrowed and modified from a series of classes in\nGoogle's [WebRTC][1] project.\n\nIn this example we wire a video renderer to the publisher's rendering\ncallback. An alternative approach for developers using video from the camera\nwith AVFoundation is to wire [AVCaptureVideoPreviewLayer][2] directly to the\ncapture class and leave the `OTPublisherKit.videoRender` property nil.\n\nTo see ExampleVideoRender in action, put a breakpoint on `renderVideoFrame:`.\nYou will see this method called for every video frame that is presented to the\nrendering endpoint by the OpenTok iOS SDK.\n\n### ExampleVideoCapture\n\nThis class interfaces with AVFoundation to provide video capture support from\nthe device's camera hardware. By implementing the OTVideoCapture interface, it\ncan be used as a video capture endpoint OTPublisher to provide video for\npublishing.\n\nTo see ExampleVideoCapture in action, put a breakpoint on\n`captureOutput:didOutputSampleBuffer:fromConnection:`. This method is invoked by\nAVFoundation for every frame that is output from the camera capture session.\nAfter some processing, the video capture invokes its own\n`OTVideoCaptureConsumer` with the captured frame. Note the consumer is set by\nthe OpenTok iOS SDK during instantiation of the publisher.\n\n\nPutting it all together\n-----------------------\n\nThe [ViewController](Lets-Build-OTPublisher/ViewController.m) for this\napplication is a near-identical clone of the previous, with text substitutions\nfor our newly-minted example publisher and subscriber classes. Notice how a\nmajority of the calls made into the OpenTok iOS SDK classes are declared\non the core classes, OTPublisherKit and OTSubscriberKit. Extending those core\nclasses as is done in this example is as simple as defining a few simple\ninterfaces and plugging everything in at runtime. We hope that this new\nclass hierarchy will give you some ideas for how to extend the core\nfunctionality of the OpenTok iOS SDK to meet your application needs.\n\n\n[1]: https://chromium.googlesource.com/external/webrtc/+/master/talk/app/webrtc/objc/\n[2]: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureVideoPreviewLayer_Class/Reference/Reference.html\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n}\n\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"6211\" systemVersion=\"14A298i\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6204\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n// Replace with your encryption secret\nlet kEncryptionSecret = \"\"\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    lazy var publisher: OTPublisher = {\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        return OTPublisher(delegate: self, settings: settings)!\n    }()\n    \n    var subscriber: OTSubscriber?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        setEncryptionSecret()\n        doConnect()\n    }\n    \n    /**\n     * Encryption secret must be set before publishing/subscribing.\n     */\n    fileprivate func setEncryptionSecret() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.setEncryptionSecret(kEncryptionSecret, error: &error)\n    }\n    \n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.publish(publisher, error: &error)\n        \n        if let pubView = publisher.view {\n            pubView.frame = CGRect(x: 0, y: 0, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(pubView)\n        }\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        \n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func cleanupPublisher() {\n        publisher.view?.removeFromSuperview()\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            DispatchQueue.main.async {\n                let controller = UIAlertController(title: \"Error\", message: err.localizedDescription, preferredStyle: .alert)\n                controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n                self.present(controller, animated: true, completion: nil)\n            }\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        cleanupPublisher()\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        if let subsView = subscriber?.view {\n            subsView.frame = CGRect(x: 0, y: kWidgetHeight, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n}\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t8CE5ECA82768CF272D93D550 /* Pods_Basic_Video_Chat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292117CDD5541CC8EDB8DFEF /* Pods_Basic_Video_Chat.framework */; };\n\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375CF1EB1633400645696 /* AppDelegate.swift */; };\n\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05375D01EB1633400645696 /* Assets.xcassets */; };\n\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D11EB1633400645696 /* LaunchScreen.storyboard */; };\n\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D31EB1633400645696 /* Main.storyboard */; };\n\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375D61EB1633400645696 /* ViewController.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t292117CDD5541CC8EDB8DFEF /* Pods_Basic_Video_Chat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Basic_Video_Chat.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t57CEF65B7B7E03022F938D38 /* Pods-Basic-Video-Chat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Basic-Video-Chat.release.xcconfig\"; path = \"Target Support Files/Pods-Basic-Video-Chat/Pods-Basic-Video-Chat.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05375D01EB1633400645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05375D21EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D41EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D51EB1633400645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05375D61EB1633400645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tC3768C616191C2590039011A /* Pods-Basic-Video-Chat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Basic-Video-Chat.debug.xcconfig\"; path = \"Target Support Files/Pods-Basic-Video-Chat/Pods-Basic-Video-Chat.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tF86C649A1D5C7C630081846D /* Basic-Video-Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Basic-Video-Chat.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64971D5C7C630081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8CE5ECA82768CF272D93D550 /* Pods_Basic_Video_Chat.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t9B91B601FD7FCD4544752C8F /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC3768C616191C2590039011A /* Pods-Basic-Video-Chat.debug.xcconfig */,\n\t\t\t\t57CEF65B7B7E03022F938D38 /* Pods-Basic-Video-Chat.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375CE1EB1633400645696 /* Basic-Video-Chat */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */,\n\t\t\t\tA05375D01EB1633400645696 /* Assets.xcassets */,\n\t\t\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05375D31EB1633400645696 /* Main.storyboard */,\n\t\t\t\tA05375D51EB1633400645696 /* Info.plist */,\n\t\t\t\tA05375D61EB1633400645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Basic-Video-Chat\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE350D1C8D33042DC5538D354 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t292117CDD5541CC8EDB8DFEF /* Pods_Basic_Video_Chat.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64911D5C7C630081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375CE1EB1633400645696 /* Basic-Video-Chat */,\n\t\t\t\tF86C649B1D5C7C630081846D /* Products */,\n\t\t\t\t9B91B601FD7FCD4544752C8F /* Pods */,\n\t\t\t\tE350D1C8D33042DC5538D354 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C649B1D5C7C630081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C649A1D5C7C630081846D /* Basic-Video-Chat.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64991D5C7C630081846D /* Basic-Video-Chat */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Basic-Video-Chat\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC161AC7963B4CE2E0ED2AC58 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tF86C64961D5C7C630081846D /* Sources */,\n\t\t\t\tF86C64971D5C7C630081846D /* Frameworks */,\n\t\t\t\tF86C64981D5C7C630081846D /* Resources */,\n\t\t\t\t3EF759C7D0E620322B2686EF /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Basic-Video-Chat\";\n\t\t\tproductName = \"Hello-World\";\n\t\t\tproductReference = F86C649A1D5C7C630081846D /* Basic-Video-Chat.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64921D5C7C630081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64991D5C7C630081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Basic-Video-Chat\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64911D5C7C630081846D;\n\t\t\tproductRefGroup = F86C649B1D5C7C630081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64991D5C7C630081846D /* Basic-Video-Chat */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64981D5C7C630081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */,\n\t\t\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3EF759C7D0E620322B2686EF /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Basic-Video-Chat/Pods-Basic-Video-Chat-resources.sh\",\n\t\t\t\t\"${PODS_ROOT}/OTXCFramework/OpenTok.xcframework/ios-arm64/OpenTok.framework/selfie_segmentation.tflite\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/selfie_segmentation.tflite\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Basic-Video-Chat/Pods-Basic-Video-Chat-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC161AC7963B4CE2E0ED2AC58 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Basic-Video-Chat-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64961D5C7C630081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */,\n\t\t\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D21EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375D31EB1633400645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D41EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64AA1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AB1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64AD1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = C3768C616191C2590039011A /* Pods-Basic-Video-Chat.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Basic-Video-Chat/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AE1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 57CEF65B7B7E03022F938D38 /* Pods-Basic-Video-Chat.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Basic-Video-Chat/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Basic-Video-Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AA1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AB1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Basic-Video-Chat\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AD1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AE1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64921D5C7C630081846D /* Project object */;\n}\n"
  },
  {
    "path": "E2EE-Video-Chat/Basic-Video-Chat.xcodeproj/xcshareddata/xcschemes/Basic-Video-Chat.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1170\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n               BuildableName = \"Basic-Video-Chat.app\"\n               BlueprintName = \"Basic-Video-Chat\"\n               ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Basic-Video-Chat.app\"\n            BlueprintName = \"Basic-Video-Chat\"\n            ReferencedContainer = \"container:Basic-Video-Chat.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "E2EE-Video-Chat/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Basic-Video-Chat' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "E2EE-Video-Chat/README.md",
    "content": "E2EE Basic Video Chat Sample App\n===============================\n\nThe E2EE Basic-Video-Chat app is a very simple application meant to get a new developer\nstarted using the OpenTok iOS SDK and end to end encryption.\n\nQuick Start\n-----------\n\nTo use this application:\n\n1. Follow the instructions in the [Quick Start](../README.md#quick-start)\n   section of the main README file for this repository.\n\n   Among other things, you need to set values for the `kApiKey`, `kSessionId`,\n   `kToken`, and `kEncryptionSecret` constants. See [Obtaining OpenTok\n   Credentials](../README.md#obtaining-opentok-credentials)\n   in the main README file for the repository.\n\n2. To create an E2EE connection you must first enable this functionality server side.\n   You enable end-to-end encryption when you create a session using the REST API. \n   Set the e2ee property to true. See the [E2EE](https://tokbox.com/developer/guides/end-to-end-encryption/#server_side) guide.\n\n3. When you run the application, it connects to an OpenTok session and\n   publishes an audio-video stream from your device to the session.\n\n4. Run the app on a second client. You can do this by deploying the app to an\n   iOS device and testing it in the simulator at the same time. Or you can use\n   the browser_demo.html file to connect in a browser (see the following\n   section).\n\n   When the second client connects, it also publishes a stream to the session,\n   and both clients subscribe to (view) each other’s stream.\n\nApplication Notes\n-----------------\n\n*   Follow the code from the `ViewController.viewDidLoad(_:)` method through\n    to the OpenTok callbacks to see how streams are created and handled in\n    the OpenTok iOS SDK.\n\n*   By default, all delegate methods from classes in the OpenTok iOS SDK are\n    invoked on the main queue. This means that you can directly modify the view\n    hierarchy from inside the callback, without any asynchronous callouts.\n\n*   When the main view loads, the ViewController calls the `OTSession.setEncryptionSecret(_:, error:)`\n    method to set the encryption secret. Then the \n    `OTSession.initWithApiKey(_:, sessionId:,delegate:)` method to initialize\n    a Session object. The app then calls the\n    `OTSession.connectWithToken(_:, error:)` to connect to the session. The\n    `OTSessionDelegate.sessionDidConnect(_:)` message is sent when the app\n    connects to the OpenTok session.\n\n*   The `doPublish()` method of the app initializes a publisher and passes it\n    into the `OTSession.publish(_:,error:)` method. This publishes an\n    audio-video stream to the session.\n\n*   The `OTSessionDelegate.session(_:,streamCreated:)` message is sent when\n    a new stream is created in the session. In response, the\n    method calls `OTSubscriber(stream:,delegate:)`,\n    passing in the OTStream object. This causes the app to subscribe to the\n    stream.\n\n\nConfiguration Notes\n-------------------\n\n*   You can test in the iOS Simulator or on a supported iOS device. However, the\n    XCode iOS Simulator does not provide access to the camera. When running in\n    the iOS Simulator, an OTPublisher object uses a demo video instead of the\n    camera.\n\n[1]: https://tokbox.com/account/#/\n[2]: https://tokbox.com/developer/sdks/server/\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n\n\n}\n\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "FrameMetadata/FrameMetadata/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14109\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14088\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"FrameMetadata\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zee-CQ-GLa\">\n                                <rect key=\"frame\" x=\"126\" y=\"617\" width=\"123\" height=\"30\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"30\" id=\"pFD-ov-Knc\"/>\n                                </constraints>\n                                <state key=\"normal\" title=\"Toggle Camera\">\n                                    <color key=\"titleColor\" red=\"0.0\" green=\"0.47843137250000001\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"toggleCamera:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"84i-Wg-qRC\"/>\n                                </connections>\n                            </button>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Label\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zyw-HR-ACL\">\n                                <rect key=\"frame\" x=\"8\" y=\"28\" width=\"42\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"Zyw-HR-ACL\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" constant=\"8\" id=\"7uv-rE-Ovs\"/>\n                            <constraint firstItem=\"zee-CQ-GLa\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"AuW-yJ-KJF\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"zee-CQ-GLa\" secondAttribute=\"bottom\" constant=\"20\" id=\"g4N-TL-UpI\"/>\n                            <constraint firstItem=\"Zyw-HR-ACL\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" constant=\"8\" id=\"vaA-dK-W8Z\"/>\n                            <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Zyw-HR-ACL\" secondAttribute=\"trailing\" constant=\"8\" id=\"vgN-fQ-Fw8\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"metadataLabel\" destination=\"Zyw-HR-ACL\" id=\"CbD-kA-r53\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"32.799999999999997\" y=\"36.431784107946029\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>FrameMetadata</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Lets-Build-OTPublisher\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\nlet kWidgetRatio: CGFloat = 1.333\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    lazy var dateFormatter: DateFormatter = {\n        let theDataFormatter = DateFormatter()\n        theDataFormatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ssZZZZZ\"\n        return theDataFormatter\n    }()\n    \n    var publisher: OTPublisher?\n    \n    var subscriber: OTSubscriber?\n    \n    let captureSession = AVCaptureSession()\n    \n    @IBOutlet weak var metadataLabel: UILabel!\n    \n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError? = nil\n        defer {\n            processError(error)\n        }\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        \n        publisher = OTPublisher(delegate: self, settings: settings)\n        if let pub = publisher {\n            let videoRender = ExampleVideoRender()\n            videoRender.delegate = self\n            let     videoCapture = ExampleVideoCapture()\n            videoCapture.delegate = self\n            pub.videoCapture = videoCapture\n            pub.videoRender = videoRender\n            session.publish(pub, error: &error)\n            \n            videoRender.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.width / kWidgetRatio)\n            view.insertSubview(videoRender, at: 0)\n        }\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            showAlert(errorStr: err.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n    \n    \n    @IBAction func toggleCamera(_ sender: Any) {\n        if let capturer = publisher?.videoCapture as? ExampleVideoCapture {\n            let _ = capturer.toggleCameraPosition()\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        subscriber?.view?.frame = CGRect(x: 0, y: view.frame.width / kWidgetRatio, width: view.frame.width, height: view.frame.width / kWidgetRatio)\n        if let subsView = subscriber?.view {\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\nextension ViewController: ExampleVideoRenderDelegate {\n    func renderer(_ renderer: ExampleVideoRender, didReceiveFrame videoFrame: OTVideoFrame) {\n        guard let metadata = videoFrame.metadata, let timestamp = String(data: metadata, encoding: .utf8) else {\n            print(\"Receiving video frame without metadata attached\")\n            return\n        }\n        \n        DispatchQueue.main.async {\n            self.metadataLabel.text = timestamp\n            print(\"Receiving video frame metadata\", timestamp)\n        }\n    }\n}\n\n/*\n * This piece is optional: we demonstrate how to attach a metadata to a video frame before transmitting to the OpenTok platform.\n * You don't have to attach a metadata to make the transmission work\n */\nextension ViewController: FrameCapturerMetadataDelegate {\n    func finishPreparingFrame(_ videoFrame: OTVideoFrame?) {\n        guard let videoFrame = videoFrame else {\n            return\n        }\n        setTimestampToVideoFrame(videoFrame)\n    }\n    \n    fileprivate func setTimestampToVideoFrame(_ videoFrame: OTVideoFrame?) {\n        guard let videoFrame = videoFrame else {\n            return\n        }\n        \n        let timestamp = self.dateFormatter.string(from: Date())\n\n        let metadata = Data(timestamp.utf8)\n        var error: OTError?\n        videoFrame.setMetadata(metadata, error: &error)\n        if let error = error {\n            print(error)\n        }\n    }\n}\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA07BCDBC2089048F00A1B684 /* EAGLVideoRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07BCDB92089048F00A1B684 /* EAGLVideoRenderer.swift */; };\n\t\tA07BCDBD2089048F00A1B684 /* ExampleVideoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07BCDBA2089048F00A1B684 /* ExampleVideoCapture.swift */; };\n\t\tA07BCDBE2089048F00A1B684 /* ExampleVideoRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07BCDBB2089048F00A1B684 /* ExampleVideoRender.swift */; };\n\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BB1D5C8A150081846D /* AppDelegate.swift */; };\n\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BD1D5C8A150081846D /* ViewController.swift */; };\n\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64BF1D5C8A150081846D /* Main.storyboard */; };\n\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C21D5C8A150081846D /* Assets.xcassets */; };\n\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C41D5C8A150081846D /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA07BCDB92089048F00A1B684 /* EAGLVideoRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EAGLVideoRenderer.swift; path = \"../../Custom-Video-Driver/Lets-Build-OTPublisher/EAGLVideoRenderer.swift\"; sourceTree = \"<group>\"; };\n\t\tA07BCDBA2089048F00A1B684 /* ExampleVideoCapture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExampleVideoCapture.swift; path = \"../../Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoCapture.swift\"; sourceTree = \"<group>\"; };\n\t\tA07BCDBB2089048F00A1B684 /* ExampleVideoRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExampleVideoRender.swift; path = \"../../Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoRender.swift\"; sourceTree = \"<group>\"; };\n\t\tF86C64B81D5C8A150081846D /* FrameMetadata.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FrameMetadata.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF86C64C01D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tF86C64C51D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C71D5C8A150081846D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64B51D5C8A150081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tF86C64AF1D5C8A150081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64BA1D5C8A150081846D /* FrameMetadata */,\n\t\t\t\tF86C64B91D5C8A150081846D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64B91D5C8A150081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64B81D5C8A150081846D /* FrameMetadata.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64BA1D5C8A150081846D /* FrameMetadata */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA07BCDB92089048F00A1B684 /* EAGLVideoRenderer.swift */,\n\t\t\t\tA07BCDBA2089048F00A1B684 /* ExampleVideoCapture.swift */,\n\t\t\t\tA07BCDBB2089048F00A1B684 /* ExampleVideoRender.swift */,\n\t\t\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */,\n\t\t\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */,\n\t\t\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */,\n\t\t\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */,\n\t\t\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */,\n\t\t\t\tF86C64C71D5C8A150081846D /* Info.plist */,\n\t\t\t);\n\t\t\tpath = FrameMetadata;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64B71D5C8A150081846D /* FrameMetadata */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"FrameMetadata\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF86C64B41D5C8A150081846D /* Sources */,\n\t\t\t\tF86C64B51D5C8A150081846D /* Frameworks */,\n\t\t\t\tF86C64B61D5C8A150081846D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = FrameMetadata;\n\t\t\tproductName = \"Lets-Build-OTPublisher\";\n\t\t\tproductReference = F86C64B81D5C8A150081846D /* FrameMetadata.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64B01D5C8A150081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64B71D5C8A150081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = MGD69Q275W;\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"FrameMetadata\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64AF1D5C8A150081846D;\n\t\t\tproductRefGroup = F86C64B91D5C8A150081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64B71D5C8A150081846D /* FrameMetadata */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64B61D5C8A150081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */,\n\t\t\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64B41D5C8A150081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA07BCDBC2089048F00A1B684 /* EAGLVideoRenderer.swift in Sources */,\n\t\t\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */,\n\t\t\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */,\n\t\t\t\tA07BCDBD2089048F00A1B684 /* ExampleVideoCapture.swift in Sources */,\n\t\t\t\tA07BCDBE2089048F00A1B684 /* ExampleVideoRender.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C01D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C51D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64C81D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64C91D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64CB1D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = MGD69Q275W;\n\t\t\t\t\"GCC_PREPROCESSOR_DEFINITIONS[arch=*]\" = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"COCOAPODS=1\",\n\t\t\t\t\t\"GLES_SILENCE_DEPRECATION=1\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = FrameMetadata/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.FrameMetadata;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64CC1D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = MGD69Q275W;\n\t\t\t\tINFOPLIST_FILE = FrameMetadata/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.tokbox.FrameMetadata;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"FrameMetadata\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64C81D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64C91D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"FrameMetadata\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64CB1D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64CC1D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64B01D5C8A150081846D /* Project object */;\n}\n"
  },
  {
    "path": "FrameMetadata/FrameMetadata.xcodeproj/xcshareddata/xcschemes/FrameMetadata.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n               BuildableName = \"FrameMetadata.app\"\n               BlueprintName = \"FrameMetadata\"\n               ReferencedContainer = \"container:FrameMetadata.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"FrameMetadata.app\"\n            BlueprintName = \"FrameMetadata\"\n            ReferencedContainer = \"container:FrameMetadata.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"FrameMetadata.app\"\n            BlueprintName = \"FrameMetadata\"\n            ReferencedContainer = \"container:FrameMetadata.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"FrameMetadata.app\"\n            BlueprintName = \"FrameMetadata\"\n            ReferencedContainer = \"container:FrameMetadata.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "FrameMetadata/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'FrameMetadata' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "FrameMetadata/README.md",
    "content": "Frame Metadata\n==================================\n\nThis project shows how to set metadata (limited to 32 bytes) to a video frame, as well as how to read metadata from a video frame. It basically extends project 2, \"Let's build OTPublisher.\" By the end of a code review, you should learn how to set and get your desired metedata from a video frame of publisher and subscriber.\n\nNote that this sample application is not supported in the XCode iOS Simulator\nbecause the custom video capturer needs to acquire video from an iOS device\ncamera.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nTBExampleVideoRender and TBExampleVideoCapture\n------------------------------------------\n\nIn this example we will include our implementations of OTVideoRender and OTVideoCapture that will allow us to capture and render video by ourselves.\n\nThe purpose of including a custom renderer and capturer is to access the underlying video frame (`OTVideoFrame`) which is not directly visible at `OTPublisher` or `OTSubscriber` class. Once each farme is ready to transmit to the OpenTok platform, we can now attach metadata by invoking the `[setMetadata:error:]` method. In the sample app, we show how to attach an ISO standard timestamp to a video frame:\n```\nfunc finishPreparingFrame(_ videoFrame: OTVideoFrame?) {\n    guard let videoFrame = videoFrame else {\n        return\n    }\n    setTimestampToVideoFrame(videoFrame)\n}\n\nfileprivate func setTimestampToVideoFrame(_ videoFrame: OTVideoFrame?) {\n    guard let videoFrame = videoFrame else {\n        return\n    }\n    \n    let timestamp = self.dateFormatter.string(from: Date())\n\n    let metdata = Data(timestamp.utf8)\n    var error: OTError?\n    videoFrame.setMetadata(metdata, error: &error)\n    if let error = error {\n        print(error)\n    }\n}\n```\nBy conforming the `FrameCapturerMetadataDelegate` protocol and implementing the `[finishPreparingFrame:]` method, you will receive a ready video frame to attach your metadata.\n\nTo read the data, the approarch is similar. We simply need to access the underlying video frame and read the `metadata` property.\n```\nfunc renderer(_ renderer: ExampleVideoRender, didReceiveFrame videoFrame: OTVideoFrame) {\n    guard let metadata = videoFrame.metadata, let timestampe = String(data: metadata, encoding: .utf8) else {\n        print(\"Receiving video frame without metadata attached\")\n        return\n    }\n    \n    DispatchQueue.main.async {\n        self.metadataLabel.text = timestampe\n        print(\"Receiving video frame metadata\", timestampe)\n    }\n}\n```\nIn the sample app, we conform `ExampleVideoRenderDelegate` and implement `[renderer:didReceiveFrame:]` method to pass back each video frame.\n\n*Note: you can always directly access a video frame from a custom captuere or renderer. We follow the classic delegate design pattern to enforce better abstraction and reusability.*\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-2016 TokBox, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Live-Photo-Capture\n//\n//  Created by Roberto Perez Cubero on 23/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_  application: UIApplication) {\n    }\n}\n\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15G31\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"Live_Photo_Capture\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/ExamplePhotoVideoCapture.swift",
    "content": "//\n//  ExamplePhotoVideoCapture.swift\n//  Live-Photo-Capture\n//\n//  Created by Roberto Perez Cubero on 23/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport AVFoundation\n\nclass ExamplePhotoVideoCapture: ExampleVideoCapture {\n    var stillImageOutput: AVCaptureStillImageOutput?\n    var oldPreset: AVCaptureSession.Preset?\n    \n    private func waitForSensor() {\n        let now = CACurrentMediaTime()\n        let timeout = 1.0\n        \n        while (timeout > (CACurrentMediaTime() - now))\n            && (videoInput!.device.isAdjustingExposure || videoInput!.device.isAdjustingFocus) {}\n        return\n    }\n    \n    private func pauseVideoCaptureForPhoto() {\n        captureSession?.beginConfiguration()\n        oldPreset = captureSession?.sessionPreset\n        captureSession?.sessionPreset = AVCaptureSession.Preset.photo\n        stillImageOutput = AVCaptureStillImageOutput()\n        stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecType.jpeg]\n        guard let stillImageOutput = self.stillImageOutput else {\n            print(\"Error setting stillImageOutput\")\n            return\n        }\n        captureSession?.addOutput(stillImageOutput)\n        captureSession?.commitConfiguration()\n        \n        waitForSensor()\n    }\n    \n    private func resumeVideoCapture() {\n        captureSession?.beginConfiguration()\n        guard let oldPreset = oldPreset else {\n            print(\"Error get oldPreset\")\n            return\n        }\n        captureSession?.sessionPreset = oldPreset\n        guard let stillImageOutput = self.stillImageOutput else {\n            print(\"Error setting stillImageOutput\")\n            return\n        }\n        captureSession?.removeOutput(stillImageOutput)\n        captureSession?.commitConfiguration()\n    }\n    \n    private func doPhotoCapture(completionHandler handler: @escaping (_ photo: UIImage?) -> ()) {\n        guard let connection:AVCaptureConnection = stillImageOutput?.connections.filter({ conn -> Bool in\n            (conn ).inputPorts.contains( where: {\n                return ($0 ).mediaType == AVMediaType.video\n            })\n        }).first\n            else {\n                handler(nil)\n                return\n        }\n\n        stillImageOutput?.captureStillImageAsynchronously(from: connection, completionHandler: { (buffer, error) in\n            guard let buffer = buffer else {\n                print(\"Error gettinb buffer\")\n                return\n            }\n            let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)\n            let resultImage = UIImage(data: data!)\n            handler(resultImage)\n        })\n    }\n    \n    func takePhoto(completionHandler handler: @escaping (_ photo: UIImage?) -> ()) {\n        captureQueue.async {\n            self.pauseVideoCaptureForPhoto()\n            self.doPhotoCapture(completionHandler: { img in\n                DispatchQueue.main.async {\n                    handler(img)\n                }\n            })\n            self.resumeVideoCapture()\n        }\n    }\n }\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Live-Photo-Capture\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n\n    let captureQueue = DispatchQueue(label: \"com.tokbox.VideoCapture\")\n    let photoVideoCapture = ExamplePhotoVideoCapture()\n    \n    var imageView: UIImageView!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        imageView = UIImageView(frame: CGRect(x: 0, y: kWidgetHeight, width: kWidgetWidth, height: kWidgetHeight))\n        imageView.backgroundColor = UIColor.green\n        view.addSubview(imageView)\n        \n        \n        let singleTap = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleSingleTap(_:)))\n        view.addGestureRecognizer(singleTap)\n        \n        doConnect()\n    }\n    \n    @objc func handleSingleTap(_ gestureRecognizer: UIGestureRecognizer) {\n        photoVideoCapture.takePhoto { (photo) in\n            self.imageView.image = photo\n            self.imageView.setNeedsDisplay()\n        }\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    private func doConnect() {\n        var error: OTError?\n        defer {\n            process(error: error)\n        }\n        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError? = nil\n        defer {\n            process(error: error)\n        }\n        let pubSettings = OTPublisherSettings()\n        pubSettings.name = UIDevice.current.name\n        publisher = OTPublisher(delegate: self, settings: pubSettings)\n        if let pub = publisher {\n            let videoRender = ExampleVideoRender()\n            pub.videoRender = videoRender\n            pub.videoCapture = photoVideoCapture\n            session.publish(pub, error: &error)\n            videoRender.frame = CGRect(x: 0, y: 0, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(videoRender)\n        }\n    }\n    \n    fileprivate func process(error err: OTError?) {\n        if let e = err {\n            showAlert(errorStr: e.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }        \n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n    \n}\n\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tF872F76E1D6C851400A0674B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F76D1D6C851400A0674B /* AppDelegate.swift */; };\n\t\tF872F7701D6C851400A0674B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F76F1D6C851400A0674B /* ViewController.swift */; };\n\t\tF872F7731D6C851400A0674B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F872F7711D6C851400A0674B /* Main.storyboard */; };\n\t\tF872F7751D6C851400A0674B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F872F7741D6C851400A0674B /* Assets.xcassets */; };\n\t\tF872F7781D6C851400A0674B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F872F7761D6C851400A0674B /* LaunchScreen.storyboard */; };\n\t\tF872F7851D6C87DD00A0674B /* EAGLVideoRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F7811D6C87DD00A0674B /* EAGLVideoRenderer.swift */; };\n\t\tF872F7871D6C87DD00A0674B /* ExampleVideoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F7831D6C87DD00A0674B /* ExampleVideoCapture.swift */; };\n\t\tF872F7881D6C87DD00A0674B /* ExampleVideoRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F7841D6C87DD00A0674B /* ExampleVideoRender.swift */; };\n\t\tF872F78B1D6C889500A0674B /* ExamplePhotoVideoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F872F78A1D6C889500A0674B /* ExamplePhotoVideoCapture.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tF872F76A1D6C851400A0674B /* Live-Photo-Capture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Live-Photo-Capture.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tF872F76D1D6C851400A0674B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tF872F76F1D6C851400A0674B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF872F7721D6C851400A0674B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tF872F7741D6C851400A0674B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tF872F7771D6C851400A0674B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tF872F7791D6C851400A0674B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tF872F7811D6C87DD00A0674B /* EAGLVideoRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EAGLVideoRenderer.swift; path = \"../Custom-Video-Driver/Lets-Build-OTPublisher/EAGLVideoRenderer.swift\"; sourceTree = \"<group>\"; };\n\t\tF872F7831D6C87DD00A0674B /* ExampleVideoCapture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExampleVideoCapture.swift; path = \"../Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoCapture.swift\"; sourceTree = \"<group>\"; };\n\t\tF872F7841D6C87DD00A0674B /* ExampleVideoRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExampleVideoRender.swift; path = \"../Custom-Video-Driver/Lets-Build-OTPublisher/ExampleVideoRender.swift\"; sourceTree = \"<group>\"; };\n\t\tF872F78A1D6C889500A0674B /* ExamplePhotoVideoCapture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExamplePhotoVideoCapture.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF872F7671D6C851400A0674B /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tF872F7611D6C851400A0674B = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F7891D6C87E300A0674B /* Live-Photo-Capture */,\n\t\t\t\tF872F76C1D6C851400A0674B /* Live-Photo-Capture */,\n\t\t\t\tF872F76B1D6C851400A0674B /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF872F76B1D6C851400A0674B /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F76A1D6C851400A0674B /* Live-Photo-Capture.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF872F76C1D6C851400A0674B /* Live-Photo-Capture */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F76D1D6C851400A0674B /* AppDelegate.swift */,\n\t\t\t\tF872F76F1D6C851400A0674B /* ViewController.swift */,\n\t\t\t\tF872F7711D6C851400A0674B /* Main.storyboard */,\n\t\t\t\tF872F7741D6C851400A0674B /* Assets.xcassets */,\n\t\t\t\tF872F7761D6C851400A0674B /* LaunchScreen.storyboard */,\n\t\t\t\tF872F7791D6C851400A0674B /* Info.plist */,\n\t\t\t\tF872F78A1D6C889500A0674B /* ExamplePhotoVideoCapture.swift */,\n\t\t\t);\n\t\t\tpath = \"Live-Photo-Capture\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF872F7891D6C87E300A0674B /* Live-Photo-Capture */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F7811D6C87DD00A0674B /* EAGLVideoRenderer.swift */,\n\t\t\t\tF872F7831D6C87DD00A0674B /* ExampleVideoCapture.swift */,\n\t\t\t\tF872F7841D6C87DD00A0674B /* ExampleVideoRender.swift */,\n\t\t\t);\n\t\t\tname = \"Live-Photo-Capture\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF872F7691D6C851400A0674B /* Live-Photo-Capture */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F872F77C1D6C851400A0674B /* Build configuration list for PBXNativeTarget \"Live-Photo-Capture\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF872F7661D6C851400A0674B /* Sources */,\n\t\t\t\tF872F7671D6C851400A0674B /* Frameworks */,\n\t\t\t\tF872F7681D6C851400A0674B /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Live-Photo-Capture\";\n\t\t\tproductName = \"Live-Photo-Capture\";\n\t\t\tproductReference = F872F76A1D6C851400A0674B /* Live-Photo-Capture.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF872F7621D6C851400A0674B /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF872F7691D6C851400A0674B = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F872F7651D6C851400A0674B /* Build configuration list for PBXProject \"Live-Photo-Capture\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F872F7611D6C851400A0674B;\n\t\t\tproductRefGroup = F872F76B1D6C851400A0674B /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF872F7691D6C851400A0674B /* Live-Photo-Capture */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF872F7681D6C851400A0674B /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF872F7781D6C851400A0674B /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tF872F7751D6C851400A0674B /* Assets.xcassets in Resources */,\n\t\t\t\tF872F7731D6C851400A0674B /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF872F7661D6C851400A0674B /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF872F78B1D6C889500A0674B /* ExamplePhotoVideoCapture.swift in Sources */,\n\t\t\t\tF872F7851D6C87DD00A0674B /* EAGLVideoRenderer.swift in Sources */,\n\t\t\t\tF872F7701D6C851400A0674B /* ViewController.swift in Sources */,\n\t\t\t\tF872F7871D6C87DD00A0674B /* ExampleVideoCapture.swift in Sources */,\n\t\t\t\tF872F76E1D6C851400A0674B /* AppDelegate.swift in Sources */,\n\t\t\t\tF872F7881D6C87DD00A0674B /* ExampleVideoRender.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tF872F7711D6C851400A0674B /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F7721D6C851400A0674B /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF872F7761D6C851400A0674B /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF872F7771D6C851400A0674B /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF872F77A1D6C851400A0674B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF872F77B1D6C851400A0674B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF872F77D1D6C851400A0674B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"COCOAPODS=1\",\n\t\t\t\t\t\"GLES_SILENCE_DEPRECATION=1\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Live-Photo-Capture/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Live-Photo-Capture\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF872F77E1D6C851400A0674B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"Live-Photo-Capture/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Live-Photo-Capture\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF872F7651D6C851400A0674B /* Build configuration list for PBXProject \"Live-Photo-Capture\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF872F77A1D6C851400A0674B /* Debug */,\n\t\t\t\tF872F77B1D6C851400A0674B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF872F77C1D6C851400A0674B /* Build configuration list for PBXNativeTarget \"Live-Photo-Capture\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF872F77D1D6C851400A0674B /* Debug */,\n\t\t\t\tF872F77E1D6C851400A0674B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F872F7621D6C851400A0674B /* Project object */;\n}\n"
  },
  {
    "path": "Live-Photo-Capture/Live-Photo-Capture.xcodeproj/xcshareddata/xcschemes/Live-Photo-Capture.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F872F7691D6C851400A0674B\"\n               BuildableName = \"Live-Photo-Capture.app\"\n               BlueprintName = \"Live-Photo-Capture\"\n               ReferencedContainer = \"container:Live-Photo-Capture.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F872F7691D6C851400A0674B\"\n            BuildableName = \"Live-Photo-Capture.app\"\n            BlueprintName = \"Live-Photo-Capture\"\n            ReferencedContainer = \"container:Live-Photo-Capture.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F872F7691D6C851400A0674B\"\n            BuildableName = \"Live-Photo-Capture.app\"\n            BlueprintName = \"Live-Photo-Capture\"\n            ReferencedContainer = \"container:Live-Photo-Capture.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F872F7691D6C851400A0674B\"\n            BuildableName = \"Live-Photo-Capture.app\"\n            BlueprintName = \"Live-Photo-Capture\"\n            ReferencedContainer = \"container:Live-Photo-Capture.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Live-Photo-Capture/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Live-Photo-Capture' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Live-Photo-Capture/README.md",
    "content": "Live Photo Capture Sample App\n================================\n\nThis project extends some of the material we presented in [Project 2][1], by\ndemonstrating how a simple capture implementation can be extended to provide\ninteresting features. By the end of a code review of this project, you should\nunderstand how to use the AVFoundation API to temporarily halt your video\ncapture module, adjust capture settings to use photo-quality resolution,\ncapture a picture, then resume video capture.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nConfiguration Notes\n-------------------\n\nSince we are importing a number of classes implemented in project 2, the\nheader search paths in the project build settings must be extended to look\nin the project 2 directory.\n\nApplication Notes\n-----------------\n\n*   The only new implementation in this project is the\n    TBExamplePhotoVideoCapture class. By subclassing the video capture module\n    implemented in project 2, we save some time setting up standard video\n    capture and focus only on manipulating AVFoundation to give us a picture\n    in the middle of a (video) capture session.\n\n*   In testing, we noticed that the image sensor takes a moment to adjust white\n    balance and exposure after switching to the capture session preset for photo\n    quality (see `pauseVideoCaptureForPhoto` in TBExamplePhotoVideoCapture).\n    The example implementation stalls the photo capture with a busy loop, but\n    a more sophisticated approach might be considered to ensure the best\n    experience for the end user.\n\n*   This implementation briefly pauses the video feed during image capture. Note\n    that a prolonged delay to the video capture consumer might result in other\n    subscribers timing out the stream. If you wait for too long to send\n    consecutive video frames, you might lose the publisher altogether! Consider\n    sending a freeze frame or even a blank image buffer to the video capture\n    endpoint if you need to pause video for a long (>2 second) period.\n\n*   An alternative approach to this problem might be to continuously pipe photo-\n    quality video into the video capture consumer. This might not work on some\n    devices, based on processing capability and the fidelity of the image\n    sensor. Feel free to experiment and let us know how it goes for you!\n\n*   Note that this sample application is not supported in the XCode iOS\n    Simulator because the custom video capturer needs to acquire video from an\n    iOS device camera.\n\n[1]: ../2.Lets-Build-OTPublisher\n"
  },
  {
    "path": "Media-Transformers/CHANGELOG.md",
    "content": "# Video Transformers Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## 2.27.2\n\n### Added\n\n- Support Vonage Media Processor library as a opt-in library.\n- Supports Noise Suppression\n\n### Fixed\n\n- Decoupled Media Processor library\n\n## 2.26.0\n\n### Added\n\n- Support pre-built transformers in the Vonage Media Processor library or create your own custom video transformer to apply to published video.\n\n### Known issues\n\n- When using the simulator, video transformers are not visible on the publisher side.\n\n### Fixed\n\n- NA\n\n### Enhancements\n\n- NA\n\n### Changed\n\n- NA\n\n### Deprecated\n\n- NA\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n}\n\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"21507\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"21505\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"21507\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"21505\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"Video_Transformers\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-16\" y=\"-40\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Hello-World\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\nclass CustomTransformer: NSObject, OTCustomVideoTransformer {\n    func resizeImage(_ image: UIImage, to size: CGSize) -> UIImage? {\n        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)\n        image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))\n        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return resizedImage\n    }\n    \n    func transform(_ videoFrame: OTVideoFrame) {\n        if let image = UIImage(named: \"Vonage_Logo.png\") {\n            let yPlaneData = videoFrame.getPlaneBinaryData(0)\n            let videoWidth = Int(videoFrame.format?.imageWidth ?? 0)\n            let videoHeight = Int(videoFrame.format?.imageHeight ?? 0)\n            \n            // Calculate the desired size of the image\n            let desiredWidth = CGFloat(videoWidth) / 8 // Adjust this value as needed\n            let desiredHeight = image.size.height * (desiredWidth / image.size.width)\n            \n            // Resize the image to the desired size\n            if let resizedImage = resizeImage(image, to: CGSize(width: desiredWidth, height: desiredHeight)) {\n                let yPlane = yPlaneData\n                \n                // Create a CGContext from the Y plane\n                guard let context = CGContext(data: yPlane,\n                                              width: videoWidth,\n                                              height: videoHeight,\n                                              bitsPerComponent: 8,\n                                              bytesPerRow: videoWidth,\n                                              space: CGColorSpaceCreateDeviceGray(),\n                                              bitmapInfo: CGImageAlphaInfo.none.rawValue) else {\n                    return\n                }\n                \n                // Location of the image (in this case right bottom corner)\n                let x = CGFloat(videoWidth) * 4/5\n                let y = CGFloat(videoHeight) * 1/5\n                \n                // Draw the resized image on top of the Y plane\n                let rect = CGRect(x: x, y: y, width: desiredWidth, height: desiredHeight)\n                context.draw(resizedImage.cgImage!, in: rect)\n            }\n        }\n    }\n}\n\nclass ViewController: UIViewController {\n    \n    var buttonMediaTransformerToggle: UIButton!\n    \n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    lazy var publisher: OTPublisher = {\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        return OTPublisher(delegate: self, settings: settings)!\n    }()\n    \n    var subscriber: OTSubscriber?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        \n        session.publish(publisher, error: &error)\n        \n        if error != nil {\n            fatalError(\"An error occurred: \\(String(describing: error))\")\n        }\n        \n        if let pubView = publisher.view {\n            pubView.frame = CGRect(x: 0, y: 0, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(pubView)\n        }\n        \n        // Configure toogle button\n        buttonMediaTransformerToggle = UIButton(type: .custom)\n        buttonMediaTransformerToggle.frame = CGRect(x: kWidgetWidth - 65, y: 50, width: 50, height: 25)\n        buttonMediaTransformerToggle.layer.cornerRadius = 5.0\n        self.view.addSubview(buttonMediaTransformerToggle)\n        self.view.bringSubviewToFront(buttonMediaTransformerToggle)\n        buttonMediaTransformerToggle.setTitle(\"set\", for: .normal)\n        buttonMediaTransformerToggle.titleLabel?.font = UIFont.systemFont(ofSize: 12)\n        buttonMediaTransformerToggle.setTitleColor(.gray, for: .normal)\n        buttonMediaTransformerToggle.backgroundColor = .white\n        buttonMediaTransformerToggle.layer.borderWidth = 1.0\n        buttonMediaTransformerToggle.layer.borderColor = UIColor.gray.cgColor\n        buttonMediaTransformerToggle.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)\n\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        \n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func cleanupPublisher() {\n        publisher.view?.removeFromSuperview()\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            DispatchQueue.main.async {\n                let controller = UIAlertController(title: \"Error\", message: err.localizedDescription, preferredStyle: .alert)\n                controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n                self.present(controller, animated: true, completion: nil)\n            }\n        }\n    }\n    \n    let logoTransformer: CustomTransformer = CustomTransformer() // Create an instance of CustomTransformer\n\n    @objc func buttonTapped(_ sender: UIButton) {\n        if publisher.videoTransformers.isEmpty {\n            // Create background blur Vonage transformer\n            guard let backgroundBlur = OTVideoTransformer(name: \"BackgroundBlur\", properties: \"{\\\"radius\\\":\\\"High\\\"}\") else { return }\n            // Create custom transformer\n            guard let myCustomTransformer = OTVideoTransformer(name: \"logo\", transformer: logoTransformer)  else { return }\n\n            var myVideoTransformers = [OTVideoTransformer]()\n\n            myVideoTransformers.append(backgroundBlur)\n            myVideoTransformers.append(myCustomTransformer)\n\n            // Set video transformers to publisher video stream\n            publisher.videoTransformers = myVideoTransformers\n\n            buttonMediaTransformerToggle.setTitle(\"reset\", for: .normal)\n        } else {\n            // Clear all transformers from video stream\n            publisher.videoTransformers = []\n\n            buttonMediaTransformerToggle.setTitle(\"set\", for: .normal)\n        }\n\n        if publisher.audioTransformers.isEmpty {\n            // Create Noise Suppression Vonage transformer\n            guard let ns = OTAudioTransformer(name: \"NoiseSuppression\", properties: \"\") else { return }\n\n            var myAudioTransformers = [OTAudioTransformer]()\n\n            myAudioTransformers.append(ns)\n\n            // Set audio transformers to publisher audio stream\n            publisher.audioTransformers = myAudioTransformers\n\n            buttonMediaTransformerToggle.setTitle(\"reset\", for: .normal)\n        } else {\n            // Clear all transformers from audio stream\n            publisher.audioTransformers = []\n\n            buttonMediaTransformerToggle.setTitle(\"set\", for: .normal)\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        cleanupPublisher()\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        if let subsView = subscriber?.view {\n            subsView.frame = CGRect(x: 0, y: kWidgetHeight, width: kWidgetWidth, height: kWidgetHeight)\n            view.addSubview(subsView)\n        }\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n}\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375CF1EB1633400645696 /* AppDelegate.swift */; };\n\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05375D01EB1633400645696 /* Assets.xcassets */; };\n\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D11EB1633400645696 /* LaunchScreen.storyboard */; };\n\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375D31EB1633400645696 /* Main.storyboard */; };\n\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375D61EB1633400645696 /* ViewController.swift */; };\n\t\tADE6E7BE2A93B07300895674 /* Vonage_Logo.png in Resources */ = {isa = PBXBuildFile; fileRef = ADE6E7BD2A93B07300895674 /* Vonage_Logo.png */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05375D01EB1633400645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05375D21EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D41EB1633400645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375D51EB1633400645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05375D61EB1633400645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tADE6E7BD2A93B07300895674 /* Vonage_Logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Vonage_Logo.png; path = \"Media-Transformers/Vonage_Logo.png\"; sourceTree = \"<group>\"; };\n\t\tF86C649A1D5C7C630081846D /* Media-Transformers.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Media-Transformers.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64971D5C7C630081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t651BF1BD8407C44E924A3910 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375CE1EB1633400645696 /* Media-Transformers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375CF1EB1633400645696 /* AppDelegate.swift */,\n\t\t\t\tA05375D01EB1633400645696 /* Assets.xcassets */,\n\t\t\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05375D31EB1633400645696 /* Main.storyboard */,\n\t\t\t\tA05375D51EB1633400645696 /* Info.plist */,\n\t\t\t\tA05375D61EB1633400645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Media-Transformers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64911D5C7C630081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tADE6E7BD2A93B07300895674 /* Vonage_Logo.png */,\n\t\t\t\tA05375CE1EB1633400645696 /* Media-Transformers */,\n\t\t\t\tF86C649B1D5C7C630081846D /* Products */,\n\t\t\t\t651BF1BD8407C44E924A3910 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C649B1D5C7C630081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C649A1D5C7C630081846D /* Media-Transformers.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64991D5C7C630081846D /* Media-Transformers */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Media-Transformers\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF86C64961D5C7C630081846D /* Sources */,\n\t\t\t\tF86C64971D5C7C630081846D /* Frameworks */,\n\t\t\t\tF86C64981D5C7C630081846D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Media-Transformers\";\n\t\t\tproductName = \"Hello-World\";\n\t\t\tproductReference = F86C649A1D5C7C630081846D /* Media-Transformers.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64921D5C7C630081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64991D5C7C630081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Media-Transformers\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64911D5C7C630081846D;\n\t\t\tproductRefGroup = F86C649B1D5C7C630081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64991D5C7C630081846D /* Media-Transformers */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64981D5C7C630081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tADE6E7BE2A93B07300895674 /* Vonage_Logo.png in Resources */,\n\t\t\t\tA05375DA1EB1633400645696 /* Main.storyboard in Resources */,\n\t\t\t\tA05375D81EB1633400645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA05375D91EB1633400645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64961D5C7C630081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375DC1EB1633400645696 /* ViewController.swift in Sources */,\n\t\t\t\tA05375D71EB1633400645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05375D11EB1633400645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D21EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375D31EB1633400645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375D41EB1633400645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64AA1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AB1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = \"arm64 arm64e armv7 armv7s x86_64\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64AD1D5C7C630081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Media-Transformers/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64AE1D5C7C630081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Media-Transformers/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.Hello-World\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64951D5C7C630081846D /* Build configuration list for PBXProject \"Media-Transformers\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AA1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AB1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64AC1D5C7C630081846D /* Build configuration list for PBXNativeTarget \"Media-Transformers\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64AD1D5C7C630081846D /* Debug */,\n\t\t\t\tF86C64AE1D5C7C630081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64921D5C7C630081846D /* Project object */;\n}\n"
  },
  {
    "path": "Media-Transformers/Media-Transformers.xcodeproj/xcshareddata/xcschemes/Video-Transformers.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1170\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n               BuildableName = \"Media-Transformers.app\"\n               BlueprintName = \"Media-Transformers\"\n               ReferencedContainer = \"container:Media-Transformers.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Media-Transformers.app\"\n            BlueprintName = \"Media-Transformers\"\n            ReferencedContainer = \"container:Media-Transformers.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Media-Transformers.app\"\n            BlueprintName = \"Media-Transformers\"\n            ReferencedContainer = \"container:Media-Transformers.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64991D5C7C630081846D\"\n            BuildableName = \"Media-Transformers.app\"\n            BlueprintName = \"Media-Transformers\"\n            ReferencedContainer = \"container:Media-Transformers.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Media-Transformers/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Media-Transformers' do\n  pod 'OTXCFramework', OpenTokSDKVersion\n  pod 'VonageClientSDKVideoTransformers' , OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Media-Transformers/README.md",
    "content": "Video Transformers\n======================\n\nThe Video Transformers app is a very simple application created on top of Basic Video Chat meant to get a new developer started using Media Processor APIs on OpenTok iOS SDK. For a full description, see the [Video Transformers tutorial at the\nOpenTok developer center](https://tokbox.com/developer/guides/vonage-media-processor/ios).\n\nYou can use pre-built transformers in the Vonage Media Processor library or create your own custom video transformer to apply to published video.\n\nYou can use the OTPublisherKit.videoTransformers properties to apply video transformers to a stream.\n\nFor video, you can apply the background blur video transformer included in the Vonage Media Library.\nYou can use the <a href=\"/developer/sdks/ios/reference/Classes/OTPublisherKit.html#//api/name/audioTransformers\"><code>OTPublisherKit.audioTransformers</code></a> and\n<a href=\"/developer/sdks/ios/reference/Classes/OTPublisherKit.html#//api/name/videoTransformers\"><code>OTPublisherKit.videoTransformers</code></a>\nproperties to apply audio and video transformers to a stream.\n\n<p class=\"important\">\n  <b>Important:</b> The audio and video transformer API is a beta feature.\n</p>\n\nFor video, you can apply the background blur video transformer included in the Vonage Media Library.\n\nYou can also create your own custom audio and video transformers.\n\n## Applying a video transformer from the Vonage Media Library\n\nUse the <a href=\"/developer/sdks/ios/reference/Classes/OTVideoTransformer.html#//api/name/initWithName:properties:\"><code>[OTVideoTransformer initWithName:properties:]</code></a>\nmethod to create a video transformer that uses a named transformer from the Vonage Media Library.\n\nCurrently, only one transformer is supported: background blur. Set the `name` parameter to `\"BackgroundBlur\"`.\nSet the `properties` parameter to a JSON string defining properties for the transformer.\nFor the background blur transformer, this JSON includes one property -- `radius` -- which can be set\nto `\"High\"`, `\"Low\"`, or `\"None\"`.\n\n```swift\nguard let backgroundBlur = OTVideoTransformer(name: \"BackgroundBlur\", properties: \"{\\\"radius\\\":\\\"High\\\"}\") else { return }\n\nvar myVideoTransformers = [OTVideoTransformer]()\nmyVideoTransformers.append(backgroundBlur)\n\n// Set video transformers to publisher video stream\npublisher.videoTransformers = myVideoTransformers\n```\n\n## Creating a custom video transformer\n\nCreate a class that implements the <a href=\"/developer/sdks/ios/reference/Protocols/OTCustomVideoTransformer.html\"><code>OTCustomVideoTransformer</code></a> \nprotocol. Implement the `[OTCustomVideoTransformer transform:]` method, applying a transformation to the `OTVideoFrame` object passed into the method. The `[OTCustomVideoTransformer transform:]` method is triggered for each video frame:\n\n```swift\nclass CustomTransformer: NSObject, OTCustomVideoTransformer {    \n    func transform(_ videoFrame: OTVideoFrame) {\n        // Your custom transformation\n    }\n}\n```\n\nIn this sample, to display one of the infinite transformations that can be applied to video frames, a logo is being added to the bottom right corner of the video.\n\n```swift\nclass CustomTransformer: NSObject, OTCustomVideoTransformer {\n    func resizeImage(_ image: UIImage, to size: CGSize) -> UIImage? {\n        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)\n        image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))\n        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return resizedImage\n    }\n    \n    func transform(_ videoFrame: OTVideoFrame) {\n        if let image = UIImage(named: \"Vonage_Logo.png\") {\n            let yPlaneData = videoFrame.getPlaneBinaryData(0)\n            let videoWidth = Int(videoFrame.format?.imageWidth ?? 0)\n            let videoHeight = Int(videoFrame.format?.imageHeight ?? 0)\n            \n            // Calculate the desired size of the image\n            let desiredWidth = CGFloat(videoWidth) / 8 // Adjust this value as needed\n            let desiredHeight = image.size.height * (desiredWidth / image.size.width)\n            \n            // Resize the image to the desired size\n            if let resizedImage = resizeImage(image, to: CGSize(width: desiredWidth, height: desiredHeight)) {\n                let yPlane = yPlaneData\n                \n                // Create a CGContext from the Y plane\n                guard let context = CGContext(data: yPlane,\n                                              width: videoWidth,\n                                              height: videoHeight,\n                                              bitsPerComponent: 8,\n                                              bytesPerRow: videoWidth,\n                                              space: CGColorSpaceCreateDeviceGray(),\n                                              bitmapInfo: CGImageAlphaInfo.none.rawValue) else {\n                    return\n                }\n                \n                // Location of the image (in this case right bottom corner)\n                let x = CGFloat(videoWidth) * 4/5\n                let y = CGFloat(videoHeight) * 1/5\n                \n                // Draw the resized image on top of the Y plane\n                let rect = CGRect(x: x, y: y, width: desiredWidth, height: desiredHeight)\n                context.draw(resizedImage.cgImage!, in: rect)\n            }\n        }\n    }\n}\n``` \n\nThen set the `OTPublisherKit.videoTransformers` property to an array that includes the object that implements the\nOTCustomVideoTransformer interface:\n\n```swift \n// Create an instance of CustomTransformer\nvar logoTransformer: CustomTransformer = CustomTransformer()\n\n...\n\n// Create custom transformer\nguard let myCustomTransformer = OTVideoTransformer(name: \"logo\", transformer: logoTransformer)  else { return }\n\nvar myVideoTransformers = [OTVideoTransformer]()\nmyVideoTransformers.append(myCustomTransformer)\n\n// Set video transformers to publisher video stream\npublisher.videoTransformers = myVideoTransformers\n```\n\nYou can combine the Vonage Media library transformer (see the previous section) with custom transformers or apply\nmultiple custom transformers by adding multiple PublisherKit.VideoTransformer objects to the ArrayList used\nfor the `OTPublisherKit.videoTransformers` property.\n\n## Clearing video transformers for a publisher\n\nTo clear video transformers for a publisher, set the `OTPublisherKit.videoTransformers` property to an empty array.\n\n```objectivec\npublisher.videoTransformers = []\n```\n\nAdding the OpenTok library\n==========================\nIn this example the OpenTok iOS SDK was not included as a dependency,\nyou can do it through Swift Package Manager or Cocoapods.\n\n\nSwift Package Manager\n---------------------\nTo add a package dependency to your Xcode project, you should select \n*File* > *Swift Packages* > *Add Package Dependency* and enter the repository URL:\n`https://github.com/opentok/vonage-client-sdk-video.git`.\n\n\nCocoapods\n---------\nTo use CocoaPods to add the OpenTok library and its dependencies into this sample app\nsimply open Terminal, navigate to the root directory of the project and run: `pod install`.\n\n\nThe Media-Transformers app is a very simple application meant to get a new developer\nstarted using the OpenTok iOS SDK."
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  7.Multiparty-UICollectionView\n//\n//  Created by Roberto Perez Cubero on 17/04/2017.\n//  Copyright © 2017 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n\n}\n\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16E195\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"wYW-m3-d6q\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12086\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Chat View Controller-->\n        <scene sceneID=\"2cp-CV-Shi\">\n            <objects>\n                <collectionViewController id=\"wYW-m3-d6q\" customClass=\"ChatViewController\" customModule=\"__Multiparty_UICollectionView\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <collectionView key=\"view\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" id=\"06X-fG-S44\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        <collectionViewLayout key=\"collectionViewLayout\" id=\"CZh-Sy-Ozm\" customClass=\"MultipartyLayout\" customModule=\"__Multiparty_UICollectionView\" customModuleProvider=\"target\"/>\n                        <cells>\n                            <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"videoCell\" id=\"8OC-g3-cn8\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"50\" height=\"50\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <view key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </view>\n                            </collectionViewCell>\n                        </cells>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"wYW-m3-d6q\" id=\"5RQ-89-4HX\"/>\n                            <outlet property=\"delegate\" destination=\"wYW-m3-d6q\" id=\"UUc-DE-X4j\"/>\n                        </connections>\n                    </collectionView>\n                </collectionViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iM9-rC-4E3\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-185\" y=\"2\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/ChatViewController.swift",
    "content": "//\n//  ViewController.swift\n//  7.Multiparty-UICollectionView\n//\n//  Created by Roberto Perez Cubero on 17/04/2017.\n//  Copyright © 2017 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nclass ChatViewController: UICollectionViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n\n    lazy var publisher: OTPublisher = {\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        return OTPublisher(delegate: self, settings: settings)!\n    }()\n\n    var subscribers: [OTSubscriber] = []\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        doConnect()\n    }\n\n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n\n        session.connect(withToken: kToken, error: &error)\n    }\n\n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        session.publish(publisher, error: &error)\n\n        collectionView?.reloadData()\n    }\n\n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        guard let subscriber = OTSubscriber(stream: stream, delegate: self)\n            else {\n                print(\"Error while subscribing\")\n                return\n        }\n        session.subscribe(subscriber, error: &error)\n        subscribers.append(subscriber)\n        collectionView?.reloadData()\n    }\n\n    fileprivate func cleanupSubscriber(_ stream: OTStream) {\n        subscribers = subscribers.filter { $0.stream?.streamId != stream.streamId }\n        collectionView?.reloadData()\n    }\n\n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            showAlert(errorStr: err.localizedDescription)\n        }\n    }\n\n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    // MARK: - UICollectionView methods\n    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return subscribers.count + 1\n    }\n\n    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"videoCell\", for: indexPath)\n        let videoView: UIView? = {\n            if (indexPath.row == 0) {\n                return publisher.view\n            } else {\n                let sub = subscribers[indexPath.row - 1]\n                return sub.view\n            }\n        }()\n\n        if let viewToAdd = videoView {\n            viewToAdd.frame = cell.bounds\n            cell.addSubview(viewToAdd)\n        }\n        return cell\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ChatViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n\n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n\n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        doSubscribe(stream)\n    }\n\n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        cleanupSubscriber(stream)\n    }\n\n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ChatViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n    }\n\n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n    }\n\n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ChatViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        print(\"Subscriber connected\")\n    }\n\n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n\n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView/MultipartyLayout.swift",
    "content": "//\n//  MultipartyLayout.swift\n//  7.Multiparty-UICollectionView\n//\n//  Created by Roberto Perez Cubero on 17/04/2017.\n//  Copyright © 2017 tokbox. All rights reserved.\n//\n\nimport UIKit\n\nextension Int {\n    var isEven: Bool {\n        return self % 2 == 0\n    }\n}\n\nclass MultipartyLayout: UICollectionViewLayout {\n    fileprivate var cache = [UICollectionViewLayoutAttributes]()\n    fileprivate var cachedNumberOfViews = 0\n    \n    override func prepare() {\n        guard let views = collectionView?.numberOfItems(inSection: 0)\n            else {\n                cache.removeAll()\n                return\n        }\n        \n        if views != cachedNumberOfViews {\n            cache.removeAll()\n        }\n        \n        if cache.isEmpty {\n            cachedNumberOfViews = views\n            let attribs: [UICollectionViewLayoutAttributes] = {\n                switch views {\n                case 1:\n                    return attributesForPublisherFullScreen()\n                case 2:\n                    return attributesForPublisherAndOneSubscriber()\n                case let x where x > 2 && x.isEven:\n                    return attributesForAllViewsTwoByTwo(withNumberOfViews: x)\n                case let x where x > 2 && !x.isEven:\n                    return attributesForPublisherOnTopAndSubscribersTwoByTwo(withNumberOfViews: x)\n                default:\n                    return []\n                }\n            }()\n            \n            cache.append(contentsOf: attribs)\n        }\n    }\n    \n    fileprivate func attributesForPublisherFullScreen() -> [UICollectionViewLayoutAttributes] {\n        var attribs = [UICollectionViewLayoutAttributes]()\n        let ip = IndexPath(item: 0, section: 0)\n        let attr = UICollectionViewLayoutAttributes(forCellWith: ip)\n        attr.frame = collectionView?.superview?.bounds ?? CGRect()\n        attribs.append(attr)\n        \n        return attribs\n    }\n    \n    // Will layout publisher view over subscriber view\n    fileprivate func attributesForPublisherAndOneSubscriber() -> [UICollectionViewLayoutAttributes] {\n        var attribs = [UICollectionViewLayoutAttributes]()\n        let height = (collectionView?.superview?.bounds.size.height ?? 0) / 2\n        let width = collectionView?.superview?.bounds.size.width ?? 0\n        \n        let pubIp = IndexPath(item: 0, section: 0)\n        let pubAttribs = UICollectionViewLayoutAttributes(forCellWith: pubIp)\n        pubAttribs.frame = CGRect(x: 0, y: 0, width: width, height: height)\n        attribs.append(pubAttribs)\n        \n        let subIp = IndexPath(item: 1, section: 0)\n        let subAttribs = UICollectionViewLayoutAttributes(forCellWith: subIp)\n        subAttribs.frame = CGRect(x: 0, y:height, width: width, height: height)\n        attribs.append(subAttribs)\n        \n        return attribs\n    }\n    \n    fileprivate func attributesForPublisherOnTopAndSubscribersTwoByTwo(withNumberOfViews views: Int)\n        -> [UICollectionViewLayoutAttributes]\n    {\n        var attribs = [UICollectionViewLayoutAttributes]()\n        let rows = CGFloat(((views  - 1) / 2) + 1)\n        let height = (collectionView?.superview?.bounds.size.height ?? 0) / CGFloat(rows)\n        let width = (collectionView?.superview?.bounds.size.width ?? 0) / 2\n        \n        let pubIp = IndexPath(item: 0, section: 0)\n        let pubAttribs = UICollectionViewLayoutAttributes(forCellWith: pubIp)\n        pubAttribs.frame = CGRect(x: 0, y: 0, width: collectionView?.superview?.bounds.size.width ?? 0, height: height)\n        attribs.append(pubAttribs)\n        attribs.append(contentsOf: attributesForViewsInRows(initialYOffset: height,\n                                                            totalNumberOfViews: views,\n                                                            viewSize: CGSize(width: width, height: height),\n                                                            viewOffset: 1))\n        return attribs\n    }\n    \n    fileprivate func attributesForAllViewsTwoByTwo(withNumberOfViews views: Int)\n        -> [UICollectionViewLayoutAttributes]\n    {\n        var attribs = [UICollectionViewLayoutAttributes]()\n        let rows = views / 2\n        let height = (collectionView?.superview?.bounds.size.height ?? 0) / CGFloat(rows)\n        let width = (collectionView?.superview?.bounds.size.width ?? 0) / 2\n        \n        attribs.append(contentsOf: attributesForViewsInRows(initialYOffset: 0,\n                                                            totalNumberOfViews: views,\n                                                            viewSize: CGSize(width: width, height: height),\n                                                            viewOffset: 0))\n        return attribs\n    }\n    \n    fileprivate func attributesForViewsInRows(initialYOffset: CGFloat,\n                                              totalNumberOfViews views: Int,\n                                              viewSize: CGSize,\n                                              viewOffset: Int)\n        -> [UICollectionViewLayoutAttributes]\n    {\n        var attribs = [UICollectionViewLayoutAttributes]()\n        var yOffset = initialYOffset\n        \n        let newLineCondition : (Int) -> Bool = {\n            if viewOffset == 0 {\n                return !$0.isEven\n            } else {\n                return $0.isEven\n            }\n        }\n        \n        for item in viewOffset..<views {\n            let ip = IndexPath(item: item, section: 0)\n            let attrs = UICollectionViewLayoutAttributes(forCellWith: ip)\n            let xOffset = CGFloat(newLineCondition(item) ? viewSize.width : 0 )\n            attrs.frame = CGRect(x: xOffset, y: yOffset, width: viewSize.width, height: viewSize.height)\n            attribs.append(attrs)\n            if item > viewOffset && newLineCondition(item) {\n                yOffset += viewSize.height\n            }\n        }\n        \n        return attribs\n    }\n    \n    override var collectionViewContentSize: CGSize {\n        return collectionView?.superview?.bounds.size ?? CGSize()\n    }\n    \n    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {\n        return cache\n    }\n    \n}\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA05376091EB1638C00645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376001EB1638C00645696 /* AppDelegate.swift */; };\n\t\tA053760A1EB1638C00645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05376011EB1638C00645696 /* Assets.xcassets */; };\n\t\tA053760B1EB1638C00645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05376021EB1638C00645696 /* LaunchScreen.storyboard */; };\n\t\tA053760C1EB1638C00645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05376041EB1638C00645696 /* Main.storyboard */; };\n\t\tA053760D1EB1638C00645696 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376061EB1638C00645696 /* ChatViewController.swift */; };\n\t\tA053760F1EB1638C00645696 /* MultipartyLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05376081EB1638C00645696 /* MultipartyLayout.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05376001EB1638C00645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05376011EB1638C00645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05376031EB1638C00645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05376051EB1638C00645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05376061EB1638C00645696 /* ChatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = \"<group>\"; };\n\t\tA05376071EB1638C00645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05376081EB1638C00645696 /* MultipartyLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartyLayout.swift; sourceTree = \"<group>\"; };\n\t\tF852CCBF1EA4D88200ADB206 /* Multiparty-UICollectionView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Multiparty-UICollectionView.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF852CCBC1EA4D88200ADB206 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA05375FF1EB1638C00645696 /* Multiparty-UICollectionView */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376001EB1638C00645696 /* AppDelegate.swift */,\n\t\t\t\tA05376011EB1638C00645696 /* Assets.xcassets */,\n\t\t\t\tA05376021EB1638C00645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05376041EB1638C00645696 /* Main.storyboard */,\n\t\t\t\tA05376061EB1638C00645696 /* ChatViewController.swift */,\n\t\t\t\tA05376071EB1638C00645696 /* Info.plist */,\n\t\t\t\tA05376081EB1638C00645696 /* MultipartyLayout.swift */,\n\t\t\t);\n\t\t\tpath = \"Multiparty-UICollectionView\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF852CCB61EA4D88200ADB206 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375FF1EB1638C00645696 /* Multiparty-UICollectionView */,\n\t\t\t\tF852CCC01EA4D88200ADB206 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF852CCC01EA4D88200ADB206 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF852CCBF1EA4D88200ADB206 /* Multiparty-UICollectionView.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF852CCBE1EA4D88200ADB206 /* Multiparty-UICollectionView */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F852CCD11EA4D88200ADB206 /* Build configuration list for PBXNativeTarget \"Multiparty-UICollectionView\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF852CCBB1EA4D88200ADB206 /* Sources */,\n\t\t\t\tF852CCBC1EA4D88200ADB206 /* Frameworks */,\n\t\t\t\tF852CCBD1EA4D88200ADB206 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Multiparty-UICollectionView\";\n\t\t\tproductName = \"7.Multiparty-UICollectionView\";\n\t\t\tproductReference = F852CCBF1EA4D88200ADB206 /* Multiparty-UICollectionView.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF852CCB71EA4D88200ADB206 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0830;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF852CCBE1EA4D88200ADB206 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3.1;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F852CCBA1EA4D88200ADB206 /* Build configuration list for PBXProject \"Multiparty-UICollectionView\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F852CCB61EA4D88200ADB206;\n\t\t\tproductRefGroup = F852CCC01EA4D88200ADB206 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF852CCBE1EA4D88200ADB206 /* Multiparty-UICollectionView */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF852CCBD1EA4D88200ADB206 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA053760C1EB1638C00645696 /* Main.storyboard in Resources */,\n\t\t\t\tA053760A1EB1638C00645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA053760B1EB1638C00645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF852CCBB1EA4D88200ADB206 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA053760F1EB1638C00645696 /* MultipartyLayout.swift in Sources */,\n\t\t\t\tA053760D1EB1638C00645696 /* ChatViewController.swift in Sources */,\n\t\t\t\tA05376091EB1638C00645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05376021EB1638C00645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376031EB1638C00645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05376041EB1638C00645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05376051EB1638C00645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF852CCCF1EA4D88200ADB206 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF852CCD01EA4D88200ADB206 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF852CCD21EA4D88200ADB206 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Multiparty-UICollectionView/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Multiparty-UICollectionView\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF852CCD31EA4D88200ADB206 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Multiparty-UICollectionView/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Multiparty-UICollectionView\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF852CCBA1EA4D88200ADB206 /* Build configuration list for PBXProject \"Multiparty-UICollectionView\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF852CCCF1EA4D88200ADB206 /* Debug */,\n\t\t\t\tF852CCD01EA4D88200ADB206 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF852CCD11EA4D88200ADB206 /* Build configuration list for PBXNativeTarget \"Multiparty-UICollectionView\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF852CCD21EA4D88200ADB206 /* Debug */,\n\t\t\t\tF852CCD31EA4D88200ADB206 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F852CCB71EA4D88200ADB206 /* Project object */;\n}\n"
  },
  {
    "path": "Multiparty-UICollectionView/Multiparty-UICollectionView.xcodeproj/xcshareddata/xcschemes/Multiparty-UICollectionView.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0930\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F852CCBE1EA4D88200ADB206\"\n               BuildableName = \"Multiparty-UICollectionView.app\"\n               BlueprintName = \"Multiparty-UICollectionView\"\n               ReferencedContainer = \"container:Multiparty-UICollectionView.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F852CCBE1EA4D88200ADB206\"\n            BuildableName = \"Multiparty-UICollectionView.app\"\n            BlueprintName = \"Multiparty-UICollectionView\"\n            ReferencedContainer = \"container:Multiparty-UICollectionView.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F852CCBE1EA4D88200ADB206\"\n            BuildableName = \"Multiparty-UICollectionView.app\"\n            BlueprintName = \"Multiparty-UICollectionView\"\n            ReferencedContainer = \"container:Multiparty-UICollectionView.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F852CCBE1EA4D88200ADB206\"\n            BuildableName = \"Multiparty-UICollectionView.app\"\n            BlueprintName = \"Multiparty-UICollectionView\"\n            ReferencedContainer = \"container:Multiparty-UICollectionView.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Multiparty-UICollectionView/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Multiparty-UICollectionView' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Multiparty-UICollectionView/README.md",
    "content": "Multiparty UICollectionView Sample App\n========================================\n\nIf you plan to build a multiparty app, you may want to use `UICollectionView` to dynamically\nadapt to the screen size and display the video views of all participants in an OpenTok session.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nUse `UICollectionView` to easily specify the way views are displayed.\n\n## Creating a custom layout for UICollectionView\n\nWhen building custom layouts, you need to subclass `UICollectionViewLayout` and override two\nmethods (`prepare()` and `layoutAttributesForElements(in:)`) and a computed property\n(`collectionViewContentSize`).\n\nFirst, you need to return the size of the entire `UICollectionView`. In our case, since we want\nto fill the entire screen without scrolling, we simply return the size of the `UICollectionView`\ncontainer by overriding `collectionViewContentSize()`:\n\n```swift\noverride var collectionViewContentSize: CGSize {\n    return collectionView?.superview?.bounds.size ?? CGSize()\n}\n```\n\nWhen the view is going to be laid out, `UIKit` calls the implementation of the\n`MultipartyLayout.prepare()` method. This method prepares values used when the views are drawn.\nIt populates a cache, which is a `UICollectionViewLayoutAttributes` object that specifies the size\nand position of each item:\n\n```swift\noverride func prepare() {\n    guard let views = collectionView?.numberOfItems(inSection: 0)\n        else {\n            cache.removeAll()\n            return\n    }\n\n    if views != cachedNumberOfViews {\n        cache.removeAll()\n    }\n\n    if cache.isEmpty {\n        cachedNumberOfViews = views\n        let attribs: [UICollectionViewLayoutAttributes] = {\n            switch views {\n            case 1:\n                return attributesForPublisherFullScreen()\n            case 2:\n                return attributesForPublisherAndOneSubscriber()\n            case let x where x > 2 && x.isEven:\n                return attributesForAllViewsTwoByTwo(withNumberOfViews: x)\n            case let x where x > 2 && !x.isEven:\n                return attributesForPublisherOnTopAndSubscribersTwoByTwo(withNumberOfViews: x)\n            default:\n                return []\n            }\n        }()\n\n        cache.append(contentsOf: attribs)\n    }\n}\n```\n\nThe implementation of the `UICollectionViewLayout.layoutAttributesForElements(in:)` method is\ncalled when the views are laid out. It returns the cache containing the actual view sizes:\n\n```swift\noverride func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {\n    return cache\n}\n```\n"
  },
  {
    "path": "OpenTokSDKVersion.rb",
    "content": "OpenTokSDKVersion = '2.32.1'\nMinIosSdkVersion = '15.0'\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/AppDelegate.swift",
    "content": "import UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n\n\n}\n\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"8150\" systemVersion=\"15A204g\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"8122\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"32700.99.1234\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22684\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"Picture_In_Picture\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleAspectFit\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AFb-Oc-lee\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"240\" height=\"128\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <subviews>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" text=\"Waiting for Remote Stream...\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"R7n-QW-r3e\">\n                                        <rect key=\"frame\" x=\"89\" y=\"76\" width=\"218\" height=\"21\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                        <nil key=\"textColor\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                </subviews>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                            </view>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"system\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0GB-Us-yig\">\n                                <rect key=\"frame\" x=\"142\" y=\"503\" width=\"91\" height=\"35\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <state key=\"normal\" title=\"Button\"/>\n                                <buttonConfiguration key=\"configuration\" style=\"plain\" title=\"Start PIP\"/>\n                                <connections>\n                                    <action selector=\"startPiPTapped:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"BTd-15-XQ4\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                    <connections>\n                        <outlet property=\"videoContainerView\" destination=\"AFb-Oc-lee\" id=\"q1s-ek-i6S\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"32.799999999999997\" y=\"36.431784107946029\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/ExampleVideoRender.swift",
    "content": "import OpenTok\nimport GLKit\nimport Foundation\nimport Accelerate\nimport UIKit\n\nclass Accelerater{\n    var infoYpCbCrToARGB = vImage_YpCbCrToARGB()\n    init() {\n        _ = configureYpCbCrToARGBInfo()\n    }\n\n    func configureYpCbCrToARGBInfo() -> vImage_Error {\n        print(\"Configuring\")\n        var pixelRange = vImage_YpCbCrPixelRange(Yp_bias: 0,\n                                                 CbCr_bias: 128,\n                                                 YpRangeMax: 255,\n                                                 CbCrRangeMax: 255,\n                                                 YpMax: 255,\n                                                 YpMin: 1,\n                                                 CbCrMax: 255,\n                                                 CbCrMin: 0)\n\n        let error = vImageConvert_YpCbCrToARGB_GenerateConversion(\n            kvImage_YpCbCrToARGBMatrix_ITU_R_601_4!,\n            &pixelRange,\n            &infoYpCbCrToARGB,\n            kvImage420Yp8_Cb8_Cr8,\n            kvImageARGB8888,\n            vImage_Flags(kvImagePrintDiagnosticsToConsole))\n\n\n\n        print(\"Configration done \\(error)\")\n        return error\n    }\n\n    func convertFrameVImageYUV(_ frame: OTVideoFrame, to pixelBufferRef: CVPixelBuffer?) -> vImage_Error{\n        if pixelBufferRef == nil {\n            print(\"No PixelBuffer refrance found\")\n            return vImage_Error(kvImageInvalidParameter)\n        }\n\n        let width = frame.format?.imageWidth ?? 0\n        let height = frame.format?.imageHeight ?? 0\n        let subsampledWidth = frame.format!.imageWidth/2\n        let subsampledHeight = frame.format!.imageHeight/2\n        let planeSize = calculatePlaneSize(forFrame: frame)\n\n        let yPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.ySize)\n        let uPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.uSize)\n        let vPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.vSize)\n\n        memcpy(yPlane, frame.planes?.pointer(at: 0), planeSize.ySize)\n        memcpy(uPlane, frame.planes?.pointer(at: 1), planeSize.uSize)\n        memcpy(vPlane, frame.planes?.pointer(at: 2), planeSize.vSize)\n\n        let yStride = frame.format!.bytesPerRow.object(at: 0) as! Int\n        // multiply chroma strides by 2 as bytesPerRow represents 2x2 subsample\n        let uStride = frame.format!.bytesPerRow.object(at: 1) as! Int\n        let vStride = frame.format!.bytesPerRow.object(at: 2) as! Int\n\n        var yPlaneBuffer = vImage_Buffer(data: yPlane, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: yStride)\n\n        var uPlaneBuffer = vImage_Buffer(data: uPlane, height: vImagePixelCount(subsampledHeight), width: vImagePixelCount(subsampledWidth), rowBytes: uStride)\n\n\n        var vPlaneBuffer = vImage_Buffer(data: vPlane, height: vImagePixelCount(subsampledHeight), width: vImagePixelCount(subsampledWidth), rowBytes: vStride)\n        CVPixelBufferLockBaseAddress(pixelBufferRef!, .readOnly)\n        let pixelBufferData = CVPixelBufferGetBaseAddress(pixelBufferRef!)\n        let rowBytes = CVPixelBufferGetBytesPerRow(pixelBufferRef!)\n        var destinationImageBuffer = vImage_Buffer()\n        destinationImageBuffer.data = pixelBufferData\n        destinationImageBuffer.height = vImagePixelCount(height)\n        destinationImageBuffer.width = vImagePixelCount(width)\n        destinationImageBuffer.rowBytes = rowBytes\n\n        var permuteMap: [UInt8] = [3, 2, 1, 0] // BGRA\n        let convertError = vImageConvert_420Yp8_Cb8_Cr8ToARGB8888(&yPlaneBuffer, &uPlaneBuffer, &vPlaneBuffer, &destinationImageBuffer, &infoYpCbCrToARGB, &permuteMap, 255, vImage_Flags(kvImagePrintDiagnosticsToConsole))\n\n        CVPixelBufferUnlockBaseAddress(pixelBufferRef!, [])\n\n\n        yPlane.deallocate()\n        uPlane.deallocate()\n        vPlane.deallocate()\n\n        return convertError\n\n    }\n    fileprivate func calculatePlaneSize(forFrame frame: OTVideoFrame)\n        -> (ySize: Int, uSize: Int, vSize: Int)\n    {\n        guard let frameFormat = frame.format\n            else {\n                return (0, 0 ,0)\n        }\n        let baseSize = Int(frameFormat.imageWidth * frameFormat.imageHeight) * MemoryLayout<GLubyte>.size\n        return (baseSize, baseSize / 4, baseSize / 4)\n    }\n\n}\n\nprotocol ExampleVideoRenderDelegate {\n    func renderer(_ renderer: ExampleVideoRender, didReceiveFrame videoFrame: OTVideoFrame)\n}\n\nclass ExampleVideoRender: UIView {\n    \n    var delegate: ExampleVideoRenderDelegate?\n    \n    var frameLock = NSLock()\n    var bufferDisplayLayer =  AVSampleBufferDisplayLayer()\n    var pipBufferDisplayLayer: AVSampleBufferDisplayLayer?\n    let accel = Accelerater()\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n    }\n    \n    required init?(coder aDecoder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n}\n\nextension ExampleVideoRender: OTVideoRender {\n    func renderVideoFrame(_ frame: OTVideoFrame) {\n        if let format = frame.format {\n            frameLock.lock()\n            assert(format.pixelFormat == .I420)\n            \n            if let sampleBuffer = createSampleBufferWithVideoFrame(frame,\n                                                                   width: Int(frame.format!.imageWidth),\n                                                                   height: Int(frame.format!.imageHeight)) {\n                bufferDisplayLayer.enqueue(sampleBuffer)\n                pipBufferDisplayLayer?.enqueue(sampleBuffer)\n            }\n            \n            frameLock.unlock()\n        }\n    }\n    \n    \n    func createSampleBufferWithVideoFrame(_ frame: OTVideoFrame, width: Int, height: Int) -> CMSampleBuffer? {\n        \n        let pixelAttributes: NSDictionary = [kCVPixelBufferIOSurfacePropertiesKey as String: [:]]\n        var pixelBuffer: CVPixelBuffer?\n        let result = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, pixelAttributes as CFDictionary, &pixelBuffer)\n        \n        guard result == 0 else {\n            return nil\n        }\n        _ = accel.convertFrameVImageYUV(frame, to: pixelBuffer)\n        let s = createSampleBufferFrom(pixelBuffer: pixelBuffer!)\n        \n        \n        return s\n    }\n    \n    func createSampleBufferFrom(pixelBuffer: CVPixelBuffer) -> CMSampleBuffer? {\n        CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)\n        \n        var sampleBuffer: CMSampleBuffer?\n        \n        \n        let now = CMTimeMakeWithSeconds(CACurrentMediaTime(), preferredTimescale: 1000)\n        var timingInfo = CMSampleTimingInfo(duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1000), presentationTimeStamp: now, decodeTimeStamp: now)\n        var formatDescription: CMFormatDescription? = nil\n        CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault, imageBuffer: pixelBuffer, formatDescriptionOut: &formatDescription)\n        \n        let osStatus = CMSampleBufferCreateReadyWithImageBuffer(\n            allocator: kCFAllocatorDefault,\n            imageBuffer: pixelBuffer,\n            formatDescription: formatDescription!,\n            sampleTiming: &timingInfo,\n            sampleBufferOut: &sampleBuffer\n        )\n        \n        if osStatus != noErr {\n            let errorMessage = osStatusToString(status: osStatus)\n            print(\"osStatus error: \\(errorMessage)\")\n        }\n        \n        guard let buffer = sampleBuffer else {\n            print(\"Cannot create sample buffer\")\n            return nil\n        }\n        \n        CVPixelBufferUnlockBaseAddress(pixelBuffer, [])\n        \n        return buffer\n    }\n    \n    func osStatusToString(status: OSStatus) -> String {\n        switch status {\n        case kCMSampleBufferError_DataCanceled:\n            return \"kCMSampleBufferError_DataCanceled\"\n        case kCMSampleBufferError_DataFailed:\n            return \"kCMSampleBufferError_DataFailed\"\n        case kCMSampleBufferError_Invalidated:\n            return \"kCMSampleBufferError_Invalidated\"\n        case kCMSampleBufferError_InvalidMediaFormat:\n            return \"kCMSampleBufferError_InvalidMediaFormat\"\n        case kCMSampleBufferError_InvalidSampleData:\n            return \"kCMSampleBufferError_InvalidSampleData\"\n        case kCMSampleBufferError_InvalidMediaTypeForOperation:\n            return \"kCMSampleBufferError_InvalidMediaTypeForOperation\"\n        case kCMSampleBufferError_SampleTimingInfoInvalid:\n            return \"kCMSampleBufferError_SampleTimingInfoInvalid\"\n        case kCMSampleBufferError_CannotSubdivide:\n            return \"kCMSampleBufferError_CannotSubdivide\"\n        case kCMSampleBufferError_InvalidEntryCount:\n            return \"kCMSampleBufferError_InvalidEntryCount\"\n        case kCMSampleBufferError_ArrayTooSmall:\n            return \"kCMSampleBufferError_ArrayTooSmall\"\n        case kCMSampleBufferError_BufferHasNoSampleTimingInfo:\n            return \"kCMSampleBufferError_BufferHasNoSampleTimingInfo\"\n        case kCMSampleBufferError_BufferHasNoSampleSizes:\n            return \"kCMSampleBufferError_BufferHasNoSampleSizes\"\n        case kCMSampleBufferError_SampleIndexOutOfRange:\n            return \"kCMSampleBufferError_SampleIndexOutOfRange\"\n        case kCMSampleBufferError_BufferNotReady:\n            return \"kCMSampleBufferError_BufferNotReady\"\n        case kCMSampleBufferError_AlreadyHasDataBuffer:\n            return \"kCMSampleBufferError_AlreadyHasDataBuffer\"\n        case kCMSampleBufferError_RequiredParameterMissing:\n            return \"kCMSampleBufferError_RequiredParameterMissing\"\n        case kCMSampleBufferError_AllocationFailed:\n            return \"kCMSampleBufferError_AllocationFailed\"\n        default:\n            return \"Unknown error with code \\(status)\"\n        }\n    }\n    \n  }\n\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>audio</string>\n\t\t<string>fetch</string>\n\t\t<string>processing</string>\n\t</array>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/SampleBufferVideoCallView.swift",
    "content": "import UIKit\nimport AVKit\n\nclass SampleBufferVideoCallView: UIView {\n    override class var layerClass: AnyClass {\n        AVSampleBufferDisplayLayer.self\n    }\n\n    var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer {\n        layer as! AVSampleBufferDisplayLayer\n    }\n}\n\n"
  },
  {
    "path": "Picture-In-Picture/Lets-Build-OTPublisher/ViewController.swift",
    "content": "import UIKit\nimport OpenTok\nimport AVKit\n\nlet kWidgetRatio: CGFloat = 1.333\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\n\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    \n    var subscriber: OTSubscriber?\n    \n    let sampleBufferVideoCallView = SampleBufferVideoCallView()\n    \n    var pipController: AVPictureInPictureController! = nil\n    \n    var pipObservation: NSKeyValueObservation?\n    \n    var frame: CGRect!\n        \n    @IBOutlet weak var videoContainerView: UIView!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.width / kWidgetRatio)\n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    fileprivate func doConnect() {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Instantiates a subscriber for the given stream and asynchronously begins the\n     * process to begin receiving A/V content for this stream. Unlike doPublish,\n     * this method does not add the subscriber to the view hierarchy. Instead, we\n     * add the subscriber only after it has connected and begins receiving data.\n     */\n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            processError(error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        \n        let videoRender = ExampleVideoRender()\n        subscriber?.videoRender = videoRender\n        \n        session.subscribe(subscriber!, error: &error)\n        \n        // to allow subscriber sending videoframe even when the app is in background\n        NotificationCenter.default.removeObserver(subscriber,\n                                 name: UIApplication.willResignActiveNotification,\n                                 object: nil)\n        \n        //SubscriberView\n        let bufferDisplayLayer = videoRender.bufferDisplayLayer\n        bufferDisplayLayer.frame = frame\n        videoContainerView.layer.addSublayer(bufferDisplayLayer)\n        \n        pipSetup(videoRender: videoRender)\n        \n    }\n    \n    fileprivate func cleanupSubscriber() {\n        subscriber?.view?.removeFromSuperview()\n        subscriber = nil\n    }\n    \n    fileprivate func processError(_ error: OTError?) {\n        if let err = error {\n            showAlert(errorStr: err.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n    \n    fileprivate func pipSetup(videoRender: ExampleVideoRender) {\n        videoRender.pipBufferDisplayLayer = sampleBufferVideoCallView.sampleBufferDisplayLayer\n        videoRender.pipBufferDisplayLayer?.frame = frame\n        \n        let pipVideoCallViewController = AVPictureInPictureVideoCallViewController()\n        pipVideoCallViewController.preferredContentSize = CGSize(width: 640, height: 480)\n        pipVideoCallViewController.view.addSubview(sampleBufferVideoCallView)\n        \n        sampleBufferVideoCallView.translatesAutoresizingMaskIntoConstraints = false\n        let constraints = [\n            sampleBufferVideoCallView.leadingAnchor.constraint(equalTo: pipVideoCallViewController.view.leadingAnchor),\n            sampleBufferVideoCallView.trailingAnchor.constraint(equalTo: pipVideoCallViewController.view.trailingAnchor),\n            sampleBufferVideoCallView.topAnchor.constraint(equalTo: pipVideoCallViewController.view.topAnchor),\n            sampleBufferVideoCallView.bottomAnchor.constraint(equalTo: pipVideoCallViewController.view.bottomAnchor)\n        ]\n        NSLayoutConstraint.activate(constraints)\n          \n        sampleBufferVideoCallView.bounds = pipVideoCallViewController.view.frame\n            \n        \n        let contentSource = AVPictureInPictureController.ContentSource(\n            activeVideoCallSourceView: videoContainerView,\n                                    contentViewController: pipVideoCallViewController)\n        \n        pipController = AVPictureInPictureController(contentSource: contentSource)\n        pipController.canStartPictureInPictureAutomaticallyFromInline = true\n        pipController.delegate = self\n        \n    }\n    \n    @IBAction func startPiPTapped(_ sender: Any) {\n        pipController?.startPictureInPicture()\n    }\n    \n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscriber == nil {\n            doSubscribe(stream)\n        }\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n        print(\"Publishing\")\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n        if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {\n            cleanupSubscriber()\n        }\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\n// MARK: - AVPictureInPictureControllerDelegate\nextension ViewController:AVPictureInPictureControllerDelegate {\n    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {\n        print(\"\\(#function)\")\n        print(\"pip error: \\(error)\")\n    }\n    \n    func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {\n        print(\"\\(#function)\")\n    }\n    \n    func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {\n        print(\"\\(#function)\")\n    }\n}\n\n"
  },
  {
    "path": "Picture-In-Picture/Picture-In-Picture.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t6510F38796E0E44CC144B1FC /* Pods_Picture_In_Picture.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0685123659B7FADE5415B782 /* Pods_Picture_In_Picture.framework */; };\n\t\tEA65E79C2BEE08920060F604 /* SampleBufferVideoCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA65E79B2BEE08920060F604 /* SampleBufferVideoCallView.swift */; };\n\t\tF84DC3AF1D5C8BF400402BD9 /* ExampleVideoRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */; };\n\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BB1D5C8A150081846D /* AppDelegate.swift */; };\n\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86C64BD1D5C8A150081846D /* ViewController.swift */; };\n\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64BF1D5C8A150081846D /* Main.storyboard */; };\n\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C21D5C8A150081846D /* Assets.xcassets */; };\n\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F86C64C41D5C8A150081846D /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0685123659B7FADE5415B782 /* Pods_Picture_In_Picture.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Picture_In_Picture.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t1C7B8F7E8A4C1EBDCE25C96B /* Pods-Custom-Video-Driver.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Custom-Video-Driver.release.xcconfig\"; path = \"Target Support Files/Pods-Custom-Video-Driver/Pods-Custom-Video-Driver.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t81DA78E557B6CC9FACB46457 /* Pods-Custom-Video-Driver.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Custom-Video-Driver.debug.xcconfig\"; path = \"Target Support Files/Pods-Custom-Video-Driver/Pods-Custom-Video-Driver.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t859ECA77BD688D6216193F82 /* Pods-Picture-In-Picture.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Picture-In-Picture.debug.xcconfig\"; path = \"Target Support Files/Pods-Picture-In-Picture/Pods-Picture-In-Picture.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tB049AB366F84CA3525E1BF9C /* Pods-Picture-In-Picture.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Picture-In-Picture.release.xcconfig\"; path = \"Target Support Files/Pods-Picture-In-Picture/Pods-Picture-In-Picture.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tEA017C342BF45C040010889B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };\n\t\tEA65E79B2BEE08920060F604 /* SampleBufferVideoCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleBufferVideoCallView.swift; sourceTree = \"<group>\"; };\n\t\tF84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleVideoRender.swift; sourceTree = \"<group>\"; };\n\t\tF86C64B81D5C8A150081846D /* Picture-In-Picture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Picture-In-Picture.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF86C64C01D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tF86C64C51D5C8A150081846D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tF86C64C71D5C8A150081846D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF86C64B51D5C8A150081846D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t6510F38796E0E44CC144B1FC /* Pods_Picture_In_Picture.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t026262AB90854995BA336336 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tEA017C342BF45C040010889B /* Security.framework */,\n\t\t\t\t0685123659B7FADE5415B782 /* Pods_Picture_In_Picture.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5BC0EA00F0A0A1C324E1C486 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81DA78E557B6CC9FACB46457 /* Pods-Custom-Video-Driver.debug.xcconfig */,\n\t\t\t\t1C7B8F7E8A4C1EBDCE25C96B /* Pods-Custom-Video-Driver.release.xcconfig */,\n\t\t\t\t859ECA77BD688D6216193F82 /* Pods-Picture-In-Picture.debug.xcconfig */,\n\t\t\t\tB049AB366F84CA3525E1BF9C /* Pods-Picture-In-Picture.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64AF1D5C8A150081846D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64BA1D5C8A150081846D /* Lets-Build-OTPublisher */,\n\t\t\t\tF86C64B91D5C8A150081846D /* Products */,\n\t\t\t\t5BC0EA00F0A0A1C324E1C486 /* Pods */,\n\t\t\t\t026262AB90854995BA336336 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64B91D5C8A150081846D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64B81D5C8A150081846D /* Picture-In-Picture.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64BA1D5C8A150081846D /* Lets-Build-OTPublisher */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64BB1D5C8A150081846D /* AppDelegate.swift */,\n\t\t\t\tF86C64BD1D5C8A150081846D /* ViewController.swift */,\n\t\t\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */,\n\t\t\t\tF86C64C21D5C8A150081846D /* Assets.xcassets */,\n\t\t\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */,\n\t\t\t\tF86C64C71D5C8A150081846D /* Info.plist */,\n\t\t\t\tF84DC3AE1D5C8BF400402BD9 /* ExampleVideoRender.swift */,\n\t\t\t\tEA65E79B2BEE08920060F604 /* SampleBufferVideoCallView.swift */,\n\t\t\t);\n\t\t\tpath = \"Lets-Build-OTPublisher\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF86C64B71D5C8A150081846D /* Picture-In-Picture */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"Picture-In-Picture\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE666A80B93844C80118AD2EB /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tF86C64B41D5C8A150081846D /* Sources */,\n\t\t\t\tF86C64B51D5C8A150081846D /* Frameworks */,\n\t\t\t\tF86C64B61D5C8A150081846D /* Resources */,\n\t\t\t\t5269D88C572E1907C803A5F4 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Picture-In-Picture\";\n\t\t\tproductName = \"Lets-Build-OTPublisher\";\n\t\t\tproductReference = F86C64B81D5C8A150081846D /* Picture-In-Picture.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF86C64B01D5C8A150081846D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0730;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF86C64B71D5C8A150081846D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = PR6C39UQ38;\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"Picture-In-Picture\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F86C64AF1D5C8A150081846D;\n\t\t\tproductRefGroup = F86C64B91D5C8A150081846D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF86C64B71D5C8A150081846D /* Picture-In-Picture */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF86C64B61D5C8A150081846D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF86C64C61D5C8A150081846D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tF86C64C31D5C8A150081846D /* Assets.xcassets in Resources */,\n\t\t\t\tF86C64C11D5C8A150081846D /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t5269D88C572E1907C803A5F4 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Picture-In-Picture/Pods-Picture-In-Picture-resources.sh\",\n\t\t\t\t\"${PODS_ROOT}/OTXCFramework/OpenTok.xcframework/ios-arm64/OpenTok.framework/selfie_segmentation.tflite\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/selfie_segmentation.tflite\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Picture-In-Picture/Pods-Picture-In-Picture-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tE666A80B93844C80118AD2EB /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Picture-In-Picture-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF86C64B41D5C8A150081846D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tEA65E79C2BEE08920060F604 /* SampleBufferVideoCallView.swift in Sources */,\n\t\t\t\tF86C64BE1D5C8A150081846D /* ViewController.swift in Sources */,\n\t\t\t\tF86C64BC1D5C8A150081846D /* AppDelegate.swift in Sources */,\n\t\t\t\tF84DC3AF1D5C8BF400402BD9 /* ExampleVideoRender.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tF86C64BF1D5C8A150081846D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C01D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF86C64C41D5C8A150081846D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tF86C64C51D5C8A150081846D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF86C64C81D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64C91D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF86C64CB1D5C8A150081846D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 859ECA77BD688D6216193F82 /* Pods-Picture-In-Picture.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = PR6C39UQ38;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"COCOAPODS=1\",\n\t\t\t\t\t\"GLES_SILENCE_DEPRECATION=1\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Lets-Build-OTPublisher/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.picture-in-picture\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF86C64CC1D5C8A150081846D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B049AB366F84CA3525E1BF9C /* Pods-Picture-In-Picture.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = PR6C39UQ38;\n\t\t\t\tINFOPLIST_FILE = \"Lets-Build-OTPublisher/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.picture-in-picture\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF86C64B31D5C8A150081846D /* Build configuration list for PBXProject \"Picture-In-Picture\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64C81D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64C91D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF86C64CA1D5C8A150081846D /* Build configuration list for PBXNativeTarget \"Picture-In-Picture\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF86C64CB1D5C8A150081846D /* Debug */,\n\t\t\t\tF86C64CC1D5C8A150081846D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F86C64B01D5C8A150081846D /* Project object */;\n}\n"
  },
  {
    "path": "Picture-In-Picture/Picture-In-Picture.xcodeproj/xcshareddata/xcschemes/Picture-In-Picture.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n               BuildableName = \"Picture-In-Picture.app\"\n               BlueprintName = \"Picture-In-Picture\"\n               ReferencedContainer = \"container:Picture-In-Picture.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Picture-In-Picture.app\"\n            BlueprintName = \"Picture-In-Picture\"\n            ReferencedContainer = \"container:Picture-In-Picture.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Picture-In-Picture.app\"\n            BlueprintName = \"Picture-In-Picture\"\n            ReferencedContainer = \"container:Picture-In-Picture.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F86C64B71D5C8A150081846D\"\n            BuildableName = \"Picture-In-Picture.app\"\n            BlueprintName = \"Picture-In-Picture\"\n            ReferencedContainer = \"container:Picture-In-Picture.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Picture-In-Picture/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Picture-In-Picture' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Picture-In-Picture/README.md",
    "content": "Picture In Picture Sample App\n==================================\n\nThis project uses the custom video render features in the OpenTok iOS SDK.\nBy the end of a code review, you should have a basic understanding how to implement\nPicture-In-Picture for the subscribed stream.\n\nNote that this sample application is not supported in the XCode iOS Simulator\nbecause the Picture-In-Picture only works on real device.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\n\n### ExampleVideoRender\n\nOTSubscriber needs an instance supporting the\n`OTVideoRender` protocol to display video contents. In short, the instance\nID that is set to the `videoRender` property will receive YUV frames (I420) \nas they are received (subscriber).\n\nIn this example we get the YUV frames from `videoRender`,\nand convert the frames to CMSampleBuffer.\nRefer to function `createSampleBufferWithVideoFrame` for YUV frames to CMSampeBuffer conversion.\n\nThen, draw the video stream on the PIP by adding the CMSampleBuffer into PIP \n`sampleBufferDisplayLayer`\n\n\n### ViewController\n\nSetup a PIP controller is well documented in [apple doc][1]. \n\nTo see sample in action, you need to add a publisher (which will display as a subscriber), either run the app a second time in an iOS device or use the OpenTok Playground to connect to the session in a supported web browser (Chrome, Firefox, or Internet Explorer 10-11).\n\n\n[1]: https://developer.apple.com/documentation/avkit/adopting-picture-in-picture-for-video-calls\n"
  },
  {
    "path": "README.md",
    "content": ":warning: **This repository has been deprecated in favour of the [Vonage iOS samples](https://github.com/Vonage/vonage-video-ios-sdk-samples)** :warning:\n\n[![Build Status](https://travis-ci.org/opentok/opentok-ios-sdk-samples-swift.svg?branch=main)](https://travis-ci.org/opentok/opentok-ios-sdk-samples-swift)\n\nOpenTok iOS SDK Samples\n=======================\n\nThis repository is meant to provide some examples for you to better understand\nthe features of the OpenTok iOS SDK. The sample applications are meant to be\nused with the latest version of the\n[OpenTok iOS SDK](https://tokbox.com/developer/sdks/ios/). Feel free to copy and\nmodify the source code herein for your own projects. Please consider sharing\nyour modifications with us, especially if they might benefit other developers\nusing the OpenTok iOS SDK. See the [License](LICENSE) for more information.\n\nQuick Start\n-----------\n\n 1. Get values for your OpenTok **API key**, **session ID**, and **token**.\n    See [Obtaining OpenTok Credentials](#obtaining-opentok-credentials)\n    for important information.\n \n 1. Install CocoaPods as described in [CocoaPods Getting Started](https://guides.cocoapods.org/using/getting-started.html#getting-started).\n \n 1. In Terminal, `cd` to your project directory and type `pod install`.\n \n 1. Reopen your project in Xcode using the new `.xcworkspace` file.\n \n 1. In the ViewController.swift file, replace the following empty strings\n    with the corresponding API key, session ID, and token values:\n \n     ```swift\n     // *** Fill the following variables using your own Project info  ***\n     // ***            https://tokbox.com/account/#/                  ***\n     // Replace with your OpenTok API key\n     let kApiKey = \"\"\n     // Replace with your generated session ID\n     let kSessionId = \"\"\n     // Replace with your generated token\n     let kToken = \"\"\n     ```\n \n 1. Use Xcode to build and run the app on an iOS simulator or device.\n\nWhat's Inside\n-------------\n\n**Basic Video Chat** -- This basic application demonstrates a short path to\ngetting started with the OpenTok iOS SDK.\n\n**Custom Audio Driver** -- This project demonstrate how to use an external audio\nsource with the OpenTok SDK. This project utilizes CoreAudio and the AUGraph API\nto create an audio session suitable for voice and video communications.\n\n**Custom Video Driver** -- This project provides classes that implement\nthe OTVideoCapture and OTVideoRender interfaces of the core Publisher and\nSubscriber classes. Using these modules, we can see the basic workflow of\nsourcing video frames from the device camera in and out of OpenTok, via the\nOTPublisherKit and OTSubscriberKit interfaces.\n\n**Live Photo Capture** -- This project extends the video capture module implemented\nin project 2, and demonstrates how the AVFoundation media capture APIs can be used to\nsimultaneously stream video and capture high-resolution photos from the same camera.\n\n**Screen Sharing** -- This project demonstrates how to use a custom video capturer\nto publish a stream that uses a UI view (instead of a camera) as the video source.\n\n**Simple Multiparty** -- This project demonstrates how to use the OpenTok iOS SDK\nfor a multi-party call. The application publishes audio/video from an iOS device and \ncan connect to multiple subscribers. However it shows only one subscriber video at a \ntime due to CPU limitations on iOS devices.\n\n**Picture In Picture** -- This project demonstrates how to implement Picture In Picture on a \nsubcribed video stream.\n\n**FrameMetadata** -- This project shows how to set metadata (limited to 32 bytes) to a video frame, as well as how to read metadata from a video frame.\n\t\n## Obtaining OpenTok Credentials\n\nTo use the OpenTok platform you need a session ID, token, and API key.\nYou can get these values by creating a project on your [OpenTok Account\nPage](https://tokbox.com/account/) and scrolling down to the Project Tools\nsection of your Project page. For production deployment, you must generate the\nsession ID and token values using one of the [OpenTok Server\nSDKs](https://tokbox.com/developer/sdks/server/).\n\n## Development and Contributing\n\nInterested in contributing? We :heart: pull requests! See the \n[Contribution](CONTRIBUTING.md) guidelines.\n\n## Getting Help\n\nWe love to hear from you so if you have questions, comments or find a bug in the project, let us know! You can either:\n\n- Open an issue on this repository\n- See <https://support.tokbox.com/> for support options\n- Tweet at us! We're [@VonageDev](https://twitter.com/VonageDev) on Twitter\n- Or [join the Vonage Developer Community Slack](https://developer.nexmo.com/community/slack)\n\n## Further Reading\n\n- Check out the Developer Documentation at <https://tokbox.com/developer/>\n"
  },
  {
    "path": "Screen-Sharing/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Screen-Sharing' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Screen-Sharing/README.md",
    "content": "Screen Sharing Sample App\n=========================\n\nThis project shows how to use OpenTok iOS SDK to publish a stream that uses a\nUIView, instead of a camera, as the video source.\n\nSee the \"Custom Video Driver\" sample code for basic information on using a\ncustom video capturer.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nThe main storyboard includes a UITextView object that is referenced in the\nViewController.swift file as the `timeDisplay` property. The `viewDidLoad` method\n(in  ViewController.swift) sets up a timer that updates this text field periodically\nto display the Date timestamp. This example will use this text field's view as\nthe video source for the published stream.\n\nvideoFrame = OTVideoFrame(format:format)\n\n\nUpon connecting to the OpenTok session, the app instantiates an OTPublisherKit\nobject, and calls its `setCapturer()` method to set a custom video capturer.\nThis custom video capturer is defined by the ScreenCapture class:\n\n    func doPublish() {\n        defer {\n            process(error: error)\n        }\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        publisher = OTPublisher(delegate: self, settings: settings)\n        publisher?.videoType = .screen\n        publisher?.audioFallbackEnabled = false\n        \n        capturer = ScreenCapturer(withView: view)\n        publisher?.videoCapture = capturer!.videoCapture()\n        \n        var error: OTError? = nil\n        session.publish(publisher!, error: &error)\n    }\n\nNote that the call to the `OTPublisher.videoType` method sets the\nvideo type of the published stream to `OTPublisherKitVideoTypeScreen`. This\noptimizes the video encoding for screen sharing. It is recommended to use a low\nframe rate (5 frames per second or lower) with this video type. When using the\nscreen video type in a session that uses the [OpenTok Media\nServer](https://tokbox.com/opentok/tutorials/create-session/#media-mode), the\naudio-only fallback feature is disabled, so that the video does not drop out in\nsubscribers. (However, the publisher in this sample does not publish audio.)\n\nThe code instantiates a ScreenCapture object and passes it into the\n`publisher.videoCapture` method. This sets the custom video capturer for\nthe publisher The ScreenCapture class implements the OTVideoCapture protocol,\ndefined in the OpenTok iOS SDK.\n\nThe implementation of the `OTVideoCapture.initCapture()` method sets up a timer\nthat periodically gets a UIImage based on a screenshot of the main view\n(`self.view`):\n\n\tlet screen = self.screenShoot()\n\tlet padded = self.resizeAndPad(image: screen)\n\tself.consume(frame: padded)\n\nThe `screenshot()` method simply returns a UIImage representation of\n`self.view`.\n\nThe `viewDidLoad` method initialized a OTVideoFormat and OTVideoFrame object to\nbe used by the custom video capturer:\n\n    let format = OTVideoFormat()\n    format.pixelFormat = .argb\n\nThe `consumeFrame()` method sets up properties of the current video frame:\n\n\tlet timeStamp = mach_absolute_time()\n\tlet time = CMTime(seconds: Double(timeStamp), preferredTimescale: 1000)\n\tlet ref = pixelBuffer(fromCGImage: frame)\n        \n\tCVPixelBufferLockBaseAddress(ref, CVPixelBufferLockFlags(rawValue: 0))\n        \n\tvideoFrame?.timestamp = time\n\tvideoFrame?.format.estimatedCaptureDelay = 100\n\tvideoFrame?.orientation = .up\n        \n\tvideoFrame?.clearPlanes()\n\tvideoFrame?.planes.addPointer(CVPixelBufferGetBaseAddress(ref))\n\tvideoCaptureConsumer.consumeFrame(videoFrame)\n\nThe `consumeFrame()` method then calls the\n`self.videoCaptureConsumer.consumeFrame(videoFrame)` method:\n\n    videoCaptureConsumer.consumeFrame(videoFrame)\n\nThe `videoCaptureConsumer` property of the OTVideoCapturer object is defined by\nthe OTVideoCaptureConsumer protocol. Its `consumeFrame()` method sets a video\nframe to be published by the OTPublisherKit object.\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  5.Screen-Sharing\n//\n//  Created by Roberto Perez Cubero on 23/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n}\n\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11201\" systemVersion=\"16A323\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11161\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"__Screen_Sharing\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"logo_opentok_registered.png\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s78-ND-ty8\"/>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"00:00:00.00\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BD3-dG-MwG\">\n                                <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"21\"/>\n                                <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"BD3-dG-MwG\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"4ca-qj-7SX\"/>\n                            <constraint firstItem=\"s78-ND-ty8\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" constant=\"154\" id=\"BFo-B7-x97\"/>\n                            <constraint firstItem=\"s78-ND-ty8\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"gJy-c0-UIQ\"/>\n                            <constraint firstItem=\"BD3-dG-MwG\" firstAttribute=\"top\" secondItem=\"s78-ND-ty8\" secondAttribute=\"bottom\" constant=\"46\" id=\"xHi-jI-7LN\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"timeText\" destination=\"BD3-dG-MwG\" id=\"thq-u7-Jgi\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"logo_opentok_registered.png\" width=\"344\" height=\"103\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/ScreenCapturer.swift",
    "content": "//\n//  ScreenCapturer.swift\n//  5.Screen-Sharing\n//\n//  Created by Roberto Perez Cubero on 23/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport Foundation\nimport OpenTok\n\nclass ScreenCapturer: NSObject, OTVideoCapture {\n    var videoContentHint: OTVideoContentHint\n    var videoCaptureConsumer: OTVideoCaptureConsumer?\n\n    let MAX_EDGE_SIZE_LIMIT: CGFloat = 1280.0\n    let EDGE_DIMENSION_COMMON_FACTOR: CGFloat = 16.0\n    \n    fileprivate let captureView: UIView\n    fileprivate let captureQueue = DispatchQueue(label: \"ot-screen-capture\")\n    fileprivate var timer: DispatchSourceTimer\n    fileprivate var capturing: Bool = false\n    fileprivate var videoFrame = OTVideoFrame(format: OTVideoFormat(argbWithWidth: 0, height: 0))\n    fileprivate var pixelBuffer: CVPixelBuffer?\n\n    private enum TimerState {\n        case notStarted\n        case started\n        case suspended\n        case resumed\n        case canceled\n    }\n    private var timerState: TimerState = .notStarted\n    \n    init(withView: UIView) {\n        self.videoContentHint = .none\n        captureView = withView        \n        timer = DispatchSource.makeTimerSource(flags: .strict, queue: captureQueue)\n    }\n    fileprivate func screenShoot() -> UIImage {\n        UIGraphicsBeginImageContextWithOptions(captureView.bounds.size, false, 0.0)\n        captureView.drawHierarchy(in: captureView.bounds, afterScreenUpdates: false)\n        let image = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return image!\n    }\n    \n    fileprivate func resizeAndPad(image img: UIImage) -> CGImage {\n        let source = img.cgImage!\n        let size = CGSize(width: source.width, height: source.height)\n        let destSizes = dimensions(forInputSize: size)\n        \n        UIGraphicsBeginImageContextWithOptions(destSizes.container, false, 1.0)\n        let ctx = UIGraphicsGetCurrentContext()\n        \n        ctx?.scaleBy(x: 1, y: -1)\n        ctx?.translateBy(x: 0, y: -destSizes.rect.size.height)\n        ctx?.draw(source, in: destSizes.rect)\n        \n        let newImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        \n        return (newImage?.cgImage)!\n    }\n    \n    fileprivate func consume(frame: CGImage) {\n        checkSize(forImage: frame)\n        \n        if !capturing {\n            return\n        }\n        \n        let timeStamp = mach_absolute_time()\n        let time = CMTime(seconds: Double(timeStamp), preferredTimescale: 1000)\n        let ref = pixelBuffer(fromCGImage: frame)\n        \n        CVPixelBufferLockBaseAddress(ref, CVPixelBufferLockFlags(rawValue: 0))\n        \n        videoFrame.timestamp = time\n        //videoFrame?.format.estimatedFramesPerSecond =\n        videoFrame.format?.estimatedCaptureDelay = 100\n        videoFrame.orientation = .up\n        \n        videoFrame.clearPlanes()\n        videoFrame.planes?.addPointer(CVPixelBufferGetBaseAddress(ref))        \n        videoCaptureConsumer?.consumeFrame(videoFrame)\n        \n        CVPixelBufferUnlockBaseAddress(ref, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))\n    }\n    \n    // MARK: - OTVideoCapture protocol\n    func initCapture() {\n        timer.setEventHandler {\n            DispatchQueue.main.async {\n                let screen = self.screenShoot()\n                let padded = self.resizeAndPad(image: screen)\n                self.consume(frame: padded)\n            }\n        }\n        timer.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.milliseconds(100))\n        timerState = .started\n    }\n    \n    func start() -> Int32 {\n        capturing = true\n        captureQueue.sync {\n            timerResume()\n        }\n        return 0\n    }\n    \n    func stop() -> Int32 {\n        capturing = false\n        captureQueue.sync {\n            timerSuspend()\n        }\n        return 0\n    }\n    \n    func releaseCapture() {\n        timerCancel()\n    }\n    \n    func isCaptureStarted() -> Bool {\n        return capturing\n    }\n    \n    func captureSettings(_ videoFormat: OTVideoFormat) -> Int32 {\n        videoFormat.pixelFormat = .ARGB\n        return 0\n    }\n\n    func timerResume() {\n        if timerState == .resumed {\n            return\n        }\n        timerState = .resumed\n        timer.resume()\n    }\n    \n    func timerSuspend() {\n        if timerState == .suspended {\n            return\n        }\n        timerState = .suspended\n        timer.suspend()\n    }\n\n    func timerCancel() {\n        timer.cancel()\n        timerState = .canceled\n        timer.resume()\n    }\n}\n\n// MARK: - Image Utils\nextension ScreenCapturer {\n    fileprivate func pixelBuffer(fromCGImage img: CGImage) -> CVPixelBuffer {\n        let frameSize = CGSize(width: img.width, height: img.height)\n        CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))\n        let pxdata = CVPixelBufferGetBaseAddress(pixelBuffer!)\n        \n        let rgbColorSpace = CGColorSpaceCreateDeviceRGB()\n        let context =\n            CGContext(data: pxdata,\n                      width: Int(frameSize.width),\n                      height: Int(frameSize.height),\n                      bitsPerComponent: 8,\n                      bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!),\n                      space: rgbColorSpace,\n                      bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue)\n        \n        \n        context?.draw(img, in: CGRect(x: 0, y: 0, width: img.width, height: img.height))\n        \n        CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))\n        \n        return pixelBuffer!;\n    }\n    \n    fileprivate func dimensions(forInputSize size: CGSize) -> (container: CGSize, rect: CGRect) {\n        let aspect = size.width / size.height\n        \n        var destContainer = CGSize(width: size.width, height: size.height)\n        var destFrame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height))\n        \n        // if image is wider than tall and width breaks edge size limit\n        if MAX_EDGE_SIZE_LIMIT < size.width && aspect >= 1.0 {\n            destContainer.width = MAX_EDGE_SIZE_LIMIT\n            destContainer.height = destContainer.width / aspect\n            if 0 != fmod(destContainer.height, EDGE_DIMENSION_COMMON_FACTOR) {\n                destContainer.height +=\n                    (EDGE_DIMENSION_COMMON_FACTOR - fmod(destContainer.height, EDGE_DIMENSION_COMMON_FACTOR))\n            }\n            destFrame.size.width = destContainer.width\n            destFrame.size.height = destContainer.width / aspect\n        }\n        \n        // ensure the dimensions of the resulting container are safe\n        if (fmod(destContainer.width, EDGE_DIMENSION_COMMON_FACTOR) != 0) {\n            let remainder = fmod(destContainer.width,\n                                 EDGE_DIMENSION_COMMON_FACTOR);\n            // increase the edge size only if doing so does not break the edge limit\n            if (destContainer.width + (EDGE_DIMENSION_COMMON_FACTOR - remainder) >\n                MAX_EDGE_SIZE_LIMIT)\n            {\n                destContainer.width -= remainder;\n            } else {\n                destContainer.width += EDGE_DIMENSION_COMMON_FACTOR - remainder;\n            }\n        }\n        // ensure the dimensions of the resulting container are safe\n        if (fmod(destContainer.height, EDGE_DIMENSION_COMMON_FACTOR) != 0) {\n            let remainder = fmod(destContainer.height,\n                                 EDGE_DIMENSION_COMMON_FACTOR);\n            // increase the edge size only if doing so does not break the edge limit\n            if (destContainer.height + (EDGE_DIMENSION_COMMON_FACTOR - remainder) >\n                MAX_EDGE_SIZE_LIMIT)\n            {\n                destContainer.height -= remainder;\n            } else {\n                destContainer.height += EDGE_DIMENSION_COMMON_FACTOR - remainder;\n            }\n        }\n        \n        destFrame.size.width = destContainer.width;\n        destFrame.size.height = destContainer.height;\n        \n        // scale and recenter source image to fit in destination container\n        if (aspect > 1.0) {\n            destFrame.origin.x = 0;\n            destFrame.origin.y =\n                (destContainer.height - destContainer.width) / 2;\n            destFrame.size.width = destContainer.width;\n            destFrame.size.height =\n                destContainer.width / aspect;\n        } else {\n            destFrame.origin.x =\n                (destContainer.width - destContainer.width) / 2;\n            destFrame.origin.y = 0;\n            destFrame.size.height = destContainer.height;\n            destFrame.size.width =\n                destContainer.height * aspect;\n        }\n        \n        return (destContainer, destFrame)\n    }\n    \n    fileprivate func checkSize(forImage img: CGImage) {\n        guard let frameFormat = videoFrame.format, frameFormat.imageHeight != UInt32(img.height),\n            frameFormat.imageWidth != UInt32(img.width)\n            else {\n                return\n        }\n        \n        frameFormat.bytesPerRow.removeAllObjects()\n        frameFormat.bytesPerRow.addObjects(from: [img.width * 4])\n        frameFormat.imageWidth = UInt32(img.width)\n        frameFormat.imageHeight = UInt32(img.height)\n        \n        let frameSize = CGSize(width: img.width, height: img.height)\n        let options: Dictionary<String, Bool> = [\n            kCVPixelBufferCGImageCompatibilityKey as String: false,\n            kCVPixelBufferCGBitmapContextCompatibilityKey as String: false\n        ]\n        \n        let status = CVPixelBufferCreate(kCFAllocatorDefault,\n                                         Int(frameSize.width),\n                                         Int(frameSize.height),\n                                         kCVPixelFormatType_32ARGB,\n                                         options as CFDictionary,\n                                         &pixelBuffer)\n        \n        assert(status == kCVReturnSuccess && pixelBuffer != nil)\n    }\n}\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  Screen-Sharing\n//\n//  Created by Roberto Perez Cubero on 11/08/16.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\nlet kWidgetHeight = 240\nlet kWidgetWidth = 320\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\n\nclass ViewController: UIViewController {\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    var publisher: OTPublisher?\n    var subscriber: OTSubscriber?\n    var capturer: ScreenCapturer?\n    \n    @IBOutlet var timeText: UILabel!\n\n    fileprivate let formatter: DateFormatter = {\n        let fmt = DateFormatter()\n        fmt.dateStyle = .short\n        fmt.timeStyle = .long\n        return fmt\n    }()\n    \n    fileprivate func updateTimeLabel() {\n        let text = formatter.string(from: Date())\n        timeText.text = text\n    }\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        Timer.scheduledTimer(withTimeInterval: TimeInterval(1), repeats: true) { _ in\n            self.updateTimeLabel()\n        }\n        doConnect()\n    }\n    \n    /**\n     * Asynchronously begins the session connect process. Some time later, we will\n     * expect a delegate method to call us back with the results of this action.\n     */\n    private func doConnect() {\n        var error: OTError?\n        defer {\n            process(error: error)\n        }        \n        session.connect(withToken: kToken, error: &error)\n    }\n    \n    /**\n     * Sets up an instance of OTPublisher to use with this session. OTPubilsher\n     * binds to the device camera and microphone, and will provide A/V streams\n     * to the OpenTok session.\n     */\n    fileprivate func doPublish() {\n        var error: OTError? = nil\n        defer {\n            process(error: error)\n        }\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        publisher = OTPublisher(delegate: self, settings: settings)\n        publisher?.videoType = .screen\n        publisher?.audioFallbackEnabled = false\n        \n        capturer = ScreenCapturer(withView: view)\n        publisher?.videoCapture = capturer\n        publisher?.videoCapture?.videoContentHint = .text\n        \n        session.publish(publisher!, error: &error)\n    }\n    \n    fileprivate func doSubscribe(_ stream: OTStream) {\n        var error: OTError?\n        defer {\n            process(error: error)\n        }\n        subscriber = OTSubscriber(stream: stream, delegate: self)\n        \n        session.subscribe(subscriber!, error: &error)\n    }\n    \n    fileprivate func process(error err: OTError?) {\n        if let e = err {\n            showAlert(errorStr: e.localizedDescription)\n        }\n    }\n    \n    fileprivate func showAlert(errorStr err: String) {\n        DispatchQueue.main.async {\n            let controller = UIAlertController(title: \"Error\", message: err, preferredStyle: .alert)\n            controller.addAction(UIAlertAction(title: \"Ok\", style: .default, handler: nil))\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        doSubscribe(stream)\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        print(\"Subscriber connected\")\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA05375E81EB1636800645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375DE1EB1636800645696 /* AppDelegate.swift */; };\n\t\tA05375E91EB1636800645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05375DF1EB1636800645696 /* Assets.xcassets */; };\n\t\tA05375EA1EB1636800645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375E01EB1636800645696 /* LaunchScreen.storyboard */; };\n\t\tA05375EB1EB1636800645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375E21EB1636800645696 /* Main.storyboard */; };\n\t\tA05375ED1EB1636800645696 /* logo_opentok_registered.png in Resources */ = {isa = PBXBuildFile; fileRef = A05375E51EB1636800645696 /* logo_opentok_registered.png */; };\n\t\tA05375EE1EB1636800645696 /* ScreenCapturer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375E61EB1636800645696 /* ScreenCapturer.swift */; };\n\t\tA05375EF1EB1636800645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375E71EB1636800645696 /* ViewController.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05375DE1EB1636800645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05375DF1EB1636800645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05375E11EB1636800645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375E31EB1636800645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375E41EB1636800645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05375E51EB1636800645696 /* logo_opentok_registered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo_opentok_registered.png; sourceTree = \"<group>\"; };\n\t\tA05375E61EB1636800645696 /* ScreenCapturer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenCapturer.swift; sourceTree = \"<group>\"; };\n\t\tA05375E71EB1636800645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF8DE15B31D951F9200EFFA79 /* Screen-Sharing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Screen-Sharing.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF8DE15B01D951F9200EFFA79 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA05375DD1EB1636800645696 /* Screen-Sharing */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375DE1EB1636800645696 /* AppDelegate.swift */,\n\t\t\t\tA05375DF1EB1636800645696 /* Assets.xcassets */,\n\t\t\t\tA05375E01EB1636800645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05375E21EB1636800645696 /* Main.storyboard */,\n\t\t\t\tA05375E41EB1636800645696 /* Info.plist */,\n\t\t\t\tA05375E51EB1636800645696 /* logo_opentok_registered.png */,\n\t\t\t\tA05375E61EB1636800645696 /* ScreenCapturer.swift */,\n\t\t\t\tA05375E71EB1636800645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Screen-Sharing\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF8DE15AA1D951F9200EFFA79 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375DD1EB1636800645696 /* Screen-Sharing */,\n\t\t\t\tF8DE15B41D951F9200EFFA79 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF8DE15B41D951F9200EFFA79 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF8DE15B31D951F9200EFFA79 /* Screen-Sharing.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF8DE15B21D951F9200EFFA79 /* Screen-Sharing */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F8DE15C51D951F9200EFFA79 /* Build configuration list for PBXNativeTarget \"Screen-Sharing\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF8DE15AF1D951F9200EFFA79 /* Sources */,\n\t\t\t\tF8DE15B01D951F9200EFFA79 /* Frameworks */,\n\t\t\t\tF8DE15B11D951F9200EFFA79 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Screen-Sharing\";\n\t\t\tproductName = \"4.Screen-Sharing\";\n\t\t\tproductReference = F8DE15B31D951F9200EFFA79 /* Screen-Sharing.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF8DE15AB1D951F9200EFFA79 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0800;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF8DE15B21D951F9200EFFA79 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F8DE15AE1D951F9200EFFA79 /* Build configuration list for PBXProject \"Screen-Sharing\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F8DE15AA1D951F9200EFFA79;\n\t\t\tproductRefGroup = F8DE15B41D951F9200EFFA79 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF8DE15B21D951F9200EFFA79 /* Screen-Sharing */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF8DE15B11D951F9200EFFA79 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375ED1EB1636800645696 /* logo_opentok_registered.png in Resources */,\n\t\t\t\tA05375EB1EB1636800645696 /* Main.storyboard in Resources */,\n\t\t\t\tA05375E91EB1636800645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA05375EA1EB1636800645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF8DE15AF1D951F9200EFFA79 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375EF1EB1636800645696 /* ViewController.swift in Sources */,\n\t\t\t\tA05375E81EB1636800645696 /* AppDelegate.swift in Sources */,\n\t\t\t\tA05375EE1EB1636800645696 /* ScreenCapturer.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05375E01EB1636800645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375E11EB1636800645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375E21EB1636800645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375E31EB1636800645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF8DE15C31D951F9200EFFA79 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF8DE15C41D951F9200EFFA79 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF8DE15C61D951F9200EFFA79 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Screen-Sharing/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Screen-Sharing\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE = \"a59dc7c3-af3f-40f4-9a52-be0289761eb4\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF8DE15C71D951F9200EFFA79 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Screen-Sharing/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Screen-Sharing\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF8DE15AE1D951F9200EFFA79 /* Build configuration list for PBXProject \"Screen-Sharing\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF8DE15C31D951F9200EFFA79 /* Debug */,\n\t\t\t\tF8DE15C41D951F9200EFFA79 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF8DE15C51D951F9200EFFA79 /* Build configuration list for PBXNativeTarget \"Screen-Sharing\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF8DE15C61D951F9200EFFA79 /* Debug */,\n\t\t\t\tF8DE15C71D951F9200EFFA79 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F8DE15AB1D951F9200EFFA79 /* Project object */;\n}\n"
  },
  {
    "path": "Screen-Sharing/Screen-Sharing.xcodeproj/xcshareddata/xcschemes/Screen-Sharing.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F8DE15B21D951F9200EFFA79\"\n               BuildableName = \"Screen-Sharing.app\"\n               BlueprintName = \"Screen-Sharing\"\n               ReferencedContainer = \"container:Screen-Sharing.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F8DE15B21D951F9200EFFA79\"\n            BuildableName = \"Screen-Sharing.app\"\n            BlueprintName = \"Screen-Sharing\"\n            ReferencedContainer = \"container:Screen-Sharing.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F8DE15B21D951F9200EFFA79\"\n            BuildableName = \"Screen-Sharing.app\"\n            BlueprintName = \"Screen-Sharing\"\n            ReferencedContainer = \"container:Screen-Sharing.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F8DE15B21D951F9200EFFA79\"\n            BuildableName = \"Screen-Sharing.app\"\n            BlueprintName = \"Screen-Sharing\"\n            ReferencedContainer = \"container:Screen-Sharing.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Signals/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Signals' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Signals/README.md",
    "content": "Signaling Sample App\n===============================\n\nThe Signaling app is a very simple application meant to get a new developer\nstarted using the signaling features of OpenTok iOS SDK.\n\nQuick Start\n-----------\n\nTo use this application:\n\n1. Follow the instructions in the [Quick Start](../README.md#quick-start)\n   section of the main README file for this repository.\n\n   Among other things, you need to set values for the `kApiKey`, `kSessionId`,\n   and `kToken` constants. See [Obtaining OpenTok\n   Credentials](../README.md#obtaining-opentok-credentials)\n   in the main README file for the repository.\n\n2. When you run the application, an OpenTok session is created . Signaling only needs\n   OTConnection(s).\n\n3. Run the app on a second client. You can do this by deploying the app to an\n   iOS device and testing it in the simulator at the same time. \n\n   \nApplication Notes\n-----------------\n\n*   Signals are meant to transmit basic text data between participants in a session.\n*   Signals don't have extensive chat like features (like emoji's etc). \n\n*   Sending an signal using an session object as follows:\n```swift\n session.signal(withType: type , string: data, connection:c.getOTConnection(), error: nil)\n ```\n or \n ```swift\n session.signal(withType: type , string: data, connection:c.getOTConnection(), retryAfterReconnect: retryAfterConnect, error: nil)\n ```\n `retryAfterReconnect` default value is `true` in the first call. The error case fails silently.\n\n *  Receiving a signal is done using OTSessionDelegate callback as follows:\n ```swift\n func session(_ session: OTSession, receivedSignalType type: String?, from connection: OTConnection?, with string: String?) {\n    ..\n }\n ```\nYou just need to implement the above calls in your app. \n\n* Valid Characters in a signal data  is limited  to `[^a-zA-Z0-9-_~\\\\s]`. If a non valid character is used , signal is  not send. To get around this you can encode signal data with `base64` and decode it on other side. This way you can send emoji's for example. A sample code which extends `String` is provided below for reference:\n```swift\nextension String {\n    func fromBase64() -> String? {\n            guard let data = Data(base64Encoded: self) else {\n                return nil\n            }\n\n            return String(data: data, encoding: .ascii)\n        }\n\n        func toBase64() -> String {\n            return Data(self.utf8).base64EncodedString()\n        }\n        func isValidSignal() -> Bool {\n            return self.count <= 128 && self.range(of: \"[^a-zA-Z0-9-_~\\\\s]\", options: .regularExpression) == nil\n        }\n ...\n }       \n```\n\nScreen shot (SwiftUI based)\n-----------------\n\n## Starting screen:\n\n1) Tap on \"Hello !!\" sends a \"Hello World\" message to all connections.\n2) Tap on the Pen image leads to Form View (as shown below)\n\n<img width=\"377\" alt=\"image\" src=\"https://user-images.githubusercontent.com/4369083/222551087-fb729575-d57c-4b43-8f5f-27477a3a1bfc.png\">\n\n\n\n## Starting screen with Scrollable Messages:\n\n<img width=\"377\" alt=\"image\" src=\"https://user-images.githubusercontent.com/4369083/222550949-200738d3-2958-4d1d-8dfd-d9043ca45edc.png\">\n\n\n## Signal Form view:\n\n<img width=\"376\" alt=\"image\" src=\"https://user-images.githubusercontent.com/4369083/222550836-815c19c8-8475-49c3-bf65-be7233f3814c.png\">\n\n<img width=\"377\" alt=\"image\" src=\"https://user-images.githubusercontent.com/4369083/222550889-9799aa88-88dc-4239-a589-9a4db066c518.png\">\n\n\n"
  },
  {
    "path": "Signals/Signals/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Signals/Signals/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Signals/Signals/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Signals/Signals/ContentView.swift",
    "content": "//\n//  ContentView.swift\n//  Signals\n//\n//  Created by Jaideep Shah on 2/9/23.\n//\n\nimport SwiftUI\nstruct ContentView {\n    @State var oneClick = true\n    @StateObject  private var sdk = VonageVideoSDK()\n    @State private var signalType = \"Greetings\"\n    @State private var signalData = \"Hello World\"\n    @State private var isRetryOnReconnect = true\n    \n}\nextension ContentView: View {\n    var body: some View {\n        ZStack {\n            VStack(alignment: .center, spacing: 25) {\n                if (sdk.isSessionConnected == false) {\n                    Text(\"Connecting ...\")\n                        .font(.title)\n                } else {\n                    if oneClick == true {\n                        Button(\"Hello !!\") {\n                            sdk.sendSignalToAll(type: \"Greetings\", data: \"Hello World\")\n                        }\n                        .font(.title)\n \n                        //OneClickView(oneClick: $oneClick)\n                        Button {\n                            oneClick = false\n                           // print(\"Edit button was tapped\")\n                        } label: {\n                            Image(systemName: \"square.and.pencil\")\n                        }\n                        ScrollView {\n                            MessagesView()\n                            \n                        }\n                    }\n                    else  {\n                        VStack {\n                            FormView(signalType: $signalType, signalData: $signalData, retryAfterConnect: $isRetryOnReconnect, oneClick: $oneClick)\n                        }\n                    }\n                }\n\n                \n            }\n            .padding(30)\n            .environmentObject(sdk)\n            .onDisappear {\n                sdk.closeAll()\n            }\n        }\n    }\n}\nstruct ContentView_Previews: PreviewProvider {\n    static var previews: some View {\n        ContentView()\n    }\n}\n\n\n\n            \n"
  },
  {
    "path": "Signals/Signals/FormView.swift",
    "content": "//\n//  FormView.swift\n//\n//  Created by Jaideep Shah on 2/9/23.\n//\n\nimport SwiftUI\n\nstruct FormView {\n    @EnvironmentObject private var sdk: VonageVideoSDK\n    @Binding var signalType : String\n    @Binding var signalData : String\n    @Binding var retryAfterConnect : Bool\n    @State private var isAllConnections = false\n    @State private var selectedConns = Set<String>()\n    @Binding var oneClick : Bool\n    @State private var signalCharError = false\n}\n\nextension FormView: View {\n    var body: some View {\n        VStack(spacing:40) {\n            \n            VStack {\n                Toggle(\"Signal all\", isOn: $isAllConnections)\n                if (isAllConnections == false) {\n                    HStack {\n                        Text(\"Choose connections:\")\n                        Spacer()\n                    }\n                \n                    List(sdk.connsInfo, id: \\.displayName, selection: $selectedConns) { c in\n                        Text(c.displayName)\n                    }\n                    .multilineTextAlignment(.leading)\n                    .font(.system(size: 12))\n                    .environment(\\.editMode, .constant(EditMode.active))\n                    .listStyle(PlainListStyle())\n                    .lineLimit(2)\n                    .overlay(\n                            RoundedRectangle(cornerRadius: 10, style: .circular).stroke(Color(uiColor: .tertiaryLabel), lineWidth: 2)\n                                    )\n\n                }\n            }\n            \n            HStack {\n               \n                    Text(\"Type:\")\n                    Spacer()\n                    TextField(signalType, text: $signalType, axis: .vertical)\n                        .multilineTextAlignment(.center)\n                        .textFieldStyle(.roundedBorder)\n                        .border(.gray, width: 1)\n                        .keyboardType(.asciiCapable)\n                        .disableAutocorrection(true)\n                        .lineLimit(1)\n                    Spacer()\n\n                }\n            \n           \n            HStack {\n               \n                    Text(\"Content:\")\n                    Spacer()\n                    TextField(\"Hello world\", text: $signalData, axis: .vertical)\n                            .multilineTextAlignment(.center)\n                            .textFieldStyle(.roundedBorder)\n                            .border(.gray, width: 1)\n                            .keyboardType(.asciiCapable)\n                            .disableAutocorrection(true)\n                            .lineLimit(1)\n                    Spacer()\n                }\n            \n          \n            Toggle(\"Retry after reconnect:\", isOn: $retryAfterConnect)\n            HStack {\n                Spacer()\n                Button(action: {\n                    if signalData.isValidSignal() == false || signalType.isValidSignal() == false {\n                        signalCharError = true\n                    } else {\n                        self.oneClick.toggle()\n                        for connId in selectedConns {\n                            sdk.sendSignalToConnection(connection: connId, type: signalType, data: signalData, retryAfterConnect: retryAfterConnect)\n                        }\n                    }\n             \n                }) {\n                    Text(\"Send\")\n                }\n                Spacer()\n                Button(role: .cancel, action: {\n                    self.oneClick.toggle()\n                }) {\n                    Text(\"Cancel\")\n                }\n                Spacer()\n            }\n\n        }\n        .padding(1)\n        .alert(\"Only \\\"a-zA-Z0-9-_~\\\" and Space characters allowed for content and type.\", isPresented: $signalCharError) {\n                    Button(\"OK\", role: .cancel) { }\n            }\n        \n    }\n    \n}\n\nstruct FormView_Previews: PreviewProvider {\n    static var previews: some View {\n        FormView(signalType: Binding.constant(\"Greeting\"), signalData: Binding.constant(\"Hello\"), retryAfterConnect: Binding.constant(true), oneClick: Binding.constant(false))\n            .environmentObject(VonageVideoSDK())\n\n    }\n    \n}\n"
  },
  {
    "path": "Signals/Signals/MessagesView.swift",
    "content": "//\n//  MessagesView.swift\n//  \n//\n//  Created by Jaideep Shah on 2/9/23.\n//\n\nimport SwiftUI\n\n\n\nstruct MessagesView {\n    @EnvironmentObject private var sdk: VonageVideoSDK\n}\n\nextension MessagesView: View {\n    var body: some View {\n        LazyVStack(alignment: .leading) {\n\n            ForEach(sdk.messages) { m in\n                    Spacer()\n                    VStack(alignment: .leading) {\n                        HStack {\n                            if m.outgoing {\n                                Image(systemName: \"arrow.up.forward.square.fill\")\n                                    .foregroundColor(.yellow)\n                            } else {\n                                Image(systemName: \"arrow.down.left.square.fill\")\n                                    .foregroundColor(.green)\n                            }\n                            Text(m.displayConnId)\n                                .padding(.horizontal)\n                                .multilineTextAlignment(.leading)\n                                .font(.system(size: 12))\n                            Spacer()\n                            Text(m.type)\n                                .multilineTextAlignment(.trailing)\n                                .font(.system(size: 12))\n                              \n                            \n                        }\n                        Spacer()\n                        HStack {\n                            Image(systemName: \"arrow.up.forward.square.fill\")\n                                .foregroundColor(.green)\n                                .hidden()\n                            Text(m.content)\n                                .padding(.horizontal)\n                                .multilineTextAlignment(.leading)\n                                .font(.system(size: 14))\n                                \n                                .allowsTightening(true)\n                                .lineLimit(3)\n                        }\n\n                    }\n                    .padding(5)\n                    .overlay(\n                        RoundedRectangle(cornerRadius: 10, style: .circular).stroke(Color(uiColor: .tertiaryLabel), lineWidth: 1)\n                            .shadow(radius: 5)\n                       \n                            \n                    )\n                    \n                }\n                \n         \n            \n        }\n        .padding()\n                        \n       }\n    \n}\n\nstruct MessagesView_Previews: PreviewProvider {\n    static var previews: some View {\n        MessagesView()\n    }\n}\n"
  },
  {
    "path": "Signals/Signals/Preview Content/Preview Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Signals/Signals/SignalsApp.swift",
    "content": "//\n//  SignalsApp.swift\n//  Signals\n//\n//  Created by Jaideep Shah on 2/9/23.\n//\n\nimport SwiftUI\n\n@main\nstruct SignalsApp: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n"
  },
  {
    "path": "Signals/Signals/VonageVideoSDK.swift",
    "content": "//\n//  VonageVideoSDK.swift\n//  Signals\n//\n//  Created by Jaideep Shah on 2/15/23.\n//\n\nimport UIKit\nimport OpenTok\n\n\n\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nclass VonageVideoSDK: NSObject {\n    @Published var isSessionConnected = false\n    @Published var connsInfo: [ConnectionInfo] = []\n    @Published var messages: [SignalMessage] = []    //unlimited and last in , first out\n\n    lazy var session: OTSession = {\n        //make sure you have entered the credentials above , else you get an exception here\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    \n    override init() {\n        super.init()\n        var error: OTError?\n        session.connect(withToken: kToken, error: &error)\n        if let error = error {\n            print(\"Session creation error \\(error.description)\")\n        }\n    }\n   \n }\n// MARK: ObservableObject\nextension VonageVideoSDK: ObservableObject {\n\n    \n}\n// MARK: - OTSession delegate callbacks\nextension VonageVideoSDK: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n       isSessionConnected = true\n        connsInfo.append(ConnectionInfo(otMyConnection: session.connection!, otParticipantConnection: nil))\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n      \n    }\n    \n    func session(_ session: OTSession, connectionCreated connection: OTConnection) {\n        connsInfo.append(ConnectionInfo(otMyConnection: session.connection!, otParticipantConnection: connection))\n    }\n    func session(_ session: OTSession, connectionDestroyed connection: OTConnection) {\n        guard connsInfo.contains(connsInfo) else {\n            return\n        }\n        let info = ConnectionInfo(otMyConnection: session.connection!, otParticipantConnection: connection)\n        connsInfo = connsInfo.filter { $0 != info }\n    }\n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"Session Failed to connect: \\(error.localizedDescription)\")\n    }\n    \n    func session(_ session: OTSession, receivedSignalType type: String?, from connection: OTConnection?, with string: String?) {\n        if let string = string, let type = type, let c = connection?.connectionId {\n            addMessage(connection: c, type: type, data: string, outgoing: false)\n        }\n    }\n}\n\n// MARK: - UI interface\nextension VonageVideoSDK {\n    private func addMessage(connection: String?, type: String, data: String, outgoing: Bool) {\n        messages.insert(SignalMessage(connId: connection, type: type, content: data, outgoing: outgoing), at: 0)\n    }\n    \n    func sendSignalToAll(type: String?, data: String?) {\n        guard let type = type, let data = data , type.isValidSignal() == true && data.isValidSignal() == true else {\n            return\n        }\n        session.signal(withType: type , string: data, connection:nil, error: nil)\n        addMessage(connection: nil, type: type, data: data, outgoing: true)\n    }\n    \n    func closeAll() {\n        session.disconnect(nil)\n    }\n\n    func sendSignalToConnection(connection: String, type: String?, data: String?, retryAfterConnect: Bool) {\n        guard let type = type, let data = data ,\n                  type.isValidSignal() == true && data.isValidSignal() == true else {\n            return\n        }\n        for c in connsInfo where c.displayName == connection  {\n            if retryAfterConnect == true {\n                //retry is true by default\n                session.signal(withType: type , string: data, connection:c.getOTConnection(), error: nil)\n            } else {\n                // You can use this call for all cases. We are just distinguishing here to show various way to call signal.\n                session.signal(withType: type , string: data, connection:c.getOTConnection(), retryAfterReconnect: retryAfterConnect, error: nil)\n            }\n            addMessage(connection: c.displayName, type: type, data: data, outgoing: true)\n        }\n    }\n}\n\nstruct SignalMessage: Identifiable {\n    let id = UUID()\n    var connId : String?\n    var type: String\n    var content: String\n    var outgoing: Bool\n    var displayConnId: String {\n        get {\n            return connId == nil ? \"All\" : connId!.lastTenCharacter()\n        }\n    }\n}\nstruct ConnectionInfo : Equatable, Hashable {\n    let id = UUID()\n    var otMyConnection : OTConnection\n    var otParticipantConnection : OTConnection?\n    let displaySelf = \"Self\"\n    \n    static func ==(lhs: ConnectionInfo, rhs: ConnectionInfo) -> Bool {\n        return lhs.otParticipantConnection?.connectionId == rhs.otParticipantConnection?.connectionId\n    }\n    func hash(into hasher: inout Hasher) {\n        hasher.combine(displayName)\n    }\n    var displayName: String {\n        get {\n            guard let otConnectionParticipant = otParticipantConnection else {\n                return displaySelf\n            }\n            return  otConnectionParticipant.connectionId\n        }\n    }\n    \n    func getOTConnection() -> OTConnection {\n        guard let otConnectionParticipant = otParticipantConnection else {\n            return otMyConnection\n        }\n        return otConnectionParticipant\n    }\n   \n}\n\nextension String {\n\n    // only letters permitted are (A-Z and a-z), numbers (0-9), \"-\", \"_\", \" \" and \"~\".\n    // hence we encode and decode with base64 to accomadate other characters like emojis etc.\n    // Both sides needs to be part of this. This sample app will not use base64 encoding/decoding\n    // and rely on the isValidSignal method below.\n    \n    func fromBase64() -> String? {\n        guard let data = Data(base64Encoded: self) else {\n            return nil\n        }\n\n        return String(data: data, encoding: .ascii)\n    }\n\n    func toBase64() -> String {\n        return Data(self.utf8).base64EncodedString()\n    }\n    \n   // The maximum length of the type string is 128 characters, and it must\n   // contain only letters (A-Z and a-z), numbers (0-9), \"-\", \"_\", \" \", and \"~\".\n   // you could have used base64 encoding decoding here. But just for illustration ,\n   // we assume the other  side is already deployed and we can't use base64.\n    \n    func isValidSignal() -> Bool {\n        return self.count <= 128 && self.range(of: \"[^a-zA-Z0-9-_~\\\\s]\", options: .regularExpression) == nil\n    }\n    func lastTenCharacter() -> String {\n        return \"...\" + self.suffix(10)\n    }\n    \n}\n"
  },
  {
    "path": "Signals/Signals.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 55;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1F8B1BA82995A93600D8E8FB /* SignalsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8B1BA72995A93600D8E8FB /* SignalsApp.swift */; };\n\t\t1F8B1BAA2995A93600D8E8FB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8B1BA92995A93600D8E8FB /* ContentView.swift */; };\n\t\t1F8B1BAC2995A93800D8E8FB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F8B1BAB2995A93800D8E8FB /* Assets.xcassets */; };\n\t\t1F8B1BAF2995A93800D8E8FB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F8B1BAE2995A93800D8E8FB /* Preview Assets.xcassets */; };\n\t\t1F8B1BB82995A96400D8E8FB /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8B1BB52995A96300D8E8FB /* MessagesView.swift */; };\n\t\t1F8B1BB92995A96400D8E8FB /* FormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8B1BB62995A96300D8E8FB /* FormView.swift */; };\n\t\t1F8B1D42299D8D0800D8E8FB /* VonageVideoSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8B1D41299D8D0800D8E8FB /* VonageVideoSDK.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t1F8B1BA42995A93600D8E8FB /* Signals.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Signals.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t1F8B1BA72995A93600D8E8FB /* SignalsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalsApp.swift; sourceTree = \"<group>\"; };\n\t\t1F8B1BA92995A93600D8E8FB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = \"<group>\"; };\n\t\t1F8B1BAB2995A93800D8E8FB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t1F8B1BAE2995A93800D8E8FB /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"Preview Assets.xcassets\"; sourceTree = \"<group>\"; };\n\t\t1F8B1BB52995A96300D8E8FB /* MessagesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesView.swift; sourceTree = \"<group>\"; };\n\t\t1F8B1BB62995A96300D8E8FB /* FormView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormView.swift; sourceTree = \"<group>\"; };\n\t\t1F8B1D41299D8D0800D8E8FB /* VonageVideoSDK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VonageVideoSDK.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t1F8B1BA12995A93600D8E8FB /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t1F8B1B9B2995A93600D8E8FB = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1F8B1BA62995A93600D8E8FB /* Signals */,\n\t\t\t\t1F8B1BA52995A93600D8E8FB /* Products */,\n\t\t\t\tFC1D2E52DCF9C6CBE4241D90 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1F8B1BA52995A93600D8E8FB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1F8B1BA42995A93600D8E8FB /* Signals.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1F8B1BA62995A93600D8E8FB /* Signals */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1F8B1D41299D8D0800D8E8FB /* VonageVideoSDK.swift */,\n\t\t\t\t1F8B1BA72995A93600D8E8FB /* SignalsApp.swift */,\n\t\t\t\t1F8B1BA92995A93600D8E8FB /* ContentView.swift */,\n\t\t\t\t1F8B1BB52995A96300D8E8FB /* MessagesView.swift */,\n\t\t\t\t1F8B1BB62995A96300D8E8FB /* FormView.swift */,\n\t\t\t\t1F8B1BAB2995A93800D8E8FB /* Assets.xcassets */,\n\t\t\t\t1F8B1BAD2995A93800D8E8FB /* Preview Content */,\n\t\t\t);\n\t\t\tpath = Signals;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1F8B1BAD2995A93800D8E8FB /* Preview Content */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1F8B1BAE2995A93800D8E8FB /* Preview Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = \"Preview Content\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFC1D2E52DCF9C6CBE4241D90 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t1F8B1BA32995A93600D8E8FB /* Signals */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1F8B1BB22995A93800D8E8FB /* Build configuration list for PBXNativeTarget \"Signals\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t1F8B1BA02995A93600D8E8FB /* Sources */,\n\t\t\t\t1F8B1BA12995A93600D8E8FB /* Frameworks */,\n\t\t\t\t1F8B1BA22995A93600D8E8FB /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Signals;\n\t\t\tproductName = Signals;\n\t\t\tproductReference = 1F8B1BA42995A93600D8E8FB /* Signals.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t1F8B1B9C2995A93600D8E8FB /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = 1;\n\t\t\t\tLastSwiftUpdateCheck = 1410;\n\t\t\t\tLastUpgradeCheck = 1410;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t1F8B1BA32995A93600D8E8FB = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 14.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1F8B1B9F2995A93600D8E8FB /* Build configuration list for PBXProject \"Signals\" */;\n\t\t\tcompatibilityVersion = \"Xcode 13.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 1F8B1B9B2995A93600D8E8FB;\n\t\t\tproductRefGroup = 1F8B1BA52995A93600D8E8FB /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t1F8B1BA32995A93600D8E8FB /* Signals */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t1F8B1BA22995A93600D8E8FB /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1F8B1BAF2995A93800D8E8FB /* Preview Assets.xcassets in Resources */,\n\t\t\t\t1F8B1BAC2995A93800D8E8FB /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t1F8B1BA02995A93600D8E8FB /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t1F8B1D42299D8D0800D8E8FB /* VonageVideoSDK.swift in Sources */,\n\t\t\t\t1F8B1BAA2995A93600D8E8FB /* ContentView.swift in Sources */,\n\t\t\t\t1F8B1BB82995A96400D8E8FB /* MessagesView.swift in Sources */,\n\t\t\t\t1F8B1BB92995A96400D8E8FB /* FormView.swift in Sources */,\n\t\t\t\t1F8B1BA82995A93600D8E8FB /* SignalsApp.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1F8B1BB02995A93800D8E8FB /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.1;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1F8B1BB12995A93800D8E8FB /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.1;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1F8B1BB32995A93800D8E8FB /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Signals/Preview Content\\\"\";\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.c.x.Signals;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1F8B1BB42995A93800D8E8FB /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\\\"Signals/Preview Content\\\"\";\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;\n\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.c.x.Signals;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1F8B1B9F2995A93600D8E8FB /* Build configuration list for PBXProject \"Signals\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1F8B1BB02995A93800D8E8FB /* Debug */,\n\t\t\t\t1F8B1BB12995A93800D8E8FB /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1F8B1BB22995A93800D8E8FB /* Build configuration list for PBXNativeTarget \"Signals\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1F8B1BB32995A93800D8E8FB /* Debug */,\n\t\t\t\t1F8B1BB42995A93800D8E8FB /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 1F8B1B9C2995A93600D8E8FB /* Project object */;\n}\n"
  },
  {
    "path": "Simple-Multiparty/Podfile",
    "content": "require_relative '../OpenTokSDKVersion'\n\nplatform :ios, MinIosSdkVersion\nuse_frameworks!\n\ntarget 'Simple-Multiparty' do\n  pod 'OTXCFramework', OpenTokSDKVersion\nend\n"
  },
  {
    "path": "Simple-Multiparty/README.md",
    "content": "Simple Multiparty Sample App\n==============================\n\nPrevious samples subscribe to only one stream. In a multiparty video audio call\nthere should be multiple parties.\n\n*Important:* To use this application, follow the instructions in the\n[Quick Start](../README.md#quick-start) section of the main README file\nfor this repository.\n\nThis simple multiparty app is able to handle only four subscriber parties. On a\nnew stream received the ViewController class creates a new Subscriber object and\nsubscribes the Session object to it. The Subscriber stream is rendered in the\nscreen as we did it before.\n\nThis sample uses a UICollectionView to show each subscriber view. We use a custom\nUICollectionViewCell that will hold the subscriber view and will also control some\nbasic user interface to mute the audio of that subscriber.\n\n```swift\nclass SubscriberCollectionCell: UICollectionViewCell {\n  @IBOutlet var muteButton: UIButton!\n\n  var subscriber: OTSubscriber?\n\n  @IBAction func muteSubscriberAction(_ sender: AnyObject) {\n    subscriber?.subscribeToAudio = !(subscriber?.subscribeToAudio ?? true)\n\n    let buttonImage: UIImage  = {\n      if !(subscriber?.subscribeToAudio ?? true) {\n        return #imageLiteral(resourceName: \"Subscriber-Speaker-Mute-35\")\n      } else {\n        return #imageLiteral(resourceName: \"Subscriber-Speaker-35\")\n      }\n    }()\n\n    muteButton.setImage(buttonImage, for: .normal)\n  }\n\n  override func layoutSubviews() {\n    if let sub = subscriber {\n      sub.view.frame = bounds\n      contentView.insertSubview(sub.view, belowSubview: muteButton)\n\n      muteButton.isEnabled = true\n      muteButton.isHidden = false\n    }\n  }\n}\n```\n\n## Adding user interface controls\n\nThe ViewController class shows how you can add user interface controls for the following:\n\n* Turning a publisher's audio stream on and off\n* Swapping the publisher's camera\n\nWhen the user taps the mute button for the publisher, the following method of the ViewController \nclass is invoked:\n\n```swift\n@IBAction func muteMicAction(_ sender: AnyObject) {\n  publisher.publishAudio = !publisher.publishAudio\n  let buttonImage: UIImage  = {\n    if !publisher.publishAudio {\n      return #imageLiteral(resourceName: \"mic_muted-24\")\n    } else {\n      return #imageLiteral(resourceName: \"mic-24\")\n    }\n    }()\n                                                                                                      \n    muteMicButton.setImage(buttonImage, for: .normal)\n}\n```\n\n## Next steps\n\nFor details on the full OpenTok Android API, see the [reference\ndocumentation](https://tokbox.com/developer/sdks/ios/reference/index.html).\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  6.Multi-Party\n//\n//  Created by Roberto Perez Cubero on 27/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n    }\n}\n\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/Subscriber-Speaker-35.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"Subscriber-Speaker-35.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"Subscriber-Speaker-35@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/Subscriber-Speaker-Mute-35.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"Subscriber-Speaker-Mute-35.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"Subscriber-Speaker-Mute-35@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/TB Bug-30.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"TB Bug-30.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"TB Bug-30@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/camera-switch_black-33.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"camera-switch_black-33.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"camera-switch_black-33@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/camera_switch-33.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"camera_switch-33.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"camera_switch-33@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/icon_arrowLeft_disabled-28.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowLeft_disabled-28.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowLeft_disabled-28@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/icon_arrowLeft_enabled-28.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowLeft_enabled-28.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowLeft_enabled-28@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/icon_arrowRight_disabled-28.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowRight_disabled-28.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowRight_disabled-28@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/icon_arrowRight_enabled-28.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowRight_enabled-28.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"icon_arrowRight_enabled-28@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/mic-24.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic-24.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic-24@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/mic_muted-24.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic_muted-24.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic_muted-24@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Assets.xcassets/mic_receiving_data-35.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic_receiving_data-35.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic_receiving_data-35@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13528\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13526\"/>\n        <capability name=\"Constraints to layout margins\" minToolsVersion=\"6.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"Simple_Multiparty\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l35-II-8uQ\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"617\" width=\"375\" height=\"50\"/>\n                                <subviews>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tqX-hd-Ltx\">\n                                        <rect key=\"frame\" x=\"159.5\" y=\"10\" width=\"56\" height=\"30\"/>\n                                        <state key=\"normal\" title=\"End Call\">\n                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"endCallAction:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"GRa-eH-mgm\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"y48-t7-0y4\">\n                                        <rect key=\"frame\" x=\"343\" y=\"13\" width=\"24\" height=\"24\"/>\n                                        <state key=\"normal\" image=\"mic-24\"/>\n                                        <connections>\n                                            <action selector=\"muteMicAction:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"8Fc-m3-idH\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p7u-kt-bSa\">\n                                        <rect key=\"frame\" x=\"8\" y=\"8.5\" width=\"33\" height=\"33\"/>\n                                        <state key=\"normal\" image=\"camera_switch-33\"/>\n                                        <connections>\n                                            <action selector=\"swapCameraAction:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"hgs-Mg-koW\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <color key=\"backgroundColor\" red=\"0.16078431372549018\" green=\"0.16078431372549018\" blue=\"0.16078431372549018\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <constraints>\n                                    <constraint firstItem=\"y48-t7-0y4\" firstAttribute=\"centerY\" secondItem=\"l35-II-8uQ\" secondAttribute=\"centerY\" id=\"1gP-tu-fGl\"/>\n                                    <constraint firstItem=\"p7u-kt-bSa\" firstAttribute=\"leading\" secondItem=\"l35-II-8uQ\" secondAttribute=\"leading\" constant=\"8\" id=\"C6g-ie-Z5h\"/>\n                                    <constraint firstItem=\"tqX-hd-Ltx\" firstAttribute=\"centerY\" secondItem=\"l35-II-8uQ\" secondAttribute=\"centerY\" id=\"HUX-9y-MJb\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"y48-t7-0y4\" secondAttribute=\"trailing\" constant=\"8\" id=\"YCL-B2-hHn\"/>\n                                    <constraint firstItem=\"tqX-hd-Ltx\" firstAttribute=\"centerX\" secondItem=\"l35-II-8uQ\" secondAttribute=\"centerX\" id=\"ZC8-is-KcK\"/>\n                                    <constraint firstItem=\"p7u-kt-bSa\" firstAttribute=\"centerY\" secondItem=\"l35-II-8uQ\" secondAttribute=\"centerY\" id=\"tzv-3q-Oob\"/>\n                                </constraints>\n                            </view>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Subscriber Area\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LUJ-yd-qlV\">\n                                <rect key=\"frame\" x=\"119.5\" y=\"322\" width=\"136.5\" height=\"23\"/>\n                                <fontDescription key=\"fontDescription\" type=\"italicSystem\" pointSize=\"19\"/>\n                                <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <collectionView hidden=\"YES\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wWg-8v-eL2\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"70\" width=\"375\" height=\"547\"/>\n                                <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                <collectionViewFlowLayout key=\"collectionViewLayout\" minimumLineSpacing=\"0.0\" minimumInteritemSpacing=\"0.0\" id=\"aBH-3s-5RT\">\n                                    <size key=\"itemSize\" width=\"160\" height=\"250\"/>\n                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                </collectionViewFlowLayout>\n                                <cells>\n                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"subscriberCell\" id=\"HiM-Pe-qiJ\" customClass=\"SubscriberCollectionCell\" customModule=\"Simple_Multiparty\" customModuleProvider=\"target\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"160\" height=\"250\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                        <view key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"160\" height=\"250\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <button opaque=\"NO\" contentMode=\"scaleToFill\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sxA-lI-1MV\">\n                                                    <rect key=\"frame\" x=\"132\" y=\"8\" width=\"20\" height=\"20\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"20\" id=\"41D-1o-avQ\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"20\" id=\"OYk-ax-Ibb\"/>\n                                                    </constraints>\n                                                    <state key=\"normal\" image=\"Subscriber-Speaker-35\"/>\n                                                    <connections>\n                                                        <action selector=\"muteSubscriberAction:\" destination=\"HiM-Pe-qiJ\" eventType=\"touchUpInside\" id=\"XNk-xh-vok\"/>\n                                                    </connections>\n                                                </button>\n                                            </subviews>\n                                        </view>\n                                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"topMargin\" secondItem=\"sxA-lI-1MV\" secondAttribute=\"top\" id=\"9yB-c3-qjs\"/>\n                                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"sxA-lI-1MV\" secondAttribute=\"trailing\" id=\"csF-AM-D0h\"/>\n                                        </constraints>\n                                        <connections>\n                                            <outlet property=\"muteButton\" destination=\"sxA-lI-1MV\" id=\"SzI-hk-0j3\"/>\n                                        </connections>\n                                    </collectionViewCell>\n                                </cells>\n                                <connections>\n                                    <outlet property=\"dataSource\" destination=\"BYZ-38-t0r\" id=\"3rZ-ks-Elu\"/>\n                                    <outlet property=\"delegate\" destination=\"BYZ-38-t0r\" id=\"h4S-K7-xbb\"/>\n                                </connections>\n                            </collectionView>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pll-Qc-YXj\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"50\"/>\n                                <subviews>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" misplaced=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cwG-DZ-Nqx\">\n                                        <rect key=\"frame\" x=\"8\" y=\"11\" width=\"42\" height=\"30\"/>\n                                        <state key=\"normal\" image=\"TB Bug-30\"/>\n                                        <connections>\n                                            <action selector=\"tokboxButtonAction:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"NHY-Zv-pwY\"/>\n                                        </connections>\n                                    </button>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" misplaced=\"YES\" text=\"Label\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L7B-Pt-YNV\">\n                                        <rect key=\"frame\" x=\"166\" y=\"16\" width=\"42\" height=\"21\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.66666666666666663\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"50\" id=\"3Co-gv-Wos\"/>\n                                    <constraint firstItem=\"L7B-Pt-YNV\" firstAttribute=\"centerY\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"centerY\" id=\"D3l-zP-O68\"/>\n                                    <constraint firstItem=\"cwG-DZ-Nqx\" firstAttribute=\"centerY\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"centerY\" id=\"Q33-Ss-Djz\"/>\n                                    <constraint firstItem=\"L7B-Pt-YNV\" firstAttribute=\"centerX\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"centerX\" id=\"W6g-Sp-MGT\"/>\n                                    <constraint firstItem=\"cwG-DZ-Nqx\" firstAttribute=\"leading\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"leading\" constant=\"8\" id=\"wFJ-X4-tmZ\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"l35-II-8uQ\" firstAttribute=\"top\" secondItem=\"wWg-8v-eL2\" secondAttribute=\"bottom\" id=\"0Qq-kc-bhY\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"l35-II-8uQ\" secondAttribute=\"bottom\" id=\"1yf-YE-qpx\"/>\n                            <constraint firstItem=\"wWg-8v-eL2\" firstAttribute=\"width\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"width\" id=\"6uz-pD-9bT\"/>\n                            <constraint firstItem=\"pll-Qc-YXj\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" id=\"9JH-TB-LqZ\"/>\n                            <constraint firstItem=\"l35-II-8uQ\" firstAttribute=\"height\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"height\" id=\"DT2-5c-bQ2\"/>\n                            <constraint firstItem=\"l35-II-8uQ\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"I67-ci-7vz\"/>\n                            <constraint firstItem=\"pll-Qc-YXj\" firstAttribute=\"width\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"width\" id=\"USu-un-gHr\"/>\n                            <constraint firstItem=\"wWg-8v-eL2\" firstAttribute=\"top\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"bottom\" id=\"hAO-El-1dq\"/>\n                            <constraint firstItem=\"l35-II-8uQ\" firstAttribute=\"width\" secondItem=\"pll-Qc-YXj\" secondAttribute=\"width\" id=\"l22-vb-OY3\"/>\n                            <constraint firstItem=\"pll-Qc-YXj\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"njp-P5-Grl\"/>\n                            <constraint firstItem=\"LUJ-yd-qlV\" firstAttribute=\"centerY\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerY\" id=\"ohO-6l-1VK\"/>\n                            <constraint firstItem=\"LUJ-yd-qlV\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"rC4-PA-1aj\"/>\n                            <constraint firstItem=\"wWg-8v-eL2\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"t2i-yK-kPC\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"collectionView\" destination=\"wWg-8v-eL2\" id=\"bv7-EK-ciI\"/>\n                        <outlet property=\"endCallButton\" destination=\"tqX-hd-Ltx\" id=\"CgH-hg-VPN\"/>\n                        <outlet property=\"muteMicButton\" destination=\"y48-t7-0y4\" id=\"qz4-Zx-r0f\"/>\n                        <outlet property=\"swapCameraButton\" destination=\"p7u-kt-bSa\" id=\"iKd-sB-52x\"/>\n                        <outlet property=\"userName\" destination=\"L7B-Pt-YNV\" id=\"U9s-Os-6Ux\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"136.80000000000001\" y=\"138.98050974512745\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"Subscriber-Speaker-35\" width=\"35\" height=\"35\"/>\n        <image name=\"TB Bug-30\" width=\"30\" height=\"30\"/>\n        <image name=\"camera_switch-33\" width=\"33\" height=\"33\"/>\n        <image name=\"mic-24\" width=\"24\" height=\"24\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>NSCameraUsageDescription</key>\n\t<string></string>\n\t<key>NSMicrophoneUsageDescription</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  6.Multi-Party\n//\n//  Created by Roberto Perez Cubero on 27/09/2016.\n//  Copyright © 2016 tokbox. All rights reserved.\n//\n\nimport UIKit\nimport OpenTok\n\n// *** Fill the following variables using your own Project info  ***\n// ***            https://tokbox.com/account/#/                  ***\n// Replace with your OpenTok API key\nlet kApiKey = \"\"\n// Replace with your generated session ID\nlet kSessionId = \"\"\n// Replace with your generated token\nlet kToken = \"\"\n\nclass ViewController: UIViewController {\n\n    @IBOutlet var endCallButton: UIButton!\n    @IBOutlet var swapCameraButton: UIButton!\n    @IBOutlet var muteMicButton: UIButton!\n    @IBOutlet var userName: UILabel!\n    @IBOutlet var collectionView: UICollectionView!\n    \n    var subscribers: [IndexPath: OTSubscriber] = [:]\n    lazy var session: OTSession = {\n        return OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)!\n    }()\n    lazy var publisher: OTPublisher = {\n        let settings = OTPublisherSettings()\n        settings.name = UIDevice.current.name\n        return OTPublisher(delegate: self, settings: settings)!\n    }()\n    var error: OTError?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        session.connect(withToken: kToken, error: &error)\n        \n        userName.text = UIDevice.current.name\n    }\n    \n    override func viewDidAppear(_ animated: Bool) {\n        guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {\n            return\n        }\n        layout.itemSize = CGSize(width: collectionView.bounds.size.width / 2,\n                                 height: collectionView.bounds.size.height / 2)\n    }\n\n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n    }\n    \n    @IBAction func swapCameraAction(_ sender: AnyObject) {\n        if publisher.cameraPosition == .front {\n            publisher.cameraPosition = .back\n        } else {\n            publisher.cameraPosition = .front\n        }\n    }\n    \n    @IBAction func tokboxButtonAction(_ sender: AnyObject) {\n        \n        UIApplication.shared.open(URL(string: \"https://www.tokbox.com/developer/\")!, options: [:], completionHandler: nil)\n    }\n    \n    @IBAction func muteMicAction(_ sender: AnyObject) {\n        publisher.publishAudio = !publisher.publishAudio\n        \n        let buttonImage: UIImage  = {\n            if !publisher.publishAudio {\n                return #imageLiteral(resourceName: \"mic_muted-24\")\n            } else {\n                return #imageLiteral(resourceName: \"mic-24\")\n            }\n        }()\n        \n        muteMicButton.setImage(buttonImage, for: .normal)\n    }\n    \n    @IBAction func endCallAction(_ sender: AnyObject) {\n        session.disconnect(&error)\n    }\n    \n    func reloadCollectionView() {\n        collectionView.isHidden = subscribers.count == 0\n        collectionView.reloadData()\n    }\n}\n\nextension ViewController: UICollectionViewDataSource {\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return subscribers.count\n    }\n    \n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"subscriberCell\", for: indexPath) as! SubscriberCollectionCell\n        cell.subscriber = subscribers[indexPath]\n        return cell\n    }\n}\n\nextension ViewController: UICollectionViewDelegate {\n}\n\n// MARK: - Subscriber Cell\nclass SubscriberCollectionCell: UICollectionViewCell {\n    @IBOutlet var muteButton: UIButton!\n    \n    var subscriber: OTSubscriber?\n    \n    @IBAction func muteSubscriberAction(_ sender: AnyObject) {\n        subscriber?.subscribeToAudio = !(subscriber?.subscribeToAudio ?? true)\n        \n        let buttonImage: UIImage  = {\n            if !(subscriber?.subscribeToAudio ?? true) {\n                return #imageLiteral(resourceName: \"Subscriber-Speaker-Mute-35\")\n            } else {\n                return #imageLiteral(resourceName: \"Subscriber-Speaker-35\")\n            }\n        }()\n        \n        muteButton.setImage(buttonImage, for: .normal)\n    }\n    \n    override func layoutSubviews() {\n        if let sub = subscriber, let subView = sub.view {\n            subView.frame = bounds\n            contentView.insertSubview(subView, belowSubview: muteButton)\n            \n            muteButton.isEnabled = true\n            muteButton.isHidden = false\n        }\n    }\n}\n\n// MARK: - OpenTok Methods\nextension ViewController {\n    func doPublish() {\n        swapCameraButton.isEnabled = true\n        muteMicButton.isEnabled = true\n        endCallButton.isEnabled = true\n        \n        if let pubView = publisher.view {\n            let publisherDimensions = CGSize(width: view.bounds.size.width / 4,\n                                             height: view.bounds.size.height / 6)\n            pubView.frame = CGRect(origin: CGPoint(x:collectionView.bounds.size.width - publisherDimensions.width,\n                                                   y:collectionView.bounds.size.height - publisherDimensions.height + collectionView.frame.origin.y),\n                                   size: publisherDimensions)\n            view.addSubview(pubView)\n            \n        }\n        \n        session.publish(publisher, error: &error)\n    }\n    \n    func doSubscribe(to stream: OTStream) {\n        if let subscriber = OTSubscriber(stream: stream, delegate: self) {\n            let indexPath = IndexPath(item: subscribers.count, section: 0)\n            subscribers[indexPath] = subscriber\n            session.subscribe(subscriber, error: &error)\n            \n            reloadCollectionView()\n        }\n    }\n    \n    func findSubscriber(byStreamId id: String) -> (IndexPath, OTSubscriber)? {\n        for (_, entry) in subscribers.enumerated() {\n            if let stream = entry.value.stream, stream.streamId == id {\n                return (entry.key, entry.value)\n            }\n        }\n        return nil\n    }\n    \n    func findSubscriberCell(byStreamId id: String) -> SubscriberCollectionCell? {\n        for cell in collectionView.visibleCells {\n            if let subscriberCell = cell as? SubscriberCollectionCell,\n                let subscriberOfCell = subscriberCell.subscriber,\n                (subscriberOfCell.stream?.streamId ?? \"\") == id\n            {\n                return subscriberCell\n            }\n        }\n        \n        return nil\n    }\n}\n\n// MARK: - OTSession delegate callbacks\nextension ViewController: OTSessionDelegate {\n    func sessionDidConnect(_ session: OTSession) {\n        print(\"Session connected\")\n        doPublish()\n    }\n    \n    func sessionDidDisconnect(_ session: OTSession) {\n        print(\"Session disconnected\")\n        subscribers.removeAll()\n        reloadCollectionView()\n    }\n    \n    func session(_ session: OTSession, streamCreated stream: OTStream) {\n        print(\"Session streamCreated: \\(stream.streamId)\")\n        if subscribers.count == 4 {\n            print(\"Sorry this sample only supports up to 4 subscribers :)\")\n            return\n        }\n        doSubscribe(to: stream)\n    }\n    \n    func session(_ session: OTSession, streamDestroyed stream: OTStream) {\n        print(\"Session streamDestroyed: \\(stream.streamId)\")\n        \n        guard let (index, subscriber) = findSubscriber(byStreamId: stream.streamId) else {\n            return\n        }\n        subscriber.view?.removeFromSuperview()\n        subscribers.removeValue(forKey: index)\n        reloadCollectionView()\n    }\n    \n    func session(_ session: OTSession, didFailWithError error: OTError) {\n        print(\"session Failed to connect: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTPublisher delegate callbacks\nextension ViewController: OTPublisherDelegate {\n    func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {\n    }\n    \n    func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {\n        print(\"Publisher failed: \\(error.localizedDescription)\")\n    }\n}\n\n// MARK: - OTSubscriber delegate callbacks\nextension ViewController: OTSubscriberDelegate {\n    func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {\n        print(\"Subscriber connected\")\n        reloadCollectionView()\n    }\n    \n    func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {\n        print(\"Subscriber failed: \\(error.localizedDescription)\")\n    }\n    \n    func subscriberVideoDataReceived(_ subscriber: OTSubscriber) {\n    }\n}\n\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA05375F91EB1637B00645696 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375F11EB1637B00645696 /* AppDelegate.swift */; };\n\t\tA05375FA1EB1637B00645696 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A05375F21EB1637B00645696 /* Assets.xcassets */; };\n\t\tA05375FB1EB1637B00645696 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375F31EB1637B00645696 /* LaunchScreen.storyboard */; };\n\t\tA05375FC1EB1637B00645696 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A05375F51EB1637B00645696 /* Main.storyboard */; };\n\t\tA05375FE1EB1637B00645696 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05375F81EB1637B00645696 /* ViewController.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tA05375F11EB1637B00645696 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tA05375F21EB1637B00645696 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tA05375F41EB1637B00645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375F61EB1637B00645696 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tA05375F71EB1637B00645696 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA05375F81EB1637B00645696 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tF829C8E51D9AB57700CDFBD5 /* Simple-Multiparty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Simple-Multiparty.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tF829C8E21D9AB57700CDFBD5 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA05375F01EB1637B00645696 /* Simple-Multiparty */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375F11EB1637B00645696 /* AppDelegate.swift */,\n\t\t\t\tA05375F21EB1637B00645696 /* Assets.xcassets */,\n\t\t\t\tA05375F31EB1637B00645696 /* LaunchScreen.storyboard */,\n\t\t\t\tA05375F51EB1637B00645696 /* Main.storyboard */,\n\t\t\t\tA05375F71EB1637B00645696 /* Info.plist */,\n\t\t\t\tA05375F81EB1637B00645696 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Simple-Multiparty\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF829C8DC1D9AB57700CDFBD5 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375F01EB1637B00645696 /* Simple-Multiparty */,\n\t\t\t\tF829C8E61D9AB57700CDFBD5 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF829C8E61D9AB57700CDFBD5 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF829C8E51D9AB57700CDFBD5 /* Simple-Multiparty.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tF829C8E41D9AB57700CDFBD5 /* Simple-Multiparty */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F829C8F71D9AB57700CDFBD5 /* Build configuration list for PBXNativeTarget \"Simple-Multiparty\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tF829C8E11D9AB57700CDFBD5 /* Sources */,\n\t\t\t\tF829C8E21D9AB57700CDFBD5 /* Frameworks */,\n\t\t\t\tF829C8E31D9AB57700CDFBD5 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Simple-Multiparty\";\n\t\t\tproductName = \"6.Simple-Multiparty\";\n\t\t\tproductReference = F829C8E51D9AB57700CDFBD5 /* Simple-Multiparty.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tF829C8DD1D9AB57700CDFBD5 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0800;\n\t\t\t\tLastUpgradeCheck = 1200;\n\t\t\t\tORGANIZATIONNAME = tokbox;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tF829C8E41D9AB57700CDFBD5 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = \"\";\n\t\t\t\t\t\tLastSwiftMigration = 1200;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = F829C8E01D9AB57700CDFBD5 /* Build configuration list for PBXProject \"Simple-Multiparty\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = F829C8DC1D9AB57700CDFBD5;\n\t\t\tproductRefGroup = F829C8E61D9AB57700CDFBD5 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tF829C8E41D9AB57700CDFBD5 /* Simple-Multiparty */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tF829C8E31D9AB57700CDFBD5 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375FC1EB1637B00645696 /* Main.storyboard in Resources */,\n\t\t\t\tA05375FA1EB1637B00645696 /* Assets.xcassets in Resources */,\n\t\t\t\tA05375FB1EB1637B00645696 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tF829C8E11D9AB57700CDFBD5 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA05375FE1EB1637B00645696 /* ViewController.swift in Sources */,\n\t\t\t\tA05375F91EB1637B00645696 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\tA05375F31EB1637B00645696 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375F41EB1637B00645696 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA05375F51EB1637B00645696 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tA05375F61EB1637B00645696 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tF829C8F51D9AB57700CDFBD5 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF829C8F61D9AB57700CDFBD5 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF829C8F81D9AB57700CDFBD5 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Simple-Multiparty/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Multi-Party\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF829C8F91D9AB57700CDFBD5 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Simple-Multiparty/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.tokbox.--Multi-Party\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tF829C8E01D9AB57700CDFBD5 /* Build configuration list for PBXProject \"Simple-Multiparty\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF829C8F51D9AB57700CDFBD5 /* Debug */,\n\t\t\t\tF829C8F61D9AB57700CDFBD5 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF829C8F71D9AB57700CDFBD5 /* Build configuration list for PBXNativeTarget \"Simple-Multiparty\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF829C8F81D9AB57700CDFBD5 /* Debug */,\n\t\t\t\tF829C8F91D9AB57700CDFBD5 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = F829C8DD1D9AB57700CDFBD5 /* Project object */;\n}\n"
  },
  {
    "path": "Simple-Multiparty/Simple-Multiparty.xcodeproj/xcshareddata/xcschemes/Simple-Multiparty.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"F829C8E41D9AB57700CDFBD5\"\n               BuildableName = \"Simple-Multiparty.app\"\n               BlueprintName = \"Simple-Multiparty\"\n               ReferencedContainer = \"container:Simple-Multiparty.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F829C8E41D9AB57700CDFBD5\"\n            BuildableName = \"Simple-Multiparty.app\"\n            BlueprintName = \"Simple-Multiparty\"\n            ReferencedContainer = \"container:Simple-Multiparty.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      enableGPUValidationMode = \"1\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F829C8E41D9AB57700CDFBD5\"\n            BuildableName = \"Simple-Multiparty.app\"\n            BlueprintName = \"Simple-Multiparty\"\n            ReferencedContainer = \"container:Simple-Multiparty.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"F829C8E41D9AB57700CDFBD5\"\n            BuildableName = \"Simple-Multiparty.app\"\n            BlueprintName = \"Simple-Multiparty\"\n            ReferencedContainer = \"container:Simple-Multiparty.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "travis_build.sh",
    "content": "#!/bin/sh\n\nset -e\n\ncd Basic-Video-Chat/\npod install\nxcodebuild -workspace Basic-Video-Chat.xcworkspace  -scheme Basic-Video-Chat -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Custom-Video-Driver/\npod install\nxcodebuild -workspace Custom-Video-Driver.xcworkspace  -scheme Custom-Video-Driver -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Custom-Audio-Driver/\npod install\nxcodebuild -workspace Custom-Audio-Driver.xcworkspace  -scheme Custom-Audio-Driver -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Screen-Sharing/\npod install\nxcodebuild -workspace Screen-Sharing.xcworkspace  -scheme Screen-Sharing -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Live-Photo-Capture/\npod install\nxcodebuild -workspace Live-Photo-Capture.xcworkspace  -scheme Live-Photo-Capture -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Simple-Multiparty/\npod install\nxcodebuild -workspace Simple-Multiparty.xcworkspace  -scheme Simple-Multiparty -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../Multiparty-UICollectionView/\npod install\nxcodebuild -workspace Multiparty-UICollectionView.xcworkspace  -scheme Multiparty-UICollectionView -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd ../CallKit/\npod install\nxcodebuild -workspace CallKitDemo.xcworkspace  -scheme CallKitDemo -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n\ncd Video-Transformers/\npod install\nxcodebuild -workspace Video-Transformers.xcworkspace  -scheme Video-Transformers -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=NO\n"
  }
]