master 4123c6ae17b7 cached
80 files
234.8 KB
60.0k tokens
108 symbols
1 requests
Download .txt
Showing preview only (258K chars total). Download the full file or copy to clipboard to get everything.
Repository: opentok/one-to-one-sample-apps
Branch: master
Commit: 4123c6ae17b7
Files: 80
Total size: 234.8 KB

Directory structure:
gitextract_smhvk9sm/

├── .github/
│   ├── CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── LICENSE
├── README.md
├── android/
│   ├── .gitignore
│   ├── OneToOneSample/
│   │   ├── .gitignore
│   │   ├── app/
│   │   │   ├── .gitignore
│   │   │   ├── build.gradle
│   │   │   ├── proguard-rules.pro
│   │   │   └── src/
│   │   │       └── main/
│   │   │           ├── AndroidManifest.xml
│   │   │           ├── java/
│   │   │           │   └── com/
│   │   │           │       └── tokbox/
│   │   │           │           └── android/
│   │   │           │               └── onetoonesample/
│   │   │           │                   ├── MainActivity.java
│   │   │           │                   ├── config/
│   │   │           │                   │   └── OpenTokConfig.java
│   │   │           │                   └── ui/
│   │   │           │                       ├── PreviewCameraFragment.java
│   │   │           │                       ├── PreviewControlFragment.java
│   │   │           │                       └── RemoteControlFragment.java
│   │   │           └── res/
│   │   │               ├── drawable/
│   │   │               │   ├── bckg_audio_only.xml
│   │   │               │   ├── bckg_icon.xml
│   │   │               │   ├── end_call_button.xml
│   │   │               │   ├── gradient_audionly.xml
│   │   │               │   ├── gradient_backg.xml
│   │   │               │   ├── initiate_call_button.xml
│   │   │               │   └── preview.xml
│   │   │               ├── layout/
│   │   │               │   ├── activity_main.xml
│   │   │               │   ├── preview_actionbar_fragment.xml
│   │   │               │   ├── preview_camera_fragment.xml
│   │   │               │   └── remote_actionbar_fragment.xml
│   │   │               ├── values/
│   │   │               │   ├── colors.xml
│   │   │               │   ├── dimens.xml
│   │   │               │   ├── strings.xml
│   │   │               │   └── styles.xml
│   │   │               ├── values-v21/
│   │   │               │   └── styles.xml
│   │   │               └── values-w820dp/
│   │   │                   └── dimens.xml
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       └── gradle-wrapper.properties
│   │   ├── gradle.properties
│   │   ├── gradlew
│   │   ├── gradlew.bat
│   │   └── settings.gradle
│   └── README.md
├── iOS/
│   ├── .gitignore
│   ├── OneToOneSample.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── OneToOneSample.xcscheme
│   ├── Podfile
│   ├── README.md
│   └── SampleApp/
│       ├── AppDelegate.h
│       ├── AppDelegate.m
│       ├── Assets.xcassets/
│       │   ├── AppIcon.appiconset/
│       │   │   └── Contents.json
│       │   ├── Contents.json
│       │   ├── audio.imageset/
│       │   │   └── Contents.json
│       │   ├── hangUp.imageset/
│       │   │   └── Contents.json
│       │   ├── mic.imageset/
│       │   │   └── Contents.json
│       │   ├── mutedMic.imageset/
│       │   │   └── Contents.json
│       │   ├── noAudio.imageset/
│       │   │   └── Contents.json
│       │   ├── noVideo.imageset/
│       │   │   └── Contents.json
│       │   ├── reverse cameras.imageset/
│       │   │   └── Contents.json
│       │   ├── startCall.imageset/
│       │   │   └── Contents.json
│       │   └── video.imageset/
│       │       └── Contents.json
│       ├── Base.lproj/
│       │   ├── LaunchScreen.storyboard
│       │   └── Main.storyboard
│       ├── Info.plist
│       ├── MainView.h
│       ├── MainView.m
│       ├── MainViewController.h
│       ├── MainViewController.m
│       ├── UIView+Helper.h
│       ├── UIView+Helper.m
│       └── main.m
└── js/
    ├── .eslintrc.json
    ├── .gitignore
    ├── .jsbeautifyrc
    ├── Procfile
    ├── README.md
    ├── package.json
    ├── public/
    │   ├── css/
    │   │   └── style.css
    │   ├── index.html
    │   └── js/
    │       ├── app.js
    │       └── components/
    │           └── opentok-acc-core.js
    └── server.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CONDUCT.md
================================================
**opentok/one-to-one-sample-apps** Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to OpenTok One-to-One Communication Sample Apps

## Code of Conduct

Please read our [Code of Conduct](https://github.com/opentok/one-to-one-sample-apps/blob/master/.github/CONDUCT.md). Intolerance, disrespect, and any of form of negativity will not be tolerated.

## Opening a new issue

1. Read *the entire* [README](https://github.com/opentok/one-to-one-sample-apps/blob/master/README.md).
* Search [open issues](https://github.com/opentok/one-to-one-sample-apps/issues) *and* [closed issues](https://github.com/opentok/one-to-one-sample-apps/issues?q=is%3Aissue+is%3Aclosed) to **avoid opening a duplicate issue.
* If your issue exists and you have some new information to contribute, you may add a comment to its thread.
* Otherwise, open a new issue with a clear title and description.
* Provide **all** of the following information:
  - Library version(s)
  - iOS, Android, or browser version(s)
  - Devices, simulators, or machines affected
  - Expected behavior vs actual behavior
  - Complete steps to reproduce the issue
  - Link to a project that exhibits the issue. It is recommended that you fork the repo and modify the demo project.
  - Screenshots, GIFs, or videos depicting the issue, if applicable.
  - Full crash log, if applicable.
  - A list of all possibly related issues.

## Submitting a pull request

1. Link to the issue that the pull request resolves. If the issue does not exist, create one.
2. Write unit tests that test your changes, if applicable.
3. Update header documentation as needed.
4. Follow the existing coding style. For more information, see [style guidelines](https://github.com/NYTimes/objective-c-style-guide).
5. Resolve any merge conflicts.
6. Squash your commits into a single commit.

## Did you read all of this?

Be sure you have visited all the links in this document.

### New issue checklist

When opening your new issue and filling out the checklist, you'll be asked for confirmation. Confirm that you've read this with these emoji: :muscle::sunglasses::facepunch:

> - [x] I have reviewed the contributing guidelines. Confirmation: :muscle::sunglasses::facepunch:


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## New issue checklist
<!-- Before submitting this issue, make sure you have done the following -->

- [ ] I have read all of the [`README`](https://github.com/opentok/one-to-one-sample-apps/blob/master/README.md) 
- [ ] I have searched [existing issues](https://github.com/opentok/one-to-one-sample-apps/issues?q=is%3Aissue+sort%3Acreated-desc) and **this is not a duplicate**.

### General information

- Library version(s):
- iOS/Android/Browser version(s):
- Devices/Simulators/Machine affected:
- Reproducible in the demo project? (Yes/No): 
- Related issues:

## Bug report

#### Expected behavior

> ...

#### Actual behavior

> ...

#### Steps to reproduce

> ...

#### Crash log? Screenshots? Videos? Sample project?

>...

## Question or Feature Request

> ...


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Pull request checklist

- [ ] All tests pass. Demo project builds and runs.
- [ ] I have resolved any merge conflicts. Confirmation: ____

#### This fixes issue #___.

## What's in this pull request?

>...


================================================
FILE: LICENSE
================================================
LICENSE

The MIT License (MIT)

Copyright (c) 2016 TokBox, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.




================================================
FILE: README.md
================================================
# DEPRECATED: OpenTok One-to-One Communication Sample App<br/>Version 1.3

<img src="https://assets.tokbox.com/img/vonage/Vonage_VideoAPI_black.svg" height="48px" alt="Tokbox is now known as Vonage" />

> This repository has been deprecated and is superseded by the following repositories:
>
> [accelerator-sample-apps-js](https://github.com/opentok/accelerator-sample-apps-js)
>
> [accelerator-sample-apps-android](https://github.com/opentok/accelerator-sample-apps-android)
>
> [accelerator-sample-apps-ios](https://github.com/opentok/accelerator-sample-apps-ios)

---

The OpenTok One-to-One Communication Sample App is an open-source solution that enables you to quickly get started in your development efforts to set up interoperable, production-quality audio/video communication between users.

With this sample app, you can:

- Start and end audio/visual communication between two users.
- Achieve interoperability between web and mobile devices.
- Mute or unmute audio.
- Enable or disable video.
- Control the camera to point in the forward direction or in the reverse direction (selfie mode).
- Customize the UI features and layout.

You can create mobile apps for Android and iOS, or embed the interactive session between users into any website. To get started with your development, visit the following sites:

- [OpenTok One-to-One Communication Sample App for Android](./android)
- [OpenTok One-to-One Communication Sample App for iOS](./iOS)
- [OpenTok One-to-One Communication Sample App for JavaScript](./js)

# Device interoperability with One-to-One communication

The OpenTok One-to-One Communication Sample App highlights the interoperability of web and mobile devices using the OpenTok platform. Regardless of the supported devices used, the OpenTok platform supports the ability of users to interact with each other and exchange audio and video. Even if the clients are on different platforms, they can both connect, publish, and subscribe to streams in the same session.

This sample app requires a **Session ID**, **Token**, and **API Key**. 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/).

For example, suppose one user is using a web (JS) version of the One-to-One Communication Sample App and another user is using a mobile version (Android or iOS). If they are both using the same **Session ID** and **API Key**, they can subscribe to each other’s audio and video streams, and the user interface rendered on both devices will allow them to interact with each other and take advantage of all the features of the sample app.

Use the following approach to try this out:

1. Configure a web and mobile user with the required **Session ID**, **Token**, and **API Key** values, using the same **Session ID** and **API Key** for each.

2. Start the web and mobile apps. You will observe the following interactions:

   - Both apps connect to the session.
   - Both apps start publishing and subscribing to each other’s streams.

3. Observe what happens for each user when you:

   - Enable or disable local audio/video on the mobile app.
   - Enable or disable local audio/video on the web app.
   - Enable or disable remote audio/video on the mobile app.
   - Enable or disable remote audio/video on the web app.

As you get started with this OpenTok sample, you will learn the best practices used to develop and manage the audio, video, and camera elements on mobile devices or in the browser. We recommend this is as your first step in delivering [Real Time Communications (WebRTC)](https://tokbox.com/about-webrtc) solutions on the OpenTok platform.

## Getting Help

We love to hear from you so if you have questions or comments, let us know! You can either:

- See <https://support.tokbox.com/> for support options
- Tweet at us! We're [@VonageDev on Twitter](https://twitter.com/VonageDev)
- Or [join the Vonage Developer Community Slack](https://developer.nexmo.com/community/slack)


================================================
FILE: android/.gitignore
================================================
# built components files
*.jar

# files for the dex VM
*.dex

# Java class files
*.class

# generated files
bin/
gen/

# Local configuration file (sdk path, etc)
local.properties

# OSX files
.DS_Store

# Android Studio files
*.iml
.idea/
.idea/workspace.xml
.gradle
build/
*.ipr
*.iws

#libs
*.so


================================================
FILE: android/OneToOneSample/.gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures


================================================
FILE: android/OneToOneSample/app/.gitignore
================================================
/build
/libs


================================================
FILE: android/OneToOneSample/app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"

    defaultConfig {
        applicationId "com.tokbox.android.onetosample"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.3"
        archivesBaseName = "OneToOneSample-$versionName"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/LICENSE'
    }
    configurations.all {

        resolutionStrategy {
            cacheChangingModulesFor 0, 'seconds'
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.+'
    compile 'com.android.support:design:25.+'
    compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
    compile 'com.opentok.android:opentok-accelerator-core:1.0.+'
}

================================================
FILE: android/OneToOneSample/app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/mserrano/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


================================================
FILE: android/OneToOneSample/app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.tokbox.android.onetoonesample">

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="23" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar"
        android:icon="@mipmap/ic_launcher"
        tools:replace="android:theme">

        <activity
            android:name="com.tokbox.android.onetoonesample.MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

================================================
FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/MainActivity.java
================================================
package com.tokbox.android.onetoonesample;

import android.Manifest;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.opentok.android.OpentokError;
import com.tokbox.android.onetoonesample.config.OpenTokConfig;
import com.tokbox.android.onetoonesample.ui.PreviewCameraFragment;
import com.tokbox.android.onetoonesample.ui.PreviewControlFragment;
import com.tokbox.android.onetoonesample.ui.RemoteControlFragment;
import com.tokbox.android.otsdkwrapper.listeners.AdvancedListener;
import com.tokbox.android.otsdkwrapper.listeners.BasicListener;
import com.tokbox.android.otsdkwrapper.listeners.ListenerException;
import com.tokbox.android.otsdkwrapper.listeners.PausableAdvancedListener;
import com.tokbox.android.otsdkwrapper.listeners.PausableBasicListener;
import com.tokbox.android.otsdkwrapper.utils.MediaType;
import com.tokbox.android.otsdkwrapper.utils.OTConfig;
import com.tokbox.android.otsdkwrapper.utils.PreviewConfig;
import com.tokbox.android.otsdkwrapper.wrapper.OTWrapper;

import java.util.UUID;
import android.widget.FrameLayout;


import java.util.UUID;

public class MainActivity extends AppCompatActivity implements PreviewControlFragment.PreviewControlCallbacks,
        RemoteControlFragment.RemoteControlCallbacks, PreviewCameraFragment.PreviewCameraCallbacks {

    private final String LOG_TAG = MainActivity.class.getSimpleName();

    private final String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA};
    private final int permsRequestCode = 200;

    private RelativeLayout mPreviewViewContainer;
    private RelativeLayout mRemoteViewContainer;
    private RelativeLayout.LayoutParams mLayoutParamsPreview;
    private String mRemoteId;
    private View mRemoteView;
    private TextView mAlert;

    //Audio only views
    private RelativeLayout mLocalAudioOnlyView;
    private RelativeLayout mRemoteAudioOnlyView;
    private ImageView mLocalAudioOnlyImage;

    //UI control bars fragments
    private PreviewControlFragment mPreviewFragment;
    private RemoteControlFragment mRemoteFragment;
    private PreviewCameraFragment mCameraFragment;
    private FragmentTransaction mFragmentTransaction;

    //Loading dialog
    ProgressDialog mProgressDialog;

    //Permissions
    private boolean mAudioPermission = false;
    private boolean mVideoPermission = false;

    //Communication status
    private boolean isConnected = false;
    private boolean isLocal = false;
    private boolean isCallInProgress = false;

    private OTWrapper mWrapper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(LOG_TAG, "onCreate");

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mPreviewViewContainer = (RelativeLayout) findViewById(R.id.publisherview);
        mRemoteViewContainer = (RelativeLayout) findViewById(R.id.subscriberview);
        mAlert = (TextView) findViewById(R.id.quality_warning);

        //remote and local audio only view
        mRemoteAudioOnlyView = (RelativeLayout) findViewById(R.id.remoteAudioOnlyView);
        mLocalAudioOnlyView = (RelativeLayout) findViewById(R.id.localAudioOnlyView);

        //request Marshmallow camera permission
        if (ContextCompat.checkSelfPermission(this, permissions[1]) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permissions, permsRequestCode);
            }
        } else {
            mVideoPermission = true;
            mAudioPermission = true;
        }

        //init the wrapper
        OTConfig config =
                new OTConfig.OTConfigBuilder(OpenTokConfig.SESSION_ID, OpenTokConfig.TOKEN,
                        OpenTokConfig.API_KEY).name("one-to-one-sample-app").subscribeAutomatically(false).subscribeToSelf(false).build();
        if ( config != null ) {
            mWrapper = new OTWrapper(MainActivity.this, config);
            mWrapper.addBasicListener(mBasicListener);
            mWrapper.addAdvancedListener(mAdvancedListener);

            if (mWrapper != null) {
                mWrapper.connect();
            }

            //init controls fragments
            if (savedInstanceState == null) {
                mFragmentTransaction = getSupportFragmentManager().beginTransaction();
                initCameraFragment(); //to swap camera
                initPreviewFragment(); //to enable/disable local media
                mFragmentTransaction.commitAllowingStateLoss();
            }

            //show connecting dialog
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setTitle("Please wait");
            mProgressDialog.setMessage("Connecting...");
            mProgressDialog.show();
        }
        else {
            Log.e(LOG_TAG, "OpenTok credentials are invalid");
            Toast.makeText(MainActivity.this, "Credentials are invalid", Toast.LENGTH_LONG).show();
            this.finish();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        reloadViews();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mWrapper != null) {
            mWrapper.pause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if ( mWrapper != null ){
            mWrapper.resume(true);
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if ( mWrapper != null && isConnected ){
            mWrapper.disconnect();
        }
    }

    @Override
    public void onRequestPermissionsResult(final int permsRequestCode, final String[] permissions,
                                           int[] grantResults) {
        switch (permsRequestCode) {
            case 200:
                mVideoPermission = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                mAudioPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED;

                if (!mVideoPermission || !mAudioPermission) {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder.setTitle(getResources().getString(R.string.permissions_denied_title));
                    builder.setMessage(getResources().getString(R.string.alert_permissions_denied));
                    builder.setPositiveButton("I'M SURE", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    builder.setNegativeButton("RE-TRY", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                requestPermissions(permissions, permsRequestCode);
                            }
                        }
                    });
                    builder.show();
                }
                break;
        }
    }

    public void showRemoteControlBar(View v) {
        if ( mRemoteFragment != null && mRemoteId != null ) {
            mRemoteFragment.show();
        }
    }

    public boolean isCallInProgress() {
        return isCallInProgress;
    }

    public OTWrapper getWrapper() {
        return mWrapper;
    }

    //Private methods
    //Init the local fragment
    private void initPreviewFragment() {
        mPreviewFragment = new PreviewControlFragment();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.actionbar_preview_fragment_container, mPreviewFragment).commit();
    }

    //Inti the remote fragment
    private void initRemoteFragment(String remoteId) {
        mRemoteFragment = new RemoteControlFragment();

        Bundle args = new Bundle();
        args.putString("remoteId", remoteId);
        mRemoteFragment.setArguments(args);

        getSupportFragmentManager().beginTransaction()
                .add(R.id.actionbar_remote_fragment_container, mRemoteFragment).commit();
    }

    //Init the local camera fragment
    private void initCameraFragment() {
        mCameraFragment = new PreviewCameraFragment();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.camera_preview_fragment_container, mCameraFragment).commit();
    }

    //Clean views
    private void cleanViewsAndControls() {
        if ( mRemoteId != null ) {
            mWrapper.removeRemote(mRemoteId);
            mRemoteView = null;
            setRemoteView(null);
        }
        if (isLocal) {
            isLocal = false;
            setLocalView(null);
        }
        if (mPreviewFragment != null)
            mPreviewFragment.restart();
        if (mRemoteFragment != null)
            mRemoteFragment.restart();
    }

    //Reload views
    private void reloadViews(){
        mRemoteViewContainer.removeAllViews();

        if (mRemoteId != null){
            setRemoteView(mWrapper.getRemoteStreamStatus(mRemoteId).getView());
        }
    }

    //Check if there are some connected remotes in the session
    private void checkRemotes(){
        if (mRemoteId != null){
            //add the remote participant to the communication
            mWrapper.addRemote(mRemoteId);
            //check the status of the remote video stream
            if (!mWrapper.isReceivedMediaEnabled(mRemoteId, MediaType.VIDEO)){
                onRemoteAudioOnly(true);
            }
            else {
                setRemoteView(mWrapper.getRemoteStreamStatus(mRemoteId).getView());
            }
        }
    }

    //Set the local participant view
    private void setLocalView(View localView){
        if (localView != null) {
            mPreviewViewContainer.removeAllViews();
            isLocal = true;
            mLayoutParamsPreview = new RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            if (mRemoteId != null) {
                mLayoutParamsPreview.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,
                        RelativeLayout.TRUE);
                mLayoutParamsPreview.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,
                        RelativeLayout.TRUE);
                mLayoutParamsPreview.width = (int) getResources().getDimension(R.dimen.preview_width);
                mLayoutParamsPreview.height = (int) getResources().getDimension(R.dimen.preview_height);
                mLayoutParamsPreview.rightMargin = (int) getResources().getDimension(R.dimen.preview_rightMargin);
                mLayoutParamsPreview.bottomMargin = (int) getResources().getDimension(R.dimen.preview_bottomMargin);
            }
            mPreviewViewContainer.addView(localView, mLayoutParamsPreview);
        }
        else {
            mPreviewViewContainer.removeAllViews();
        }
    }

    //Set the remote participant view
    private void setRemoteView(View remoteView) {
        if (mPreviewViewContainer.getChildCount() > 0) {
            setLocalView(mPreviewViewContainer.getChildAt(0)); //main preview view
        }
        if (remoteView != null) {
            //show remote view
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                    this.getResources().getDisplayMetrics().widthPixels, this.getResources()
                    .getDisplayMetrics().heightPixels);
            mRemoteViewContainer.removeView(remoteView);
            mRemoteViewContainer.addView(remoteView, layoutParams);
            mRemoteViewContainer.setClickable(true);
            if (mRemoteFragment != null)
                mRemoteFragment.show();
        } else { //view null --> remove view
            if (mRemoteViewContainer.getChildCount() > 0) {
                mRemoteViewContainer.removeAllViews();
            }
            mRemoteViewContainer.setClickable(false);
            mRemoteAudioOnlyView.setVisibility(View.GONE);
        }
    }

    //Set the remote audio only view
    private void onRemoteAudioOnly(boolean enabled) {
        if (mRemoteView != null) {
            if (enabled) {
                mRemoteView.setVisibility(View.GONE);
                mRemoteAudioOnlyView.setVisibility(View.VISIBLE);
            } else {
                mRemoteAudioOnlyView.setVisibility(View.GONE);
                mRemoteView.setVisibility(View.VISIBLE);
            }
        }
    }

    //Converts dp to real pixels, according to the screen density.
    private int dpToPx(int dp) {
        double screenDensity = this.getResources().getDisplayMetrics().density;
        return (int) (screenDensity * (double) dp);
    }

    //Basic Listener from OTWrapper
    private BasicListener mBasicListener =
            new PausableBasicListener(new BasicListener<OTWrapper>() {
                @Override
                public void onConnected(OTWrapper otWrapper, int participantsCount, String connId, String data) throws ListenerException {
                    Log.i(LOG_TAG, "Connected to the session. Number of participants: "+participantsCount);
                    isConnected = true;
                    mProgressDialog.dismiss();
                }

                @Override
                public void onDisconnected(OTWrapper otWrapper, int participantsCount, String connId, String data) throws ListenerException {
                    Log.i(LOG_TAG, "Connection dropped: "+connId);
                    if ( connId == mWrapper.getOwnConnId() ) {
                        Log.i(LOG_TAG, "Disconnected to the session");
                        cleanViewsAndControls();
                    }
                }

                @Override
                public void onPreviewViewReady(OTWrapper otWrapper, View localView) throws ListenerException {
                    Log.i(LOG_TAG, "Local preview view is ready");
                    setLocalView(localView);
                }

                @Override
                public void onPreviewViewDestroyed(OTWrapper otWrapper, View localView) throws ListenerException {
                    Log.i(LOG_TAG, "Local preview view is destroyed");
                    setLocalView(null);
                }

                @Override
                public void onRemoteViewReady(OTWrapper otWrapper, View remoteView, String remoteId, String data) throws ListenerException {
                    Log.i(LOG_TAG, "Remove view is ready");
                    if ( remoteId == mRemoteId ) {
                        if (isCallInProgress()) {
                            setRemoteView(remoteView);
                        }
                        mRemoteView = remoteView;
                    }
                }

                @Override
                public void onRemoteViewDestroyed(OTWrapper otWrapper, View remoteView, String remoteId) throws ListenerException {
                    Log.i(LOG_TAG, "Remote view is destroyed");
                    setRemoteView(null);
                    mRemoteView = null;
                }


                @Override
                public void onStartedPublishingMedia(OTWrapper otWrapper, boolean screensharing) throws ListenerException {
                    Log.i(LOG_TAG, "Local started streaming video.");
                    //Check if there are some connected remotes
                    checkRemotes();
                }

                @Override
                public void onStoppedPublishingMedia(OTWrapper otWrapper, boolean screensharing) throws ListenerException {
                    Log.i(LOG_TAG, "Local stopped streaming video.");
                }

                @Override
                public void onRemoteJoined(OTWrapper otWrapper, String remoteId) throws ListenerException {
                    Log.i(LOG_TAG, "A new remote joined.");
                    if (mRemoteId == null){ //one-to-one, the first to arrive, will be the used
                        MainActivity.this.mRemoteId = remoteId;
                        initRemoteFragment(remoteId);
                        if (mWrapper.isPublishing()){
                            mWrapper.addRemote(mRemoteId);
                        }
                    }
                }

                @Override
                public void onRemoteLeft(OTWrapper otWrapper, String remoteId) throws ListenerException {
                    Log.i(LOG_TAG, "A new remote left.");
                    if ( mRemoteId != null && remoteId == mRemoteId ) { //one-to-one
                        mRemoteId = null;
                    }
                }

                @Override
                public void onRemoteVideoChanged(OTWrapper otWrapper, String remoteId, String reason, boolean videoActive, boolean subscribed) throws ListenerException {
                    Log.i(LOG_TAG, "Remote video changed");
                    if (isCallInProgress) {
                        if (reason.equals("quality")) {
                            //network quality alert
                            mAlert.setBackgroundResource(R.color.quality_alert);
                            mAlert.setTextColor(MainActivity.this.getResources().getColor(R.color.white));
                            mAlert.bringToFront();
                            mAlert.setVisibility(View.VISIBLE);
                            mAlert.postDelayed(new Runnable() {
                                public void run() {
                                    mAlert.setVisibility(View.GONE);
                                }
                            }, 7000);
                        }

                        if (!videoActive) {
                            onRemoteAudioOnly(true); //video is not active
                        } else {
                            onRemoteAudioOnly(false);
                        }
                    }
                }

                @Override
                public void onError(OTWrapper otWrapper, OpentokError error) throws ListenerException {
                    Log.i(LOG_TAG, "Error "+error.getErrorCode()+"-"+error.getMessage());

                    Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
                    mWrapper.disconnect(); //end communication
                    mProgressDialog.dismiss();
                    cleanViewsAndControls(); //restart views
                }
            });

    //Advanced Listener from OTWrapper
    private AdvancedListener mAdvancedListener =
            new PausableAdvancedListener(new AdvancedListener<OTWrapper>() {

                @Override
                public void onCameraChanged(OTWrapper otWrapper) throws ListenerException {
                    Log.i(LOG_TAG, "The camera changed");
                }

                @Override
                public void onReconnecting(OTWrapper otWrapper) throws ListenerException {
                    Log.i(LOG_TAG, "The session is reconnecting.");
                    Toast.makeText(MainActivity.this, R.string.reconnecting, Toast.LENGTH_LONG).show();
                }

                @Override
                public void onReconnected(OTWrapper otWrapper) throws ListenerException {
                    Log.i(LOG_TAG, "The session reconnected.");
                    Toast.makeText(MainActivity.this, R.string.reconnected, Toast.LENGTH_LONG).show();
                }

                @Override
                public void onVideoQualityWarning(OTWrapper otWrapper, String remoteId) throws ListenerException {
                    Log.i(LOG_TAG, "The quality has degraded");
                    mAlert.setBackgroundResource(R.color.quality_warning);
                    mAlert.setTextColor(MainActivity.this.getResources().getColor(R.color.warning_text));
                    mAlert.bringToFront();
                    mAlert.setVisibility(View.VISIBLE);
                    mAlert.postDelayed(new Runnable() {
                        public void run() {
                            mAlert.setVisibility(View.GONE);
                        }
                    }, 7000);
                }

                @Override
                public void onVideoQualityWarningLifted(OTWrapper otWrapper, String remoteId) throws ListenerException {
                    Log.i(LOG_TAG, "The quality has improved");
                }

                @Override
                public void onError(OTWrapper otWrapper, OpentokError error) throws ListenerException {
                    Log.i(LOG_TAG, "Error " + error.getErrorCode() + "-" + error.getMessage());
                    Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
                    mWrapper.disconnect(); //end communication
                    mProgressDialog.dismiss();
                    cleanViewsAndControls(); //restart views
                }
            });
    //Audio local button event
    @Override
    public void onDisableLocalAudio(boolean audio) {
        if (mWrapper != null) {
            mWrapper.enableLocalMedia(MediaType.AUDIO, audio);
        }
    }

    //Video local button event
    @Override
    public void onDisableLocalVideo(boolean video) {
        if (mWrapper != null) {
            mWrapper.enableLocalMedia(MediaType.VIDEO, video);
            if (mRemoteId != null) {
                if (!video) {
                    mLocalAudioOnlyImage = new ImageView(this);
                    mLocalAudioOnlyImage.setImageResource(R.drawable.avatar);
                    mLocalAudioOnlyImage.setBackgroundResource(R.drawable.bckg_audio_only);
                    mPreviewViewContainer.addView(mLocalAudioOnlyImage, mLayoutParamsPreview);
                } else {
                    mPreviewViewContainer.removeView(mLocalAudioOnlyImage);
                }
            } else {
                if (!video) {
                    mLocalAudioOnlyView.setVisibility(View.VISIBLE);
                    mPreviewViewContainer.addView(mLocalAudioOnlyView);
                } else {
                    mLocalAudioOnlyView.setVisibility(View.GONE);
                    mPreviewViewContainer.removeView(mLocalAudioOnlyView);
                }
            }
        }
    }

    //Remote control callbacks
    @Override
    public void onDisableRemoteAudio(boolean audio) {
        if (mWrapper != null) {
            mWrapper.enableReceivedMedia(mRemoteId, MediaType.AUDIO, audio);
        }
    }

    @Override
    public void onDisableRemoteVideo(boolean video) {
        if (mWrapper != null) {
            mWrapper.enableReceivedMedia(mRemoteId, MediaType.VIDEO, video);
        }
    }

    //Camera control callback
    @Override
    public void onCameraSwap() {
        if (mWrapper != null) {
            mWrapper.cycleCamera();
        }
    }

    @Override
    public void onCall() {
        if (mWrapper != null && isConnected) {
            if (!isCallInProgress) {
                mWrapper.startPublishingMedia(new PreviewConfig.PreviewConfigBuilder().
                        name("Tokboxer").build(), false);
                if ( mPreviewFragment != null ) {
                    mPreviewFragment.setEnabled(true);
                }
                isCallInProgress = true;
            } else {
                mWrapper.stopPublishingMedia(false);
                isCallInProgress = false;
                cleanViewsAndControls();
            }
        }
    }
}


================================================
FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/config/OpenTokConfig.java
================================================
package com.tokbox.android.onetoonesample.config;

public class OpenTokConfig {

    // *** Fill the following variables using your own Project info from the OpenTok dashboard  ***
    // ***                      https://dashboard.tokbox.com/projects                           ***
    // Replace with a generated Session ID
    public static final String SESSION_ID = "";
    // Replace with a generated token (from the dashboard or using an OpenTok server SDK)
    public static final String TOKEN = "";
    // Replace with your OpenTok API key
    public static final String API_KEY = "";

}

================================================
FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewCameraFragment.java
================================================
package com.tokbox.android.onetoonesample.ui;

import android.app.Activity;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RelativeLayout;

import com.tokbox.android.onetoonesample.MainActivity;
import com.tokbox.android.onetoonesample.R;

public class PreviewCameraFragment extends Fragment {
    private static final String LOGTAG = PreviewCameraFragment.class.getSimpleName();

    private View mRootView;
    private ImageButton mCameraBtn;

    private PreviewCameraCallbacks mCameraCallbacks = cameraCallbacks;

    public interface PreviewCameraCallbacks {
        void onCameraSwap();
    }

    private static PreviewCameraCallbacks cameraCallbacks = new PreviewCameraCallbacks() {
        @Override
        public void onCameraSwap() {}

    };

    private View.OnClickListener mBtnClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            cameraSwap();
        }
    };

    @Override
    public void onAttach(Context context) {
        Log.i(LOGTAG, "OnAttach PreviewCameraFragment");

        super.onAttach(context);
        this.mCameraCallbacks = (PreviewCameraCallbacks) context;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            this.mCameraCallbacks = (PreviewCameraCallbacks) activity;
        }
    }

    @Override
    public void onDetach() {
        Log.i(LOGTAG, "OnDetach PreviewCameraFragment");

        super.onDetach();

        mCameraCallbacks = cameraCallbacks;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i(LOGTAG, "onCreate PreviewCameraFragment");

        mRootView = inflater.inflate(R.layout.preview_camera_fragment, container, false);
        mCameraBtn = (ImageButton) mRootView.findViewById(R.id.camera);
        mCameraBtn.setOnClickListener(mBtnClickListener);

        return mRootView;
    }

    public void cameraSwap() {
        mCameraCallbacks.onCameraSwap();
    }

}


================================================
FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewControlFragment.java
================================================
package com.tokbox.android.onetoonesample.ui;

import android.app.Activity;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RelativeLayout;

import com.tokbox.android.onetoonesample.MainActivity;
import com.tokbox.android.onetoonesample.R;
import com.tokbox.android.otsdkwrapper.utils.MediaType;


public class PreviewControlFragment extends Fragment {
    private static final String LOGTAG = MainActivity.class.getName();

    private MainActivity mActivity;

    private View rootView;
    private ImageButton mAudioBtn;
    private ImageButton mVideoBtn;
    private ImageButton mCallBtn;

    private VectorDrawableCompat drawableStartCall;
    private VectorDrawableCompat drawableEndCall;
    private VectorDrawableCompat drawableBckBtn;

    private PreviewControlCallbacks mControlCallbacks = previewCallbacks;

    public interface PreviewControlCallbacks {

        void onDisableLocalAudio(boolean audio);

        void onDisableLocalVideo(boolean video);

        void onCall();
    }

    private static PreviewControlCallbacks previewCallbacks = new PreviewControlCallbacks() {
        @Override
        public void onDisableLocalAudio(boolean audio) { }

        @Override
        public void onDisableLocalVideo(boolean video) { }

        @Override
        public void onCall() { }

    };

    private View.OnClickListener mBtnClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.localAudio:
                    updateLocalAudio();
                    break;

                case R.id.localVideo:
                    updateLocalVideo();
                    break;

                case R.id.call:
                    updateCall();
                    break;
            }
        }
    };

    @Override
    public void onAttach(Context context) {
        Log.i(LOGTAG, "OnAttach PreviewControlFragment");

        super.onAttach(context);

        this.mActivity = (MainActivity) context;
        this.mControlCallbacks = (PreviewControlCallbacks) context;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {

            this.mActivity = (MainActivity) activity;
            this.mControlCallbacks = (PreviewControlCallbacks) activity;
        }
    }

    @Override
    public void onDetach() {
        Log.i(LOGTAG, "onDetach PreviewControlFragment");

        super.onDetach();

        mControlCallbacks = previewCallbacks;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Retain this fragment across configuration changes.
        setRetainInstance(true);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i(LOGTAG, "OnCreate PreviewControlFragment");

        rootView = inflater.inflate(R.layout.preview_actionbar_fragment, container, false);
        mAudioBtn = (ImageButton) rootView.findViewById(R.id.localAudio);
        mVideoBtn = (ImageButton) rootView.findViewById(R.id.localVideo);
        mCallBtn = (ImageButton) rootView.findViewById(R.id.call);

        drawableStartCall = VectorDrawableCompat.create(getResources(), R.drawable.initiate_call_button, null);
        drawableEndCall = VectorDrawableCompat.create(getResources(), R.drawable.end_call_button, null);
        drawableBckBtn = VectorDrawableCompat.create(getResources(), R.drawable.bckg_icon, null);

        mAudioBtn.setImageResource(mActivity.getWrapper().isLocalMediaEnabled(MediaType.AUDIO)
                ? R.drawable.mic_icon
                : R.drawable.muted_mic_icon);
        mAudioBtn.setBackground(drawableBckBtn);

        mVideoBtn.setImageResource(mActivity.getWrapper().isLocalMediaEnabled(MediaType.VIDEO)
                ? R.drawable.video_icon
                : R.drawable.no_video_icon);
        mVideoBtn.setBackground(drawableBckBtn);

        mCallBtn.setImageResource(mActivity.isCallInProgress()
                ? R.drawable.hang_up
                : R.drawable.start_call);

        mCallBtn.setBackground(mActivity.isCallInProgress()
                ? drawableEndCall
                : drawableStartCall);

        mCallBtn.setOnClickListener(mBtnClickListener);

        setEnabled(mActivity.isCallInProgress());

        return rootView;
    }

    public void updateLocalAudio() {
        if (!mActivity.getWrapper().isLocalMediaEnabled(MediaType.AUDIO)) {
            mControlCallbacks.onDisableLocalAudio(true);
            mAudioBtn.setImageResource(R.drawable.mic_icon);
        } else {
            mControlCallbacks.onDisableLocalAudio(false);
            mAudioBtn.setImageResource(R.drawable.muted_mic_icon);
        }
    }

    public void updateLocalVideo() {
        if (!mActivity.getWrapper().isLocalMediaEnabled(MediaType.VIDEO)){
            mControlCallbacks.onDisableLocalVideo(true);
            mVideoBtn.setImageResource(R.drawable.video_icon);
        } else {
            mControlCallbacks.onDisableLocalVideo(false);
            mVideoBtn.setImageResource(R.drawable.no_video_icon);
        }
    }

    public void updateCall() {
        mCallBtn.setImageResource(!mActivity.isCallInProgress()
                ? R.drawable.hang_up
                : R.drawable.start_call);

        mCallBtn.setBackground(!mActivity.isCallInProgress()
                ? drawableEndCall
                : drawableStartCall);

        if ( mControlCallbacks != null )
            mControlCallbacks.onCall();
    }

    public void setEnabled(boolean enabled) {
        if (mVideoBtn != null && mAudioBtn != null) {
            if (enabled) {
                mAudioBtn.setOnClickListener(mBtnClickListener);
                mVideoBtn.setOnClickListener(mBtnClickListener);
            } else {
                mAudioBtn.setOnClickListener(null);
                mVideoBtn.setOnClickListener(null);
                mAudioBtn.setImageResource(R.drawable.mic_icon);
                mVideoBtn.setImageResource(R.drawable.video_icon);
            }
        }
    }

    public void restart() {
        setEnabled(false);
        mCallBtn.setBackground(drawableStartCall);
        mCallBtn.setImageResource(R.drawable.start_call);

    }
}

================================================
FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/RemoteControlFragment.java
================================================
package com.tokbox.android.onetoonesample.ui;

import android.app.Activity;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RelativeLayout;

import com.tokbox.android.onetoonesample.MainActivity;
import com.tokbox.android.onetoonesample.R;
import com.tokbox.android.otsdkwrapper.utils.MediaType;

public class RemoteControlFragment extends Fragment {
    private static final String LOGTAG = RemoteControlFragment.class.getSimpleName();
    private static final int ANIMATION_DURATION = 7000;

    private MainActivity mActivity;

    private RelativeLayout mContainer;
    private View mRootView;
    private ImageButton mAudioBtn;
    private ImageButton mVideoBtn;

    private RemoteControlCallbacks mControlCallbacks = remoteCallbacks;

    private String mRemoteId;

    public interface RemoteControlCallbacks {
        void onDisableRemoteAudio(boolean audio);

        void onDisableRemoteVideo(boolean video);
    }

    private static RemoteControlCallbacks remoteCallbacks = new RemoteControlCallbacks() {
        @Override
        public void onDisableRemoteAudio(boolean audio) { }

        @Override
        public void onDisableRemoteVideo(boolean video) { }
    };

    private View.OnClickListener mBtnClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.remoteAudio:
                    updateRemoteAudio();
                    break;

                case R.id.remoteVideo:
                    updateRemoteVideo();
                    break;
            }
        }
    };

    @Override
    public void onAttach(Context context) {
        Log.i(LOGTAG, "OnAttach RemoteControlFragment");

        super.onAttach(context);

        this.mActivity = (MainActivity) context;
        this.mControlCallbacks = (RemoteControlCallbacks) context;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            this.mActivity = (MainActivity) activity;
            this.mControlCallbacks = (RemoteControlCallbacks) activity;
        }

        if ( mRemoteId == null ) {
            mRemoteId = getArguments().getString("remoteId");
        }
    }

    @Override
    public void onDetach() {
        Log.i(LOGTAG, "OnDetach RemoteControlFragment");
        super.onDetach();
        mControlCallbacks = remoteCallbacks;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i(LOGTAG, "OnCreate RemoteControlFragment");

        mRootView = inflater.inflate(R.layout.remote_actionbar_fragment, container, false);

        mContainer = (RelativeLayout) this.mActivity.findViewById(R.id.actionbar_remote_fragment_container);
        mAudioBtn = (ImageButton) mRootView.findViewById(R.id.remoteAudio);
        mVideoBtn = (ImageButton) mRootView.findViewById(R.id.remoteVideo);

        mAudioBtn.setOnClickListener(mBtnClickListener);
        mVideoBtn.setOnClickListener(mBtnClickListener);
        return mRootView;
    }

    public void updateRemoteAudio(){
        if(mRemoteId != null && !mActivity.getWrapper().isReceivedMediaEnabled(mRemoteId, MediaType.AUDIO)){
            mControlCallbacks.onDisableRemoteAudio(true);
            mAudioBtn.setImageResource(R.drawable.audio);
        }
        else {
            mControlCallbacks.onDisableRemoteAudio(false);
            mAudioBtn.setImageResource(R.drawable.no_audio);
        }
    }

    public void updateRemoteVideo(){
        if(mRemoteId != null && !mActivity.getWrapper().isReceivedMediaEnabled(mRemoteId, MediaType.VIDEO)){
            mControlCallbacks.onDisableRemoteVideo(true);
            mVideoBtn.setImageResource(R.drawable.video_icon);
        }
        else {
            mControlCallbacks.onDisableRemoteVideo(false);
            mVideoBtn.setImageResource(R.drawable.no_video_icon);
        }
    }

    public void show(){
        mContainer.setVisibility(View.VISIBLE);
        mRootView.setVisibility(View.VISIBLE);

        mContainer.postDelayed(new Runnable() {
            public void run() {
                mContainer.setVisibility(View.INVISIBLE);
            }
        }, ANIMATION_DURATION);
    }

    private void setEnabled(boolean enabled) {
        if (mVideoBtn != null && mAudioBtn != null) {
            if (!enabled) {
                mAudioBtn.setImageResource(R.drawable.audio);
                mVideoBtn.setImageResource(R.drawable.video_icon);
            }
        }
    }

    public void restart() {
        setEnabled(false);
        mContainer.setVisibility(View.INVISIBLE);
    }

}


================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/bckg_audio_only.xml
================================================
<shape
    xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <solid android:color="@color/audiOnlyBackground"/>
    <stroke android:color="@color/white" android:width="1dp"/>
</shape>

================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/bckg_icon.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="106dp"
        android:height="106dp"
        android:viewportWidth="106.0"
        android:viewportHeight="106.0">
    <path
        android:pathData="M1.26,52.61a51.93,51.91 0,1 0,103.87 0a51.93,51.91 0,1 0,-103.87 0z"
        android:strokeWidth="1"
        android:fillColor="#66000000"
        android:strokeColor="#979797" />
</vector>


================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/end_call_button.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="105dp"
    android:height="105dp"
    android:viewportWidth="105.0"
    android:viewportHeight="105.0">
    <path
        android:pathData="M0.25,52.68a51.93,51.91 0,1 0,103.87 0a51.93,51.91 0,1 0,-103.87 0z"
        android:strokeWidth="1"
        android:fillColor="@color/endCall"
        android:strokeColor="#00000000"/>
</vector>


================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/gradient_audionly.xml
================================================
<shape
    xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="@color/gradientAudioOnlyStart"
        android:endColor="@color/gradientAudioOnlyEnd"
        android:angle="270" />
</shape>

================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/gradient_backg.xml
================================================
<shape
    xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="@color/gradientStart"
        android:endColor="@color/gradientEnd"
        android:angle="270" />
</shape>

================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/initiate_call_button.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="105dp"
        android:height="105dp"
        android:viewportWidth="105.0"
        android:viewportHeight="105.0">
    <path
        android:pathData="M0.25,52.68a51.93,51.91 0,1 0,103.87 0a51.93,51.91 0,1 0,-103.87 0z"
        android:strokeWidth="1"
        android:fillColor="@color/startCall"
        android:strokeColor="#00000000"/>
</vector>


================================================
FILE: android/OneToOneSample/app/src/main/res/drawable/preview.xml
================================================
<shape
    xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <stroke android:color="@color/white" android:width="1dp"/>
</shape>

================================================
FILE: android/OneToOneSample/app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/gradient_backg"
    android:keepScreenOn="true"
    tools:context="com.tokbox.android.onetoonesample.MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/quality_warning"
            android:layout_width="match_parent"
            android:layout_height="@dimen/alert_bar_height"
            android:background="@color/quality_warning"
            android:gravity="center"
            android:text="@string/network_quality"
            android:textColor="@color/warning_text"
            android:textSize="@dimen/alert_text"
            android:visibility="gone"></TextView>

        <RelativeLayout
            android:id="@+id/subscriberview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clickable="false"
            android:gravity="center_horizontal"
            android:onClick="showRemoteControlBar">

            <RelativeLayout
                android:id="@+id/remoteAudioOnlyView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true"
                android:background="@drawable/gradient_audionly"
                android:visibility="gone" >

                <ImageView
                    android:id="@+id/avatar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:layout_centerHorizontal="true"
                    android:layout_marginBottom="30dp"
                    android:src="@drawable/avatar" />

            </RelativeLayout>

        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/publisherview"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <RelativeLayout
                android:id="@+id/localAudioOnlyView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true"
                android:background="@drawable/gradient_audionly"
                android:visibility="gone" >

                <ImageView
                    android:id="@+id/localAvatar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:layout_centerHorizontal="true"
                    android:layout_marginBottom="30dp"
                    android:src="@drawable/avatar" />

            </RelativeLayout>
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/actionbar_preview_fragment_container"
            android:layout_width="match_parent"
            android:layout_height="@dimen/action_bar_height"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:visibility="visible"></RelativeLayout>

        <RelativeLayout
            android:id="@+id/camera_preview_fragment_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="21.5dp"
            android:layout_marginTop="37.5dp"
            android:visibility="visible"></RelativeLayout>

        <RelativeLayout
            android:id="@+id/actionbar_remote_fragment_container"
            android:layout_width="@dimen/action_bar_width"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="21.5dp"
            android:layout_marginTop="37.5dp"
            android:visibility="visible"></RelativeLayout>
    </RelativeLayout>


</android.support.design.widget.CoordinatorLayout>


================================================
FILE: android/OneToOneSample/app/src/main/res/layout/preview_actionbar_fragment.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutPreviewActionBar"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/previewFragment"
        android:layout_width="fill_parent"
        android:layout_height="@dimen/action_bar_height"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true">

        <ImageButton
            android:id="@+id/localVideo"
            android:layout_width="@dimen/icon_width"
            android:layout_height="@dimen/icon_height"
            android:layout_centerVertical="true"
            android:layout_marginRight="14.1dp"
            android:layout_toLeftOf="@+id/call"
            android:background="@drawable/bckg_icon"
            android:src="@drawable/video_icon" />

        <ImageButton
            android:id="@+id/call"
            android:layout_width="@dimen/icon_width"
            android:layout_height="@dimen/icon_height"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:background="@drawable/initiate_call_button"
            android:clickable="true"
            android:src="@drawable/start_call" />

        <ImageButton
            android:id="@+id/localAudio"
            android:layout_width="@dimen/icon_width"
            android:layout_height="@dimen/icon_height"
            android:layout_centerVertical="true"
            android:layout_marginLeft="14.1dp"
            android:layout_toRightOf="@+id/call"
            android:background="@drawable/bckg_icon"
            android:src="@drawable/mic_icon" />

    </RelativeLayout>

</RelativeLayout>

================================================
FILE: android/OneToOneSample/app/src/main/res/layout/preview_camera_fragment.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutPreviewCamera"
    android:layout_width="match_parent"
    android:layout_height="@dimen/action_bar_height"
    android:layout_alignParentTop="true">

    <ImageButton
        android:id="@+id/camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:background="@null"
        android:src="@drawable/camera" />

</RelativeLayout>


================================================
FILE: android/OneToOneSample/app/src/main/res/layout/remote_actionbar_fragment.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutPreviewActionBar"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:visibility="gone">

    <RelativeLayout
        android:id="@+id/remoteFragment"
        android:layout_width="@dimen/action_bar_width"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true">

        <ImageButton
            android:id="@+id/remoteVideo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:enabled="false"
            android:src="@drawable/video_icon" />

        <ImageButton
            android:id="@+id/remoteAudio"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/remoteVideo"
            android:layout_marginTop="25dp"
            android:background="@null"
            android:enabled="false"
            android:src="@drawable/audio" />

    </RelativeLayout>

</RelativeLayout>

================================================
FILE: android/OneToOneSample/app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="gradientStart">#5B5B5B</color>
    <color name="gradientEnd">#393939</color>
    <color name="gradientAudioOnlyStart">#343434</color>
    <color name="gradientAudioOnlyEnd">#6e6e6e</color>
    <color name="audiOnlyBackground">#7e7e7e</color>
    <color name="white">#ffffff</color>
    <color name="black">#000000</color>
    <color name="startCall">#6aadbf</color>
    <color name="endCall">#cb1e28</color>
    <color name="quality_alert">#cb1e28</color>
    <color name="quality_warning">#fef9c8</color>
    <color name="warning_text">#ad7212</color>
</resources>


================================================
FILE: android/OneToOneSample/app/src/main/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="border">1dp</dimen>
    <dimen name="action_bar_height">71dp</dimen>
    <dimen name="action_bar_width">71dp</dimen>
    <dimen name="icon_width">52dp</dimen>
    <dimen name="icon_height">52dp</dimen>
    <dimen name="alert_bar_height">30dp</dimen>
    <dimen name="alert_text">14sp</dimen>
    <dimen name="preview_width">90dp</dimen>
    <dimen name="preview_height">78dp</dimen>
    <dimen name="preview_rightMargin">24dp</dimen>
    <dimen name="preview_bottomMargin">75dp</dimen>
</resources>


================================================
FILE: android/OneToOneSample/app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">OneToOneSample</string>
    <string name="network_quality">Network connection is unstable.</string>
    <string name="reconnecting">The session is reconnecting</string>
    <string name="reconnected">The session reconnected</string>
    <string name="permissions_denied_title">Permissions Denied</string>
    <string name="permissions_denied">Cannot use this app without requested permission. Please, grant audio and video permissions</string>
    <string name="alert_permissions_denied">Without these permissions the app is unable to make call.Are you sure you want to deny these permissions?</string>
</resources>


================================================
FILE: android/OneToOneSample/app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>


================================================
FILE: android/OneToOneSample/app/src/main/res/values-v21/styles.xml
================================================
<resources>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>


================================================
FILE: android/OneToOneSample/app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>


================================================
FILE: android/OneToOneSample/build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url  "http://tokbox.bintray.com/maven"
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


================================================
FILE: android/OneToOneSample/gradle/wrapper/gradle-wrapper.properties
================================================
#Thu Jan 19 16:41:06 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip


================================================
FILE: android/OneToOneSample/gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

================================================
FILE: android/OneToOneSample/gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: android/OneToOneSample/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: android/OneToOneSample/settings.gradle
================================================
include ':app'


================================================
FILE: android/README.md
================================================
![logo](../tokbox-logo.png)

# OpenTok One-to-One Communication Sample App for Android

## Quick start

This section shows you how to prepare, build, and run the sample application.

### Install the project files

1. Clone the [OpenTok One-to-One Communication Sample App for Android repository](https://github.com/opentok/one-to-one-sample-apps/tree/master/android) from GitHub.
1. Start Android Studio.
1. In the **Quick Start** panel, click **Open an existing Android Studio Project**.
1. Navigate to the **android** folder, select the **OnetoOneSample** folder, and click **Choose**.


### Add the Accelerator Core Android

There are two options for installing the OpenTok SDK included in the Accelerator Pack Common for Android:


#### Using the repository

1. Clone the [OpenTok Accelerator Core repo](https://github.com/opentok/accelerator-core-android).
2. From your app project, right-click the app name and select **New > Module > Import Gradle Project**.
3. Navigate to the directory in which you cloned **OpenTok Accelerator Pack**, select **accelerator-core**, and click **Finish**.
4. Open the **build.gradle** file for the app and ensure the following lines have been added to the `dependencies` section:

```
compile project(':accelerator-core-android')

```

#### Using Maven

1. Modify the `build.gradle` for your solution and add the following code snippet to the section labeled `repositories`:

  ```gradle
    maven { url  "http://tokbox.bintray.com/maven" }
  ```

1. Modify the `build.gradle` for your activity and add the following code snippet to the section labeled `dependencies`:
  
  ```gradle
    compile 'com.opentok.android:accelerator-core-android:+'
  ```

### Configure and build the app

Configure the sample app code. Then, build and run the app.

1. Get values for **API Key**, **Session ID**, and **Token**. See [OpenTok One-to-One Communication Sample App home page](../README.md) for important information.

In Android Studio, open **OpenTokConfig.java** and replace the following empty strings with the corresponding **API Key**, **Session ID**, and **Token** values:

  ```java
    // Replace with a generated Session ID
    public static final String SESSION_ID = "";

    // Replace with a generated token
    public static final String TOKEN = "";

    // Replace with your OpenTok API key
    public static final String API_KEY = "";
  ```

  ```java
    //init the wrapper
    OTConfig config =
          new OTConfig.OTConfigBuilder(OpenTokConfig.SESSION_ID, OpenTokConfig.TOKEN,
            OpenTokConfig.API_KEY).name("one-to-one-sample-app").subscribeAutomatically(true).subscribeToSelf(false).build();
    
    if ( config != null ) {
      mWrapper = new OTWrapper(MainActivity.this, config);
      mWrapper.addBasicListener(mBasicListener);
      mWrapper.addAdvancedListener(mAdvancedListener);

      //...
    }
  ```

## Exploring the code

This section describes best practices the sample app code uses to implement the one-to-one communication features.

For detail about the APIs used to develop this sample, see the [OpenTok Android SDK Reference](https://tokbox.com/developer/sdks/android/reference/) and [Android API Reference](http://developer.android.com/reference/packages.html).


### Class design

This section focuses on one-to-one communication features. For more information, see the [OpenTok One-to-One Communication Sample App](https://github.com/opentok/one-to-one-sample-apps).

| Class        | Description  |
| ------------- | ------------- |
| `MainActivity`    | Implements the UI and media control callbacks. |
| `OpenTokConfig`   | Stores the information required to configure the session and authorize the app to make requests to the backend server.   |
| `PreviewControlFragment`   | Manages the toolbar for the local audio and video controls, and the start/end call button. |
| `RemoteControlFragment`   | Manages the icons to enable/disable the audio and video of the remote subscriber. |
| `PreviewCameraFragment `   | Manages the camera control. |


### Session and stream management

The `OTWrapper` class, included in the Accelerator Core for Android, is the backbone of the one-to-one communication features for the app.

This class uses the OpenTok API to initiate the client connection to the OpenTok session and manage the audio and video streams.
```java
  
  mWrapper.connect();
  
  mWrapper.startPublishingMedia(new PreviewConfig.PreviewConfigBuilder().
                        name("Tokboxer").build(), false);

  mWrapper.enableLocalMedia(MediaType.AUDIO, audio);
  
  mWrapper.disconnect();

```

The BasicListener and AdvancedListener interface monitor state changes in the communication, and defines the following methods:

```java
  //Basic Listener from OTWrapper
  private BasicListener mBasicListener =
    new PausableBasicListener(new BasicListener<OTWrapper>() {
    @Override
    public void onConnected(OTWrapper otWrapper, int participantsCount, String connId, String data) throws ListenerException { //...}
    @Override
    public void onDisconnected(OTWrapper otWrapper, int participantsCount, String connId, String data) throws ListenerException { //...}
    @Override
    public void onPreviewViewReady(OTWrapper otWrapper, View localView) throws ListenerException { //...}
    @Override
    public void onRemoteViewReady(OTWrapper otWrapper, View remoteView, String remoteId, String data) throws ListenerException { //...}
    @Override
    public void onStartedPublishingMedia(OTWrapper otWrapper, boolean screensharing) throws ListenerException { //...}
    //...
  });

```
```java
  //Advanced Listener from OTWrapper
  private AdvancedListener mAdvancedListener =
    new PausableAdvancedListener(new AdvancedListener<OTWrapper>() {
    @Override
    public void onCameraChanged(OTWrapper otWrapper) throws ListenerException { //... }
    @Override
    public void onReconnecting(OTWrapper otWrapper) throws ListenerException { //... }
    @Override
    public void onReconnected(OTWrapper otWrapper) throws ListenerException { //... }
    @Override
    public void onVideoQualityWarning(OTWrapper otWrapper, String remoteId) throws ListenerException { //... }
    //...
  });
```
### User interface

As described in [Class design](#class-design), the following classes set up and manage the UI fragments for the local and remote controls:

   - `PreviewControlFragment`
   - `RemoteControlFragment`
   - `PreviewCameraFragment`


These classes work with the following `MainActivity` methods, which manage the views as the publisher and subscriber participate in the session.

## Requirements

To develop your one-to-one communication app:

1. Install [Android Studio](http://developer.android.com/intl/es/sdk/index.html)
1. Review the [OpenTok Android SDK Requirements](https://tokbox.com/developer/sdks/android/#developerandclientrequirements)


================================================
FILE: iOS/.gitignore
================================================
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData
*.xcdatamodeld
.idea/
# Pods - for those of you who use CocoaPods
Pods

*.framework
*.bundle
Podfile.lock



================================================
FILE: iOS/OneToOneSample.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 46;
	objects = {

/* Begin PBXBuildFile section */
		70F017EE1E004A7A008EF97D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F017E01E004A7A008EF97D /* AppDelegate.m */; };
		70F017EF1E004A7A008EF97D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 70F017E11E004A7A008EF97D /* Assets.xcassets */; };
		70F017F01E004A7A008EF97D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70F017E21E004A7A008EF97D /* LaunchScreen.storyboard */; };
		70F017F11E004A7A008EF97D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70F017E41E004A7A008EF97D /* Main.storyboard */; };
		70F017F31E004A7A008EF97D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F017E71E004A7A008EF97D /* main.m */; };
		70F017F41E004A7A008EF97D /* MainView.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F017E91E004A7A008EF97D /* MainView.m */; };
		70F017F51E004A7A008EF97D /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F017EB1E004A7A008EF97D /* MainViewController.m */; };
		70F017F61E004A7A008EF97D /* UIView+Helper.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F017ED1E004A7A008EF97D /* UIView+Helper.m */; };
		A0A0E85D1E441C6C003F319C /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = A0A0E85C1E441C6C003F319C /* Podfile */; };
		A0A0E85F1E441C70003F319C /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = A0A0E85E1E441C70003F319C /* README.md */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
		70F017981E00458D008EF97D /* OneToOneSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OneToOneSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
		70F017DF1E004A7A008EF97D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
		70F017E01E004A7A008EF97D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
		70F017E11E004A7A008EF97D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		70F017E31E004A7A008EF97D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
		70F017E51E004A7A008EF97D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		70F017E61E004A7A008EF97D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		70F017E71E004A7A008EF97D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
		70F017E81E004A7A008EF97D /* MainView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainView.h; sourceTree = "<group>"; };
		70F017E91E004A7A008EF97D /* MainView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainView.m; sourceTree = "<group>"; };
		70F017EA1E004A7A008EF97D /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
		70F017EB1E004A7A008EF97D /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
		70F017EC1E004A7A008EF97D /* UIView+Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Helper.h"; sourceTree = "<group>"; };
		70F017ED1E004A7A008EF97D /* UIView+Helper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Helper.m"; sourceTree = "<group>"; };
		A0A0E85C1E441C6C003F319C /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; };
		A0A0E85E1E441C70003F319C /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		70F017951E00458D008EF97D /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		70F0178F1E00458D008EF97D = {
			isa = PBXGroup;
			children = (
				A0A0E85E1E441C70003F319C /* README.md */,
				A0A0E85C1E441C6C003F319C /* Podfile */,
				70F017DE1E004A7A008EF97D /* SampleApp */,
				70F017991E00458D008EF97D /* Products */,
			);
			sourceTree = "<group>";
		};
		70F017991E00458D008EF97D /* Products */ = {
			isa = PBXGroup;
			children = (
				70F017981E00458D008EF97D /* OneToOneSample.app */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		70F017DE1E004A7A008EF97D /* SampleApp */ = {
			isa = PBXGroup;
			children = (
				70F017DF1E004A7A008EF97D /* AppDelegate.h */,
				70F017E01E004A7A008EF97D /* AppDelegate.m */,
				70F017F71E004A88008EF97D /* Resources */,
				70F017E71E004A7A008EF97D /* main.m */,
				70F017E81E004A7A008EF97D /* MainView.h */,
				70F017E91E004A7A008EF97D /* MainView.m */,
				70F017EA1E004A7A008EF97D /* MainViewController.h */,
				70F017EB1E004A7A008EF97D /* MainViewController.m */,
				70F017EC1E004A7A008EF97D /* UIView+Helper.h */,
				70F017ED1E004A7A008EF97D /* UIView+Helper.m */,
			);
			path = SampleApp;
			sourceTree = "<group>";
		};
		70F017F71E004A88008EF97D /* Resources */ = {
			isa = PBXGroup;
			children = (
				70F017E11E004A7A008EF97D /* Assets.xcassets */,
				70F017E21E004A7A008EF97D /* LaunchScreen.storyboard */,
				70F017E41E004A7A008EF97D /* Main.storyboard */,
				70F017E61E004A7A008EF97D /* Info.plist */,
			);
			name = Resources;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		70F017971E00458D008EF97D /* OneToOneSample */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 70F017BA1E00458D008EF97D /* Build configuration list for PBXNativeTarget "OneToOneSample" */;
			buildPhases = (
				70F017941E00458D008EF97D /* Sources */,
				70F017951E00458D008EF97D /* Frameworks */,
				70F017961E00458D008EF97D /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = OneToOneSample;
			productName = OneToOneSample;
			productReference = 70F017981E00458D008EF97D /* OneToOneSample.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		70F017901E00458D008EF97D /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastUpgradeCheck = 0810;
				ORGANIZATIONNAME = "Tokbox, Inc.";
				TargetAttributes = {
					70F017971E00458D008EF97D = {
						CreatedOnToolsVersion = 8.1;
						ProvisioningStyle = Automatic;
					};
				};
			};
			buildConfigurationList = 70F017931E00458D008EF97D /* Build configuration list for PBXProject "OneToOneSample" */;
			compatibilityVersion = "Xcode 3.2";
			developmentRegion = English;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 70F0178F1E00458D008EF97D;
			productRefGroup = 70F017991E00458D008EF97D /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				70F017971E00458D008EF97D /* OneToOneSample */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		70F017961E00458D008EF97D /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				70F017F11E004A7A008EF97D /* Main.storyboard in Resources */,
				70F017F01E004A7A008EF97D /* LaunchScreen.storyboard in Resources */,
				A0A0E85D1E441C6C003F319C /* Podfile in Resources */,
				70F017EF1E004A7A008EF97D /* Assets.xcassets in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		70F017941E00458D008EF97D /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				A0A0E85F1E441C70003F319C /* README.md in Sources */,
				70F017EE1E004A7A008EF97D /* AppDelegate.m in Sources */,
				70F017F61E004A7A008EF97D /* UIView+Helper.m in Sources */,
				70F017F51E004A7A008EF97D /* MainViewController.m in Sources */,
				70F017F41E004A7A008EF97D /* MainView.m in Sources */,
				70F017F31E004A7A008EF97D /* main.m in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXVariantGroup section */
		70F017E21E004A7A008EF97D /* LaunchScreen.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				70F017E31E004A7A008EF97D /* Base */,
			);
			name = LaunchScreen.storyboard;
			sourceTree = "<group>";
		};
		70F017E41E004A7A008EF97D /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				70F017E51E004A7A008EF97D /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		70F017B81E00458D008EF97D /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_SUSPICIOUS_MOVES = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 10.1;
				MTL_ENABLE_DEBUG_INFO = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
			};
			name = Debug;
		};
		70F017B91E00458D008EF97D /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_SUSPICIOUS_MOVES = YES;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu99;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 10.1;
				MTL_ENABLE_DEBUG_INFO = NO;
				SDKROOT = iphoneos;
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		70F017BB1E00458D008EF97D /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				DEVELOPMENT_TEAM = "";
				INFOPLIST_FILE = SampleApp/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.tokbox.OneToOneSample;
				PRODUCT_NAME = "$(TARGET_NAME)";
			};
			name = Debug;
		};
		70F017BC1E00458D008EF97D /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				DEVELOPMENT_TEAM = "";
				INFOPLIST_FILE = SampleApp/Info.plist;
				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				PRODUCT_BUNDLE_IDENTIFIER = com.tokbox.OneToOneSample;
				PRODUCT_NAME = "$(TARGET_NAME)";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		70F017931E00458D008EF97D /* Build configuration list for PBXProject "OneToOneSample" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				70F017B81E00458D008EF97D /* Debug */,
				70F017B91E00458D008EF97D /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		70F017BA1E00458D008EF97D /* Build configuration list for PBXNativeTarget "OneToOneSample" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				70F017BB1E00458D008EF97D /* Debug */,
				70F017BC1E00458D008EF97D /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 70F017901E00458D008EF97D /* Project object */;
}


================================================
FILE: iOS/OneToOneSample.xcodeproj/xcshareddata/xcschemes/OneToOneSample.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0800"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "70F017971E00458D008EF97D"
               BuildableName = "OneToOneSample.app"
               BlueprintName = "OneToOneSample"
               ReferencedContainer = "container:OneToOneSample.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "A034743C1CCD15A800198DB4"
               BuildableName = "OneToOneSampleTests.xctest"
               BlueprintName = "OneToOneSampleTests"
               ReferencedContainer = "container:OneToOneSample.xcodeproj">
            </BuildableReference>
         </TestableReference>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "70F017B01E00458D008EF97D"
               BuildableName = "OneToOneSampleUITests.xctest"
               BlueprintName = "OneToOneSampleUITests"
               ReferencedContainer = "container:OneToOneSample.xcodeproj">
            </BuildableReference>
         </TestableReference>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "70F017971E00458D008EF97D"
            BuildableName = "OneToOneSample.app"
            BlueprintName = "OneToOneSample"
            ReferencedContainer = "container:OneToOneSample.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "70F017971E00458D008EF97D"
            BuildableName = "OneToOneSample.app"
            BlueprintName = "OneToOneSample"
            ReferencedContainer = "container:OneToOneSample.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "70F017971E00458D008EF97D"
            BuildableName = "OneToOneSample.app"
            BlueprintName = "OneToOneSample"
            ReferencedContainer = "container:OneToOneSample.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: iOS/Podfile
================================================

platform :ios, '9.0'

target 'OneToOneSample' do 
  pod 'OTAcceleratorCore', '1.0.3'
  pod 'SVProgressHUD'
end


================================================
FILE: iOS/README.md
================================================
![logo](../tokbox-logo.png)

# OpenTok One-to-One Communication Sample App for iOS<br/>Version 1.3

## Quick start

This section shows you how to prepare, build, and run the sample application. The app is built by the [Accelerator Core iOS](https://github.com/opentok/accelerator-core-ios).

### Install the project files

Use CocoaPods to install the project files and dependencies.

1. Install CocoaPods as described in [CocoaPods Getting Started](https://guides.cocoapods.org/using/getting-started.html#getting-started).
1. In Terminal, `cd` to your project directory and type `pod install`.
1. Reopen your project in Xcode using the new `*.xcworkspace` file.

### Configure and build the app

Configure the sample app code. Then, build and run the app.

1. Get values for **API Key**, **Session ID**, and **Token**. See [OpenTok One-to-One Communication Sample App home page](../README.md) for important information.

1. Replace the following empty strings with the corresponding **API Key**, **Session ID**, and **Token** values:

    ```objc
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

        // Override point for customization after application launch.    
        [OTAcceleratorSession setOpenTokApiKey:@""
                                     sessionId:@""
                                         token:@""];
        return YES;
    }
    ```

1. Use Xcode to build and run the app on an iOS simulator or device.

## Exploring the code

For detail about the APIs used to develop this sample, see the [OpenTok iOS SDK Reference](https://tokbox.com/developer/sdks/ios/reference/).

_**NOTE:** This sample app collects anonymous usage data for internal TokBox purposes only. Please do not modify or remove any logging code from this sample application._

### Session and stream management

The `OTOneToOneCommunicator` class is the backbone of the one-to-one communication features for the app. This class conforms to the protocols that initiate the client connection to the OpenTok session and sets up the listeners for the publisher and subscriber streams:

```objc
[self.oneToOneCommunicator connectWithHandler:^(OTOneToOneCommunicationSignal signal, NSError *error) {
    if (!error) {
        if (signal == OTSessionDidConnect) {
            // publisher view is available, now you can add subscriber view to your desired view
        }
        else if (signal == OTSubscriberDidConnect) {
            // subscriber view is available, now you can add subscriber view to your desired view
        }
    }
    else {
        
    }
}];
```

The following enum notifies the main controller of all session, publisher, and subscriber events:

```objc
typedef NS_ENUM(NSUInteger, OTOneToOneCommunicationSignal) {
    OTSessionDidConnect = 0,
    OTSessionDidDisconnect,
    OTSessionDidFail,
    OTSessionStreamCreated,
    OTSessionStreamDestroyed,
    OTSessionDidBeginReconnecting,
    OTSessionDidReconnect,
    OTPublisherDidFail,
    OTPublisherStreamCreated,
    OTPublisherStreamDestroyed,
    OTSubscriberDidConnect,
    OTSubscriberDidFail,
    OTSubscriberVideoDisabledByPublisher,
    OTSubscriberVideoDisabledBySubscriber,
    OTSubscriberVideoDisabledByBadQuality,
    OTSubscriberVideoEnabledByPublisher,
    OTSubscriberVideoEnabledBySubscriber,
    OTSubscriberVideoEnabledByGoodQuality,
    OTSubscriberVideoDisableWarning,
    OTSubscriberVideoDisableWarningLifted,
};
```
## Requirements

To develop your one-to-one communication app:

1. Install Xcode version 5 or later.
2. Review the [OpenTok iOS SDK Requirements](https://tokbox.com/developer/sdks/ios/).


================================================
FILE: iOS/SampleApp/AppDelegate.h
================================================
//
//  AppDelegate.h
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import <UIKit/UIKit.h>

@class OTAcceleratorSession;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong, readonly) OTAcceleratorSession* acceleratorSession;

@end


================================================
FILE: iOS/SampleApp/AppDelegate.m
================================================
//
//  AppDelegate.m
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import "AppDelegate.h"
#import "OTAcceleratorSession.h"

@interface AppDelegate ()
@property (nonatomic, strong) OTAcceleratorSession* acceleratorSession;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.acceleratorSession = [[OTAcceleratorSession alloc] initWithOpenTokApiKey:@"<# Replace #>"
                                                                        sessionId:@"<# Replace #>"
                                                                            token:@"<# Replace #>"];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
  // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
  // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
  // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
  // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
  // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
  // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
  // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  // Saves changes in the application's managed object context before the application terminates.
}

@end


================================================
FILE: iOS/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "3x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-40@2x-1.png",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon-40@3x-1.png",
      "scale" : "3x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-40@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-40@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@3x.png",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "Icon-Small.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "Icon-40@2x-2.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "Icon-40.png",
      "scale" : "1x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "Icon-40@2x-3.png",
      "scale" : "2x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "Icon-76.png",
      "scale" : "1x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "Icon-76@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "83.5x83.5",
      "idiom" : "ipad",
      "filename" : "Icon-83.5@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "24x24",
      "idiom" : "watch",
      "scale" : "2x",
      "role" : "notificationCenter",
      "subtype" : "38mm"
    },
    {
      "size" : "27.5x27.5",
      "idiom" : "watch",
      "scale" : "2x",
      "role" : "notificationCenter",
      "subtype" : "42mm"
    },
    {
      "size" : "29x29",
      "idiom" : "watch",
      "filename" : "Icon-Small@2x.png",
      "role" : "companionSettings",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "watch",
      "filename" : "Icon-Small@3x.png",
      "role" : "companionSettings",
      "scale" : "3x"
    },
    {
      "size" : "40x40",
      "idiom" : "watch",
      "scale" : "2x",
      "role" : "appLauncher",
      "subtype" : "38mm"
    },
    {
      "size" : "86x86",
      "idiom" : "watch",
      "scale" : "2x",
      "role" : "quickLook",
      "subtype" : "38mm"
    },
    {
      "size" : "98x98",
      "idiom" : "watch",
      "scale" : "2x",
      "role" : "quickLook",
      "subtype" : "42mm"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/audio.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "audio.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "audio@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "audio@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/hangUp.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "hangUp.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "hangUp@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "hangUp@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/mic.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "mic.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "mic@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "mic@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/mutedMic.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "mutedMicLineCopy.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "mutedMicLineCopy@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "mutedMicLineCopy@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/noAudio.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "noSoundCopy.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "noSoundCopy@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "noSoundCopy@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/noVideo.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "noVideoIcon.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "noVideoIcon@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "noVideoIcon@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/reverse cameras.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "reverse cameras.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "reverse cameras@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "reverse cameras@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/startCall.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "startCall.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "startCall@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "startCall@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Assets.xcassets/video.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "filename" : "videoIcon.png",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "filename" : "videoIcon@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "filename" : "videoIcon@3x.png",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: iOS/SampleApp/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="nPX-gN-iCp"/>
                        <viewControllerLayoutGuide type="bottom" id="s0L-bH-Ejt"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="OneToOneSample" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8h-0e-daP">
                                <rect key="frame" x="67.5" y="315.5" width="240" height="36"/>
                                <fontDescription key="fontDescription" type="system" pointSize="30"/>
                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="e8h-0e-daP" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="Xte-x5-DI8"/>
                            <constraint firstItem="e8h-0e-daP" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="aXa-6M-aml"/>
                        </constraints>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>


================================================
FILE: iOS/SampleApp/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Main View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController autoresizesArchivedViewToFullSize="NO" id="BYZ-38-t0r" customClass="MainViewController" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="ibB-sB-NO2"/>
                        <viewControllerLayoutGuide type="bottom" id="g1w-3N-XuV"/>
                    </layoutGuides>
                    <view key="view" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="HtV-zK-mFJ" customClass="MainView">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zJt-pm-lIX">
                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                            </view>
                            <view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="EoV-Kh-ae4">
                                <rect key="frame" x="265" y="471" width="90" height="90"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="90" id="2ZZ-pD-0bi"/>
                                    <constraint firstAttribute="width" secondItem="EoV-Kh-ae4" secondAttribute="height" multiplier="1:1" id="HVT-by-pPc"/>
                                </constraints>
                            </view>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QaT-qb-Mgd">
                                <rect key="frame" x="84.5" y="581" width="206" height="66"/>
                                <subviews>
                                    <button opaque="NO" alpha="0.5" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lI4-Iv-Bhv" userLabel="publisherVideoButton">
                                        <rect key="frame" x="8" y="8" width="50" height="50"/>
                                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <constraints>
                                            <constraint firstAttribute="width" constant="50" id="WHA-xY-mGi"/>
                                            <constraint firstAttribute="width" secondItem="lI4-Iv-Bhv" secondAttribute="height" multiplier="1:1" id="atV-3z-CfA"/>
                                        </constraints>
                                        <state key="normal" image="video"/>
                                        <connections>
                                            <action selector="publisherVideoButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="2mt-7G-8tP"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8fW-9l-wlb" userLabel="publisherCallButton">
                                        <rect key="frame" x="78" y="8" width="50" height="50"/>
                                        <color key="backgroundColor" red="0.41568627450000001" green="0.67843137249999996" blue="0.74901960779999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <constraints>
                                            <constraint firstAttribute="width" constant="50" id="7Lw-oa-woS"/>
                                            <constraint firstAttribute="width" secondItem="8fW-9l-wlb" secondAttribute="height" multiplier="1:1" id="DuI-oP-9Bu"/>
                                        </constraints>
                                        <state key="normal" image="startCall"/>
                                        <connections>
                                            <action selector="publisherCallButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="SO2-eY-tdE"/>
                                        </connections>
                                    </button>
                                    <button opaque="NO" alpha="0.5" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Bwb-uu-g2a" userLabel="publisherMicButton">
                                        <rect key="frame" x="148" y="8" width="50" height="50"/>
                                        <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <constraints>
                                            <constraint firstAttribute="width" constant="50" id="ip2-ay-ESy"/>
                                            <constraint firstAttribute="width" secondItem="Bwb-uu-g2a" secondAttribute="height" multiplier="1:1" id="vkb-t2-Kh2"/>
                                        </constraints>
                                        <state key="normal" image="mic"/>
                                        <connections>
                                            <action selector="publisherAudioButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="pxR-Us-IdT"/>
                                        </connections>
                                    </button>
                                </subviews>
                                <constraints>
                                    <constraint firstItem="8fW-9l-wlb" firstAttribute="centerX" secondItem="QaT-qb-Mgd" secondAttribute="centerX" id="5Lu-9t-BnR"/>
                                    <constraint firstItem="lI4-Iv-Bhv" firstAttribute="top" secondItem="QaT-qb-Mgd" secondAttribute="top" constant="8" id="CvT-GV-vFr"/>
                                    <constraint firstAttribute="trailing" secondItem="Bwb-uu-g2a" secondAttribute="trailing" constant="8" id="JF3-ro-Bkg"/>
                                    <constraint firstItem="lI4-Iv-Bhv" firstAttribute="leading" secondItem="QaT-qb-Mgd" secondAttribute="leading" constant="8" id="JGU-Xi-nK9"/>
                                    <constraint firstItem="Bwb-uu-g2a" firstAttribute="top" secondItem="QaT-qb-Mgd" secondAttribute="top" constant="8" id="NKW-13-1oS"/>
                                    <constraint firstItem="8fW-9l-wlb" firstAttribute="centerY" secondItem="QaT-qb-Mgd" secondAttribute="centerY" id="PHM-ze-gCT"/>
                                    <constraint firstAttribute="bottom" secondItem="lI4-Iv-Bhv" secondAttribute="bottom" constant="8" id="RQX-rI-B3e"/>
                                    <constraint firstItem="Bwb-uu-g2a" firstAttribute="leading" secondItem="8fW-9l-wlb" secondAttribute="trailing" constant="20" id="V8L-hw-qhh"/>
                                    <constraint firstItem="8fW-9l-wlb" firstAttribute="leading" secondItem="lI4-Iv-Bhv" secondAttribute="trailing" constant="20" id="fmd-Pm-bEV"/>
                                    <constraint firstAttribute="bottom" secondItem="Bwb-uu-g2a" secondAttribute="bottom" constant="8" id="m7x-ZQ-Ppg"/>
                                </constraints>
                            </view>
                            <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SKX-dv-Vnc" userLabel="subscriberAudioButton">
                                <rect key="frame" x="20" y="60" width="25" height="25"/>
                                <constraints>
                                    <constraint firstAttribute="width" secondItem="SKX-dv-Vnc" secondAttribute="height" multiplier="1:1" id="qV6-yn-B90"/>
                                </constraints>
                                <state key="normal" image="audio"/>
                                <connections>
                                    <action selector="subscriberAudioButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="COG-Jp-EKl"/>
                                </connections>
                            </button>
                            <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TaE-Jx-zZR" userLabel="subscriberVideoButton">
                                <rect key="frame" x="20" y="105" width="24" height="24"/>
                                <constraints>
                                    <constraint firstAttribute="width" secondItem="TaE-Jx-zZR" secondAttribute="height" multiplier="1:1" id="5UO-AX-cjB"/>
                                </constraints>
                                <state key="normal" image="video"/>
                                <connections>
                                    <action selector="subscriberVideoButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="XWM-IL-u0J"/>
                                </connections>
                            </button>
                            <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xR7-mn-zpN" userLabel="publisherCameraButton">
                                <rect key="frame" x="325" y="60" width="30" height="21"/>
                                <constraints>
                                    <constraint firstAttribute="width" secondItem="xR7-mn-zpN" secondAttribute="height" multiplier="55:39" id="E2O-Tz-PqK"/>
                                    <constraint firstAttribute="width" constant="30" id="Xky-0a-JDU"/>
                                </constraints>
                                <state key="normal" image="reverse cameras"/>
                                <connections>
                                    <action selector="publisherCameraButtonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="rUd-XL-ngb"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="EoV-Kh-ae4" secondAttribute="trailing" constant="20" id="9Fu-eZ-Rs1"/>
                            <constraint firstItem="TaE-Jx-zZR" firstAttribute="leading" secondItem="HtV-zK-mFJ" secondAttribute="leading" constant="20" id="C2K-eN-JaA"/>
                            <constraint firstAttribute="trailing" secondItem="zJt-pm-lIX" secondAttribute="trailing" id="Hyy-01-kNd"/>
                            <constraint firstItem="SKX-dv-Vnc" firstAttribute="top" secondItem="HtV-zK-mFJ" secondAttribute="top" constant="60" id="O4w-5G-XL8"/>
                            <constraint firstItem="QaT-qb-Mgd" firstAttribute="centerX" secondItem="HtV-zK-mFJ" secondAttribute="centerX" id="Pf6-T6-PHm"/>
                            <constraint firstItem="QaT-qb-Mgd" firstAttribute="top" secondItem="EoV-Kh-ae4" secondAttribute="bottom" constant="20" id="RxN-kP-cKg"/>
                            <constraint firstItem="g1w-3N-XuV" firstAttribute="top" secondItem="QaT-qb-Mgd" secondAttribute="bottom" constant="20" id="U8e-tl-f28"/>
                            <constraint firstItem="zJt-pm-lIX" firstAttribute="top" secondItem="HtV-zK-mFJ" secondAttribute="top" id="VE2-60-yEH"/>
                            <constraint firstItem="TaE-Jx-zZR" firstAttribute="top" secondItem="SKX-dv-Vnc" secondAttribute="bottom" constant="20" id="VsL-68-FSY"/>
                            <constraint firstAttribute="bottom" secondItem="zJt-pm-lIX" secondAttribute="bottom" id="aa2-ub-2be"/>
                            <constraint firstItem="zJt-pm-lIX" firstAttribute="leading" secondItem="HtV-zK-mFJ" secondAttribute="leading" id="bWH-Z0-RpJ"/>
                            <constraint firstItem="SKX-dv-Vnc" firstAttribute="leading" secondItem="HtV-zK-mFJ" secondAttribute="leading" constant="20" id="p9N-b2-8WU"/>
                            <constraint firstItem="xR7-mn-zpN" firstAttribute="top" secondItem="HtV-zK-mFJ" secondAttribute="top" constant="60" id="sIb-ZZ-Zsj"/>
                            <constraint firstAttribute="trailing" secondItem="xR7-mn-zpN" secondAttribute="trailing" constant="20" id="wyq-rV-OBQ"/>
                        </constraints>
                        <connections>
                            <outlet property="callButton" destination="8fW-9l-wlb" id="uSS-1W-0Ln"/>
                            <outlet property="publisherAudioButton" destination="Bwb-uu-g2a" id="FaO-jl-Nwv"/>
                            <outlet property="publisherVideoButton" destination="lI4-Iv-Bhv" id="GAY-eu-ff1"/>
                            <outlet property="publisherView" destination="EoV-Kh-ae4" id="WWF-wf-5KH"/>
                            <outlet property="reverseCameraButton" destination="xR7-mn-zpN" id="sd4-AJ-Rur"/>
                            <outlet property="subscriberAudioButton" destination="SKX-dv-Vnc" id="oVI-Jt-h1h"/>
                            <outlet property="subscriberVideoButton" destination="TaE-Jx-zZR" id="hHd-ZY-atr"/>
                            <outlet property="subscriberView" destination="zJt-pm-lIX" id="mYB-hs-kpy"/>
                        </connections>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="565" y="357.99999999999989"/>
        </scene>
    </scenes>
    <resources>
        <image name="audio" width="24" height="25"/>
        <image name="mic" width="21" height="26"/>
        <image name="reverse cameras" width="55" height="39"/>
        <image name="startCall" width="15" height="30"/>
        <image name="video" width="24" height="14"/>
    </resources>
</document>


================================================
FILE: iOS/SampleApp/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NSCameraUsageDescription</key>
	<string>$(PRODUCT_NAME) uses camera</string>
	<key>NSMicrophoneUsageDescription</key>
	<string>$(PRODUCT_NAME) uses microphone</string>
	<key>UIBackgroundModes</key>
	<array>
		<string>audio</string>
	</array>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UIStatusBarHidden</key>
	<true/>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
</dict>
</plist>


================================================
FILE: iOS/SampleApp/MainView.h
================================================
//
//  MainView.h
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface MainView : UIView

// publisher view
- (void)addPublisherView:(UIView *)publisherView;
- (void)removePublisherView;

- (void)connectCallHolder:(BOOL)connected;
- (void)updatePublisherAudio:(BOOL)connected;
- (void)updatePublisherVideo:(BOOL)connected;

// subscriber view
- (void)addSubscribeView:(UIView *)subscriberView;
- (void)removeSubscriberView;

- (void)updateSubscriberAudioButton:(BOOL)connected;
- (void)updateSubscriberVideoButton:(BOOL)connected;
- (void)showSubscriberControls:(BOOL)shown;

// other controls
- (void)enableControlButtonsForCall:(BOOL)enabled;
- (void)showReverseCameraButton;

- (void)resetAllControl;
@end


================================================
FILE: iOS/SampleApp/MainView.m
================================================
//
//  MainView.m
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import "MainView.h"
#import "UIView+Helper.h"

@interface MainView()
@property (weak, nonatomic) IBOutlet UIView *publisherView;
@property (weak, nonatomic) IBOutlet UIView *subscriberView;

// 3 action buttons at the bottom of the view
@property (weak, nonatomic) IBOutlet UIButton *publisherVideoButton;
@property (weak, nonatomic) IBOutlet UIButton *callButton;
@property (weak, nonatomic) IBOutlet UIButton *publisherAudioButton;

@property (weak, nonatomic) IBOutlet UIButton *reverseCameraButton;

@property (weak, nonatomic) IBOutlet UIButton *subscriberVideoButton;
@property (weak, nonatomic) IBOutlet UIButton *subscriberAudioButton;

@end

@implementation MainView

- (void)awakeFromNib {
    [super awakeFromNib];
    
    self.publisherView.hidden = YES;
    self.publisherView.alpha = 1;
    self.publisherView.layer.borderWidth = 1;
    self.publisherView.layer.borderColor = [UIColor whiteColor].CGColor;
    self.publisherView.layer.backgroundColor = [UIColor grayColor].CGColor;
    self.publisherView.layer.cornerRadius = 3;
    
    [self drawBorderOn:self.publisherAudioButton withWhiteBorder:YES];
    [self drawBorderOn:self.callButton withWhiteBorder:NO];
    [self drawBorderOn:self.publisherVideoButton withWhiteBorder:YES];
    [self showSubscriberControls:NO];
}

- (void)drawBorderOn:(UIView *)view
     withWhiteBorder:(BOOL)withWhiteBorder {
    
    view.layer.cornerRadius = (view.bounds.size.width / 2);
    if (withWhiteBorder) {
        view.layer.borderWidth = 1;
        view.layer.borderColor = [UIColor whiteColor].CGColor;
    }
}

#pragma mark - publisher view
- (void)addPublisherView:(UIView *)publisherView {
    
    [self.publisherView setHidden:NO];
    [self.publisherView addSubview:publisherView];
    publisherView.translatesAutoresizingMaskIntoConstraints = NO;
    [publisherView addAttachedLayoutConstantsToSuperview];
}

- (void)removePublisherView {
    [self.publisherView setHidden:YES];
    [self.publisherView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
}

- (void)connectCallHolder:(BOOL)connected {
    [self.callButton setImage:connected ? [UIImage imageNamed:@"hangUp"] : [UIImage imageNamed:@"startCall"]  forState:UIControlStateNormal];
    self.callButton.layer.backgroundColor = connected ? [UIColor colorWithRed:(205/255.0) green:(32/255.0) blue:(40/255.0) alpha:1.0].CGColor : [UIColor colorWithRed:(106/255.0) green:(173/255.0) blue:(191/255.0) alpha:1.0].CGColor;
}
- (void)updatePublisherAudio:(BOOL)connected {
    [self.publisherAudioButton setImage:connected ? [UIImage imageNamed:@"mic"] : [UIImage imageNamed:@"mutedMic"] forState:UIControlStateNormal];
}

- (void)updatePublisherVideo:(BOOL)connected {
    [self.publisherVideoButton setImage:connected ? [UIImage imageNamed:@"video"] : [UIImage imageNamed:@"noVideo"] forState:UIControlStateNormal];
}

#pragma mark - subscriber view
- (void)addSubscribeView:(UIView *)subscriberView {
    [self.subscriberView addSubview:subscriberView];
    subscriberView.translatesAutoresizingMaskIntoConstraints = NO;
    [subscriberView addAttachedLayoutConstantsToSuperview];
}

- (void)removeSubscriberView {
    [self.subscriberView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
}

- (void)updateSubscriberAudioButton:(BOOL)connected {
    [self.subscriberAudioButton setImage:connected ? [UIImage imageNamed:@"audio"] : [UIImage imageNamed:@"noAudio"] forState:UIControlStateNormal];
}

- (void)updateSubscriberVideoButton:(BOOL)connected {
    [self.subscriberVideoButton setImage:connected ? [UIImage imageNamed:@"video"] : [UIImage imageNamed:@"noVideo"] forState:UIControlStateNormal];
}

- (void)showSubscriberControls:(BOOL)shown {
    [self.subscriberAudioButton setHidden:!shown];
    [self.subscriberVideoButton setHidden:!shown];
}

#pragma mark - other controls
- (void)enableControlButtonsForCall:(BOOL)enabled {
    [self.subscriberAudioButton setEnabled:enabled];
    [self.subscriberVideoButton setEnabled:enabled];
    [self.publisherVideoButton setEnabled:enabled];
    [self.publisherAudioButton setEnabled:enabled];
}

- (void)showReverseCameraButton; {
    self.reverseCameraButton.hidden = NO;
}

- (void)resetAllControl {
    [self removePublisherView];
    [self connectCallHolder:NO];
    [self updatePublisherAudio:YES];
    [self updatePublisherVideo:YES];
    [self updateSubscriberAudioButton:YES];
    [self updateSubscriberVideoButton:YES];
    [self enableControlButtonsForCall:NO];
}

@end


================================================
FILE: iOS/SampleApp/MainViewController.h
================================================
//
//  MainViewController.h
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface MainViewController : UIViewController

@end


================================================
FILE: iOS/SampleApp/MainViewController.m
================================================
//
//  MainViewController.m
//
// Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import "MainView.h"
#import "MainViewController.h"
#import "OTOneToOneCommunicator.h"
#import "AppDelegate.h"

#import <SVProgressHUD/SVProgressHUD.h>

#define MAKE_WEAK(self) __weak typeof(self) weak##self = self
#define MAKE_STRONG(self) __strong typeof(weak##self) strong##self = weak##self

@interface MainViewController () <OTOneToOneCommunicatorDataSource>
@property (nonatomic) MainView *mainView;
@property (nonatomic) OTOneToOneCommunicator *oneToOneCommunicator;
@end

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.mainView = (MainView *)self.view;
    
    self.oneToOneCommunicator = [[OTOneToOneCommunicator alloc] init];
    self.oneToOneCommunicator.dataSource = self;
    
#if !(TARGET_OS_SIMULATOR)
    [self.mainView showReverseCameraButton];
#endif
}

- (IBAction)publisherCallButtonPressed:(UIButton *)sender {
    
    if (!self.oneToOneCommunicator.isCallEnabled) {
        [SVProgressHUD show];

        MAKE_WEAK(self);
        [self.oneToOneCommunicator connectWithHandler:^(OTCommunicationSignal signal, NSError *error) {
            MAKE_STRONG(self);
            strongself.oneToOneCommunicator.publisherView.showAudioVideoControl = NO;
            if (!error) {
                [strongself handleCommunicationSignal:signal];
            }
            else {
                [SVProgressHUD showErrorWithStatus:error.localizedDescription];
            }
        }];
    }
    else {
        [SVProgressHUD popActivity];
        [self.oneToOneCommunicator disconnect];
        [self.mainView resetAllControl];
    }
}

- (void)handleCommunicationSignal:(OTCommunicationSignal)signal {
    
    switch (signal) {
        case OTPublisherCreated: {
            [SVProgressHUD popActivity];
            [self.mainView connectCallHolder:self.oneToOneCommunicator.isCallEnabled];
            [self.mainView enableControlButtonsForCall:YES];
            [self.mainView addPublisherView:self.oneToOneCommunicator.publisherView];
            break;
        }
        case OTPublisherDestroyed: {
            [self.mainView removePublisherView];
            NSLog(@"Your publishing feed stops streaming in OpenTok");
            break;
        }
        case OTSubscriberCreated: {
            [SVProgressHUD show];
        }
        case OTSubscriberReady: {
            [SVProgressHUD popActivity];
            [self.mainView addSubscribeView:self.oneToOneCommunicator.subscriberView];
            break;
        }
        case OTSubscriberDestroyed:{
            [self.mainView removeSubscriberView];
            break;
        }
        case OTSessionDidBeginReconnecting: {
            [SVProgressHUD showInfoWithStatus:@"Reconnecting"];
            break;
        }
        case OTSessionDidReconnect: {
            [SVProgressHUD popActivity];
            break;
        }
        case OTSubscriberVideoDisabledByBadQuality:
        case OTSubscriberVideoDisabledBySubscriber: {
            NSLog(@"The remote has disabled the video");
            break;
        }
        case OTSubscriberVideoDisabledByPublisher:{
            self.oneToOneCommunicator.subscribeToVideo = NO;
            break;
        }
        case OTSubscriberVideoEnabledByGoodQuality:
        case OTSubscriberVideoEnabledBySubscriber:{
            NSLog(@"The remote has enabled the video");
            break;
        }
        case OTSubscriberVideoEnabledByPublisher:{
            self.oneToOneCommunicator.subscribeToVideo = YES;
            break;
        }
        case OTSubscriberVideoDisableWarning:{
            self.oneToOneCommunicator.subscribeToVideo = NO;
            [SVProgressHUD showErrorWithStatus:@"Network connection is unstable."];
            break;
        }
        case OTSubscriberVideoDisableWarningLifted:{
            self.oneToOneCommunicator.subscribeToVideo = YES;
            break;
        }
        default: break;
    }
}

- (IBAction)publisherAudioButtonPressed:(UIButton *)sender {
    self.oneToOneCommunicator.publishAudio = !self.oneToOneCommunicator.publishAudio;
    [self.mainView updatePublisherAudio:self.oneToOneCommunicator.publishAudio];
}

- (IBAction)publisherVideoButtonPressed:(UIButton *)sender {
    self.oneToOneCommunicator.publishVideo = !self.oneToOneCommunicator.publishVideo;
    [self.mainView updatePublisherVideo:self.oneToOneCommunicator.publishVideo];
}

- (IBAction)publisherCameraButtonPressed:(UIButton *)sender {
    self.oneToOneCommunicator.cameraPosition = self.oneToOneCommunicator.cameraPosition == AVCaptureDevicePositionBack ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack
}

- (IBAction)subscriberVideoButtonPressed:(UIButton *)sender {
    self.oneToOneCommunicator.subscribeToVideo = !self.oneToOneCommunicator.subscribeToVideo;
    [self.mainView updateSubscriberVideoButton:self.oneToOneCommunicator.subscribeToVideo];
}

- (IBAction)subscriberAudioButtonPressed:(UIButton *)sender {
    self.oneToOneCommunicator.subscribeToAudio = !self.oneToOneCommunicator.subscribeToAudio;
    [self.mainView updateSubscriberAudioButton:self.oneToOneCommunicator.subscribeToAudio];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    if (self.oneToOneCommunicator.subscriberView){
        [self.mainView showSubscriberControls:YES];
    }
    [self.mainView performSelector:@selector(showSubscriberControls:)
                        withObject:@(NO)
                        afterDelay:7.0];
}

- (OTAcceleratorSession *)sessionOfOTOneToOneCommunicator:(OTOneToOneCommunicator *)oneToOneCommunicator {
    AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    return appDelegate.acceleratorSession;
}

@end


================================================
FILE: iOS/SampleApp/UIView+Helper.h
================================================
//
//  UIView+Helper.h
//
//  Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UIView (Helper)

- (void)addAttachedLayoutConstantsToSuperview;

@end


================================================
FILE: iOS/SampleApp/UIView+Helper.m
================================================
//
//  UIView+Helper.m
//
//  Copyright © 2016 Tokbox, Inc. All rights reserved.
//

#import "UIView+Helper.h"

@implementation UIView (Helper)

- (void)addAttachedLayoutConstantsToSuperview {
    
    if (!self.superview) {
        return;
    }
    
    NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self
                                                           attribute:NSLayoutAttributeTop
                                                           relatedBy:NSLayoutRelationEqual
                                                              toItem:self.superview
                                                           attribute:NSLayoutAttributeTop
                                                          multiplier:1.0
                                                            constant:0.0];
    NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:self
                                                               attribute:NSLayoutAttributeLeading
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:self.superview
                                                               attribute:NSLayoutAttributeLeading
                                                              multiplier:1.0
                                                                constant:0.0];
    NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self
                                                                attribute:NSLayoutAttributeTrailing
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:self.superview
                                                                attribute:NSLayoutAttributeTrailing
                                                               multiplier:1.0
                                                                 constant:0.0];
    NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:self
                                                              attribute:NSLayoutAttributeBottom
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.superview
                                                              attribute:NSLayoutAttributeBottom
                                                             multiplier:1.0
                                                               constant:0.0];
    [NSLayoutConstraint activateConstraints:@[top, leading, trailing, bottom]];
}

@end


================================================
FILE: iOS/SampleApp/main.m
================================================
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}


================================================
FILE: js/.eslintrc.json
================================================
{
  "extends": "airbnb",
  "env": {
    "browser": true,
    "node": true
  },
  "parserOptions": {
    "ecmaVersion": 5
  },
  "plugins": [
    "react"
  ],
  "rules": {
    "no-underscore-dangle": 0,
    "vars-on-top": 0,
    "padded-blocks": 0,
    "no-var": 0,
    "comma-dangle": 0,
    "func-names": 0,
    "prefer-arrow-callback": 0,
    "object-shorthand": 0,
    "no-unused-expressions": [2, {
      "allowTernary": true,
      "allowShortCircuit": true
    }],
    "global-require": 0
  },
  "globals": {
    "$": true,
    "_": true
  }
}


================================================
FILE: js/.gitignore
================================================
node_modules

================================================
FILE: js/.jsbeautifyrc
================================================
{
    "js":{
        "indent_size": 2,
        "space_after_anon_function": true,
        "end_with_newline": true,
        "brace_style": "collaps-preserve-inline"
    }
}

================================================
FILE: js/Procfile
================================================
web: node server.js

================================================
FILE: js/README.md
================================================
![logo](../tokbox-logo.png)

# OpenTok One-to-One Communication Sample App for JavaScript<br/>Version 1.3

## Quick start

This section shows you how to prepare and run the sample application. The app is built by the [Accelerator Core JS](https://github.com/opentok/accelerator-core-js).

### Configuring the app

Configure the sample app code. Then, build and run the app.

1. Get values for **API Key**, **Session ID**, and **Token**. See [OpenTok One-to-One Communication Sample App home page](../README.md) for important information.

2. In **app.js**, replace the following empty strings with the corresponding **API Key**, **Session ID**, and **Token** values:

   ```javascript
    apiKey: '',    // Replace with your OpenTok API Key
    sessionId: '', // Replace with a generated Session ID
    token: '',     // Replace with a generated token (from the dashboard or using an OpenTok server SDK)
   ```

### Deploying and running the app

```javascript
$ npm install
$ npm run build
$ node server.js
```

The web page that loads the sample app for JavaScript must be served over HTTP/HTTPS. Browser security limitations prevent you from publishing video using a `file://` path, as discussed in the OpenTok.js [Release Notes](https://www.tokbox.com/developer/sdks/js/release-notes.html#knownIssues). To support clients running [Chrome 47 or later](https://groups.google.com/forum/#!topic/discuss-webrtc/sq5CVmY69sc), HTTPS is required. A [Node](https://nodejs.org/en/) server will work, as will [MAMP](https://www.mamp.info/) or [XAMPP](https://www.apachefriends.org/index.html).  You can also use a cloud service such as [Heroku](https://www.heroku.com/) to host the application.


## Exploring the code

For details about how to use the Accelerator Core in the sample app, see [here](https://github.com/opentok/accelerator-core-js#sample-applications).



================================================
FILE: js/package.json
================================================
{
  "name": "one-to-one-sample",
  "version": "1.0.4",
  "description": "One to One sample app",
  "main": "server.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/opentok/one-to-one-sample-apps"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cp ./node_modules/opentok-accelerator-core/browser/opentok-acc-core.js ./public/js/components/opentok-acc-core.js",
    "start": "node server.js"
  },
  "author": "adrice727@gmail.com",
  "license": "MIT",
  "dependencies": {
    "express": "^4.14.1",
    "body-parser": "^1.16.0",
    "opentok-accelerator-core": "*"
  }
}


================================================
FILE: js/public/css/style.css
================================================
html,
body {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: sans-serif;
}

.clickable {
  cursor: pointer;
}

*,
*:before,
*:after {
    box-sizing: inherit;
}

.App-header {
    background-color: #222;
    height: 40px;
    color: white;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 20px;
}

.App-header h1 {
    font-size: 16px;
    font-weight: 200;
}

.App-logo {
    height: 60%;
    width: auto;
}

.App-main {
    position: relative;
    width: 75vw;
    height: calc(75vw * .6);
    margin: 10px auto;
    border: 1px solid lightblue;
}

.App-control-container {
    position: absolute;
    height: 100%;
    width: 60px;
    left: -60px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.App-control-container.hidden {
    display: none;
}

.App-control-container .ots-video-control {
    width: 50px;
    height: 50px;
    margin: 20px 0 !important;
    border: 2px solid white;
    border-radius: 50%;
    background-position: center;
    background-color: rgba(27, 134, 144, 0.4);
    background-color: lightgrey;
    background-repeat: no-repeat;
    cursor: pointer;
}

.App-control-container .ots-video-control.audio {
    background-image: url(https://assets.tokbox.com/solutions/images/icon-mic.png);
}

.App-control-container .ots-video-control.audio:hover, .App-control-container .ots-video-control.audio.muted {
    background-image: url(https://assets.tokbox.com/solutions/images/icon-muted-mic.png);
}

.App-control-container .ots-video-control.video {
    background-image: url(https://assets.tokbox.com/solutions/images/icon-video.png);
}

.App-control-container .ots-video-control.video.muted {
    background-image: url(https://assets.tokbox.com/solutions/images/icon-no-video.png);
}

.App-control-container .ots-video-control.end-call {
    background-image: url(https://assets.tokbox.com/solutions/images/icon-hang-up.png);
    background-color: red;
}
   
.App-video-container {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}

.App-mask {
    width: 100%;
    height: 100%;
    position: relative;
    color: white;
    background: rgba(27, 134, 144, 0.4);
    display: flex;
    justify-content: center;
    align-items: center;
}

.App-mask.hidden {
    display: none;
}

.App-mask .react-spinner {
    position: absolute;
}

.App-mask .message {
    font-weight: 200;
}

.App-mask .message.with-spinner {
    position: absolute;
    top: 57.5%;
}

.App-mask .message.button {
    border: 1px solid white;
    padding: 20px 40px;
    border-radius: 6px;
}

.App-video-container .video-container {
    width: 100%;
    height: 100%;
    display: flex;
}

.App-video-container .video-container.small {
    position: absolute;
    top: 20px;
    right: 20px;
    width: 160px;
    height: 96px;
    border: 1px solid #fcba00;
    z-index: 2;
}

.App-video-container .video-container.small.left {
    left: 20px;
    border: 1px solid #00fcc2;
}

.App-video-container .video-container.hidden {
    display: none;
}

.App-video-container .video-container.active-2 .OT_subscriber {
    width: 50%;
}

.App-video-container .video-container.active-3 .OT_subscriber {
    width: calc(100%/3) !important;
}

.App-video-container .video-container.active-4 {
    flex-wrap: wrap;
}

.App-video-container .video-container.active-4 .OT_subscriber {
    width: 50% !important;
    height: 50% !important;
}

progress-spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 1px solid transparent;
  border-top-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  -webkit-animation: rotate 800ms linear infinite;
          animation: rotate 800ms linear infinite;
}
progress-spinner[dark] {
  border-top-color: rgba(255, 255, 255, 0.6);
}
progress-spinner[dotted] {
  border-width: 0;
  border-style: dotted;
  border-top-width: 2px;
}
@-webkit-keyframes rotate {
  0% {
    -webkit-transform: rotate(0deg);
            transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
            transform: rotate(360deg);
  }
}
@keyframes rotate {
  0% {
    -webkit-transform: rotate(0deg);
            transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
            transform: rotate(360deg);
  }
}

================================================
FILE: js/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>OT Accelerator Core</title>

    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="https://assets.tokbox.com/solutions/css/style.css">
    <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
    <script src="js/components/opentok-acc-core.js"></script>
    <script src="js/app.js"></script>
</head>

<body>
    <div class="App">
        <div class="App-header">
            <img src="./images/logo.svg" class="App-logo" alt="logo" />
            <h1>OpenTok Accelerator Core</h1>
        </div>
        <div class="App-main">
            <div id="controls" class='App-control-container hidden'>
                <div class="ots-video-control circle audio" id="toggleLocalAudio"></div>
                <div class="ots-video-control circle video" id="toggleLocalVideo"></div>
                <div class="ots-video-control circle end-call" id="toggleEndCall"></div>
            </div>
            <div class="App-video-container" id="appVideoContainer">
                <div class="App-mask" id="connecting-mask">
                    <progress-spinner dark style="font-size:50px"></progress-spinner>
                    <div class="message with-spinner">Connecting</div>
                </div>
                <div class="App-mask hidden" id="start-mask">
                    <div class="message button clickable" id="start">Click to Start Call</div>
                </div>
                <div id="cameraPublisherContainer" class="video-container hidden"></div>
                <div id="screenPublisherContainer" class="video-container hidden"></div>
                <div id="cameraSubscriberContainer" class="video-container-hidden"></div>
            </div>
        </div>
    </div>

</body>

</html>

================================================
FILE: js/public/js/app.js
================================================
/* global otCore */
const options = {
  credentials: {
    apiKey: "",  //Replace with your OpenTok API key 
    sessionId: "", //Replace with a generated Session ID
    token: "", //Replace with a generated token (from the dashboard or using an OpenTok server SDK)
  },
   // A container can either be a query selector or an HTMLElement
  streamContainers: function streamContainers(pubSub, type, data) {
    return {
      publisher: {
        camera: '#cameraPublisherContainer',
      },
      subscriber: {
        camera: '#cameraSubscriberContainer',
      },
    }[pubSub][type];
  },
  controlsContainer: '#controls',
  packages: [],
  communication: {
    callProperites: null, // Using default
  }
};

/** Application Logic */
const app = () => {
  const state = {
    connected: false,
    active: false,
    publishers: null,
    subscribers: null,
    meta: null,
    localAudioEnabled: true,
    localVideoEnabled: true,
  };

  /**
   * Update the size and position of video containers based on the number of
   * publishers and subscribers specified in the meta property returned by otCore.
   */
  const updateVideoContainers = () => {
    const { meta } = state;
    const activeCameraSubscribers = meta ? meta.subscriber.camera : 0;
   
    const videoContainerClass = `App-video-container ${''}`;
    document.getElementById('appVideoContainer').setAttribute('class', videoContainerClass);

    const cameraPublisherClass =
      `video-container ${!!activeCameraSubscribers? 'small' : ''} ${!!activeCameraSubscribers? 'small' : ''}`;
    document.getElementById('cameraPublisherContainer').setAttribute('class', cameraPublisherClass);

    const cameraSubscriberClass =
      `video-container ${!activeCameraSubscribers ? 'hidden' : ''} active-${activeCameraSubscribers}`;
    document.getElementById('cameraSubscriberContainer').setAttribute('class', cameraSubscriberClass);
  };


  /**
   * Update the UI
   * @param {String} update - 'connected', 'active', or 'meta'
   */
  const updateUI = (update) => {
    const { connected, active } = state;

    switch (update) {
      case 'connected':
        if (connected) {
          document.getElementById('connecting-mask').classList.add('hidden');
          document.getElementById('start-mask').classList.remove('hidden');
        }
        break;
      case 'active':
        if (active) {
          document.getElementById('cameraPublisherContainer').classList.remove('hidden');
          document.getElementById('start-mask').classList.add('hidden');
          document.getElementById('controls').classList.remove('hidden');
        }
        else {
          document.getElementById('start-mask').classList.remove('hidden');
          document.getElementById('controls').classList.add('hidden');
          document.getElementById('cameraPublisherContainer').classList.add('hidden');
          document.getElementById('toggleLocalVideo').classList.remove('muted');
          document.getElementById('toggleLocalAudio').classList.remove('muted');
        }
        break;
      case 'meta':
        updateVideoContainers();
        break;
      default:
        console.log('nothing to do, nowhere to go');
    }
  };

  /**
   * Update the state and UI
   */
  const updateState = (updates) => {
    Object.assign(state, updates);
    Object.keys(updates).forEach(update => updateUI(update));
  };

  /**
   * Start publishing video/audio and subscribe to streams
   */
  const startCall = () => {
    otCore.startCall()
      .then(({ publishers, subscribers, meta }) => {
        updateState({ publishers, subscribers, meta, active: true });
      }).catch(error => console.log(error));
  };

  /**
   * Toggle publishing local audio
   */
  const toggleLocalAudio = () => {
    const enabled = state.localAudioEnabled;
    otCore.toggleLocalAudio(!enabled);
    updateState({ localAudioEnabled: !enabled });
    const action = enabled ? 'add' : 'remove';
    document.getElementById('toggleLocalAudio').classList[action]('muted');
  };

  /**
   * Toggle publishing local video
   */
  const toggleLocalVideo = () => {
    const enabled = state.localVideoEnabled;
    otCore.toggleLocalVideo(!enabled);
    updateState({ localVideoEnabled: !enabled });
    const action = enabled ? 'add' : 'remove';
    document.getElementById('toggleLocalVideo').classList[action]('muted');
  };

  /**
   * Toggle end call
   */
  const toggleEndCall = () => {
    updateState({ active: false });
    otCore.endCall();
  };

  /**
   * Subscribe to otCore and UI events
   */
  const createEventListeners = () => {
    const events = [
      'subscribeToCamera',
      'unsubscribeFromCamera',
    ];
    events.forEach(event => otCore.on(event, ({ publishers, subscribers, meta }) => {
      updateState({ publishers, subscribers, meta });
    }));

    document.getElementById('start').addEventListener('click', startCall);
    document.getElementById('toggleLocalAudio').addEventListener('click', toggleLocalAudio);
    document.getElementById('toggleLocalVideo').addEventListener('click', toggleLocalVideo);
    document.getElementById('toggleEndCall').addEventListener('click', toggleEndCall);
  };

  /**
   * Initialize otCore, connect to the session, and listen to events
   */
  const init = () => {
    otCore.init(options);
    otCore.connect().then(() => updateState({ connected: true }));
    createEventListeners();
  };

  init();
};

document.addEventListener('DOMContentLoaded', app);


================================================
FILE: js/public/js/components/opentok-acc-core.js
================================================
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
function _classCallCheck(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}var _this=this,_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},_createClass=function(){function n(n,e){for(var t=0;t<e.length;t++){var o=e[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(n,o.key,o)}}return function(e,t,o){return t&&n(e.prototype,t),o&&n(e,o),e}}();!function(){var n=function(n,e,t){var o="",r=void 0;t&&(r=new Date,r.setTime(r.getTime()+24*t*60*60*1e3),o=["; expires=",r.toGMTString()].join(""));var i=[n,"=",e,o,"; path=/"].join("");return document.cookie=i,e},e=function(n){for(var e=n+"=",t=document.cookie.split(";"),o=void 0,r=0;r<t.length;r++){for(o=t[r];" "===o.charAt(0);)o=o.substring(1,o.length);if(0===o.indexOf(e))return o.substring(e.length,o.length)}return null},t=function(){for(var n=[],e="0123456789abcdef",t=0;t<36;t++)n.push(e.substr(Math.floor(16*Math.random()),1));return n[14]="4",n[19]=e.substr(3&n[19]|8,1),n[8]=n[13]=n[18]=n[23]="-",n.join("")},o=function(o){return e(o)||n(o,t(),7)},r=function(n){if(!n.clientVersion)throw console.log("Error. The clientVersion field cannot be null in the log entry"),new Error("The clientVersion field cannot be null in the log entry");if(!n.source)throw console.log("Error. The source field cannot be null in the log entry"),new Error("The source field cannot be null in the log entry");if(!n.componentId)throw console.log("Error. The componentId field cannot be null in the log entry"),new Error("The componentId field cannot be null in the log entry");if(!n.name)throw console.log("Error. The name field cannot be null in the log entry"),new Error("The guid field cannot be null in the log entry");var e=n.logVersion||"2",t=n.clientSystemTime||(new Date).getTime();return Object.assign({},n,{logVersion:e,clientSystemTime:t})},i=function(n){var e=r(n),t="https://hlg.tokbox.com/prod/logging/ClientEvent",o=new XMLHttpRequest;o.open("POST",t,!0),o.setRequestHeader("Content-type","application/json"),o.send(JSON.stringify(e))},l=function(){function n(e){_classCallCheck(this,n),this.analyticsData=e,this.analyticsData.guid=o(e.name)}return _createClass(n,[{key:"addSessionInfo",value:function(n){if(!n.sessionId)throw console.log("Error. The sessionId field cannot be null in the log entry"),new Error("The sessionId field cannot be null in the log entry");if(this.analyticsData.sessionId=n.sessionId,!n.connectionId)throw console.log("Error. The connectionId field cannot be null in the log entry"),new Error("The connectionId field cannot be null in the log entry");if(this.analyticsData.connectionId=n.connectionId,0===n.partnerId)throw console.log("Error. The partnerId field cannot be null in the log entry"),new Error("The partnerId field cannot be null in the log entry");this.analyticsData.partnerId=n.partnerId}},{key:"logEvent",value:function(n){this.analyticsData.action=n.action,this.analyticsData.variation=n.variation,this.analyticsData.clientSystemTime=(new Date).getTime(),i(this.analyticsData)}}]),n}();"object"===("undefined"==typeof exports?"undefined":_typeof(exports))?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):_this.OTKAnalytics=l}(this);
},{}],2:[function(require,module,exports){
'use strict';

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

/* global OT */

/** Dependencies */
var state = require('./state');

var _require = require('./errors'),
    CoreError = _require.CoreError;

var _require2 = require('./util'),
    dom = _require2.dom,
    path = _require2.path,
    pathOr = _require2.pathOr,
    properCase = _require2.properCase;

var _require3 = require('./logging'),
    message = _require3.message,
    logAnalytics = _require3.logAnalytics,
    logAction = _require3.logAction,
    logVariation = _require3.logVariation;

/** Module variables */


var session = void 0;
var accPack = void 0;
var callProperties = void 0;
var screenProperties = void 0;
var streamContainers = void 0;
var autoSubscribe = void 0;
var connectionLimit = void 0;
var active = false;

/**
 * Default UI propties
 * https://tokbox.com/developer/guides/customize-ui/js/
 */
var defaultCallProperties = {
  insertMode: 'append',
  width: '100%',
  height: '100%',
  showControls: false,
  style: {
    buttonDisplayMode: 'off'
  }
};

/**
 * Trigger an event through the API layer
 * @param {String} event - The name of the event
 * @param {*} [data]
 */
var triggerEvent = function triggerEvent(event, data) {
  return accPack.triggerEvent(event, data);
};

/**
 * Determine whether or not the party is able to join the call based on
 * the specified connection limit, if any.
 * @return {Boolean}
 */
var ableToJoin = function ableToJoin() {
  if (!connectionLimit) {
    return true;
  }
  // Not using the session here since we're concerned with number of active publishers
  var connections = Object.values(state.getStreams()).filter(function (s) {
    return s.videoType === 'camera';
  });
  return connections.length < connectionLimit;
};

/**
 * Create a camera publisher object
 * @param {Object} publisherProperties
 * @returns {Promise} <resolve: Object, reject: Error>
 */
var createPublisher = function createPublisher(publisherProperties) {
  return new Promise(function (resolve, reject) {
    // TODO: Handle adding 'name' option to props
    var props = Object.assign({}, callProperties, publisherProperties);
    // TODO: Figure out how to handle common vs package-specific options
    // ^^^ This may already be available through package options
    var container = dom.element(streamContainers('publisher', 'camera'));
    var publisher = OT.initPublisher(container, props, function (error) {
      error ? reject(error) : resolve(publisher);
    });
  });
};

/**
 * Publish the local camera stream and update state
 * @param {Object} publisherProperties
 * @returns {Promise} <resolve: empty, reject: Error>
 */
var publish = function publish(publisherProperties) {
  return new Promise(function (resolve, reject) {
    var onPublish = function onPublish(publisher) {
      return function (error) {
        if (error) {
          reject(error);
          logAnalytics(logAction.startCall, logVariation.fail);
        } else {
          logAnalytics(logAction.startCall, logVariation.success);
          state.addPublisher('camera', publisher);
          resolve(publisher);
        }
      };
    };

    var publishToSession = function publishToSession(publisher) {
      return session.publish(publisher, onPublish(publisher));
    };

    var handleError = function handleError(error) {
      logAnalytics(logAction.startCall, logVariation.fail);
      var errorMessage = error.code === 1010 ? 'Check your network connection' : error.message;
      triggerEvent('error', errorMessage);
      reject(error);
    };

    createPublisher(publisherProperties).then(publishToSession).catch(handleError);
  });
};

/**
 * Subscribe to a stream and update the state
 * @param {Object} stream - An OpenTok stream object
 * @returns {Promise} <resolve: empty reject: Error >
 */
var subscribe = function subscribe(stream) {
  return new Promise(function (resolve, reject) {
    logAnalytics(logAction.subscribe, logVariation.attempt);
    var streamMap = state.getStreamMap();
    if (streamMap[stream.id]) {
      // Are we already subscribing to the stream?
      resolve();
    } else {
      (function () {
        // No videoType indicates SIP https://tokbox.com/developer/guides/sip/
        var type = pathOr('sip', 'videoType', stream);
        var connectionData = JSON.parse(path(['connection', 'data'], stream) || null);
        var container = dom.query(streamContainers('subscriber', type, connectionData));
        var options = type === 'camera' ? callProperties : screenProperties;
        var subscriber = session.subscribe(stream, container, options, function (error) {
          if (error) {
            logAnalytics(logAction.subscribe, logVariation.fail);
            reject(error);
          } else {
            state.addSubscriber(subscriber);
            triggerEvent('subscribeTo' + properCase(type), Object.assign({}, { subscriber: subscriber }, state.all()));
            type === 'screen' && triggerEvent('startViewingSharedScreen', subscriber); // Legacy event
            logAnalytics(logAction.subscribe, logVariation.success);
            resolve();
          }
        });
      })();
    }
  });
};

/**
 * Unsubscribe from a stream and update the state
 * @param {Object} subscriber - An OpenTok subscriber object
 * @returns {Promise} <resolve: empty>
 */
var unsubscribe = function unsubscribe(subscriber) {
  return new Promise(function (resolve) {
    logAnalytics(logAction.unsubscribe, logVariation.attempt);
    var type = path('stream.videoType', subscriber);
    state.removeSubscriber(type, subscriber);
    session.unsubscribe(subscriber);
    logAnalytics(logAction.unsubscribe, logVariation.success);
    resolve();
  });
};

/**
 * Ensure all required options are received
 * @param {Object} options
 */
var validateOptions = function validateOptions(options) {
  var requiredOptions = ['accPack'];
  requiredOptions.forEach(function (option) {
    if (!options[option]) {
      throw new CoreError(option + ' is a required option.', 'invalidParameters');
    }
  });

  accPack = options.accPack;
  streamContainers = options.streamContainers;
  callProperties = options.callProperties || defaultCallProperties;
  connectionLimit = options.connectionLimit || null;
  autoSubscribe = options.hasOwnProperty('autoSubscribe') ? options.autoSubscribe : true;

  screenProperties = options.screenProperties || Object.assign({}, defaultCallProperties, { videoSource: 'window' });
};

/**
 * Set session in module scope
 */
var setSession = function setSession() {
  session = state.getSession();
};

/**
 * Subscribe to new stream unless autoSubscribe is set to false
 * @param {Object} stream
 */
var onStreamCreated = function onStreamCreated(_ref) {
  var stream = _ref.stream;
  return active && autoSubscribe && subscribe(stream);
};

/**
 * Update state and trigger corresponding event(s) when stream is destroyed
 * @param {Object} stream
 */
var onStreamDestroyed = function onStreamDestroyed(_ref2) {
  var stream = _ref2.stream;

  state.removeStream(stream);
  var type = pathOr('sip', 'videoType', stream);
  type === 'screen' && triggerEvent('endViewingSharedScreen'); // Legacy event
  triggerEvent('unsubscribeFrom' + properCase(type), state.getPubSub());
};

/**
 * Listen for API-level events
 */
var createEventListeners = function createEventListeners() {
  accPack.on('streamCreated', onStreamCreated);
  accPack.on('streamDestroyed', onStreamDestroyed);
};

/**
 * Start publishing the local camera feed and subscribing to streams in the session
 * @param {Object} publisherProperties
 * @returns {Promise} <resolve: Object, reject: Error>
 */
var startCall = function startCall(publisherProperties) {
  return new Promise(function (resolve, reject) {
    // eslint-disable-line consistent-return
    logAnalytics(logAction.startCall, logVariation.attempt);

    /**
     * Determine if we're able to join the session based on an existing connection limit
     */
    if (!ableToJoin()) {
      var errorMessage = 'Session has reached its connection limit';
      triggerEvent('error', errorMessage);
      logAnalytics(logAction.startCall, logVariation.fail);
      return reject(new CoreError(errorMessage, 'connectionLimit'));
    }

    /**
     * Subscribe to any streams that existed before we start the call from our side.
     */
    var subscribeToInitialStreams = function subscribeToInitialStreams(publisher) {
      // Get an array of initial subscription promises
      var initialSubscriptions = function initialSubscriptions() {
        if (autoSubscribe) {
          var _ret2 = function () {
            var streams = state.getStreams();
            return {
              v: Object.keys(streams).map(function (id) {
                return subscribe(streams[id]);
              })
            };
          }();

          if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v;
        }
        return [Promise.resolve()];
      };

      // Handle success
      var onSubscribeToAll = function onSubscribeToAll() {
        var pubSubData = Object.assign({}, state.getPubSub(), { publisher: publisher });
        triggerEvent('startCall', pubSubData);
        active = true;
        resolve(pubSubData);
      };

      // Handle error
      var onError = function onError(reason) {
        message('Failed to subscribe to all existing streams: ' + reason);
        // We do not reject here in case we still successfully publish to the session
        resolve(Object.assign({}, state.getPubSub(), { publisher: publisher }));
      };

      Promise.all(initialSubscriptions()).then(onSubscribeToAll).catch(onError);
    };

    publish(publisherProperties).then(subscribeToInitialStreams).catch(reject);
  });
};

/**
 * Stop publishing and unsubscribe from all streams
 */
var endCall = function endCall() {
  logAnalytics(logAction.endCall, logVariation.attempt);

  var _state$getPubSub = state.getPubSub(),
      publishers = _state$getPubSub.publishers,
      subscribers = _state$getPubSub.subscribers;

  var unpublish = function unpublish(publisher) {
    return session.unpublish(publisher);
  };
  Object.values(publishers.camera).forEach(unpublish);
  Object.values(publishers.screen).forEach(unpublish);
  // TODO Promise.all for unsubsribing
  Object.values(subscribers.camera).forEach(unsubscribe);
  Object.values(subscribers.screen).forEach(unsubscribe);
  state.removeAllPublishers();
  active = false;
  triggerEvent('endCall');
  logAnalytics(logAction.endCall, logVariation.success);
};

/**
 * Enable/disable local audio or video
 * @param {String} source - 'audio' or 'video'
 * @param {Boolean} enable
 */
var enableLocalAV = function enableLocalAV(id, source, enable) {
  var method = 'publish' + properCase(source);

  var _state$getPubSub2 = state.getPubSub(),
      publishers = _state$getPubSub2.publishers;

  publishers.camera[id][method](enable);
};

/**
 * Enable/disable remote audio or video
 * @param {String} subscriberId
 * @param {String} source - 'audio' or 'video'
 * @param {Boolean} enable
 */
var enableRemoteAV = function enableRemoteAV(subscriberId, source, enable) {
  var method = 'subscribeTo' + properCase(source);

  var _state$getPubSub3 = state.getPubSub(),
      subscribers = _state$getPubSub3.subscribers;

  subscribers.camera[subscriberId][method](enable);
};

/**
 * Initialize the communication component
 * @param {Object} options
 * @param {Object} options.accPack
 * @param {Number} options.connectionLimit
 * @param {Function} options.streamContainer
 */
var init = function init(options) {
  return new Promise(function (resolve) {
    validateOptions(options);
    setSession();
    createEventListeners();
    resolve();
  });
};

/** Exports */
module.exports = {
  init: init,
  startCall: startCall,
  endCall: endCall,
  subscribe: subscribe,
  unsubscribe: unsubscribe,
  enableLocalAV: enableLocalAV,
  enableRemoteAV: enableRemoteAV
};

},{"./errors":4,"./logging":6,"./state":10,"./util":11}],3:[function(require,module,exports){
(function (global){
'use strict';

var _arguments = arguments;

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

/* global OT */
/**
 * Dependencies
 */
var util = require('./util');
var internalState = require('./state');
var accPackEvents = require('./events');
var communication = require('./communication');
var OpenTokSDK = require('./sdk-wrapper/sdkWrapper');

var _require = require('./errors'),
    CoreError = _require.CoreError;

var _require2 = require('./logging'),
    message = _require2.message,
    initLogAnalytics = _require2.initLogAnalytics,
    logAnalytics = _require2.logAnalytics,
    logAction = _require2.logAction,
    logVariation = _require2.logVariation,
    updateLogAnalytics = _require2.updateLogAnalytics;

/**
 * Helper methods
 */


var dom = util.dom,
    path = util.path,
    pathOr = util.pathOr,
    properCase = util.properCase;

/**
 * Individual Accelerator Packs
 */

var textChat = void 0; // eslint-disable-line no-unused-vars
var screenSharing = void 0; // eslint-disable-line no-unused-vars
var annotation = void 0;
var archiving = void 0; // eslint-disable-line no-unused-vars

/**
 * Get access to an accelerator pack
 * @param {String} packageName - textChat, screenSharing, annotation, or archiving
 * @returns {Object} The instance of the accelerator pack
 */
var getAccPack = function getAccPack(packageName) {
  logAnalytics(logAction.getAccPack, logVariation.attempt);
  var packages = {
    textChat: textChat,
    screenSharing: screenSharing,
    annotation: annotation,
    archiving: archiving
  };
  logAnalytics(logAction.getAccPack, logVariation.success);
  return packages[packageName];
};

/** Eventing */

var eventListeners = {};

/**
 * Register events that can be listened to be other components/modules
 * @param {array | string} events - A list of event names. A single event may
 * also be passed as a string.
 */
var registerEvents = function registerEvents(events) {
  var eventList = Array.isArray(events) ? events : [events];
  eventList.forEach(function (event) {
    if (!eventListeners[event]) {
      eventListeners[event] = new Set();
    }
  });
};

/**
 * Register a callback for a specific event or pass an object with
 * with event => callback key/value pairs to register listeners for
 * multiple events.
 * @param {String | Object} event - The name of the event
 * @param {Function} callback
 */
var on = function on(event, callback) {
  // logAnalytics(logAction.on, logVariation.attempt);
  if ((typeof event === 'undefined' ? 'undefined' : _typeof(event)) === 'object') {
    Object.keys(event).forEach(function (eventName) {
      on(eventName, event[eventName]);
    });
    return;
  }
  var eventCallbacks = eventListeners[event];
  if (!eventCallbacks) {
    message(event + ' is not a registered event.');
    // logAnalytics(logAction.on, logVariation.fail);
  } else {
    eventCallbacks.add(callback);
    // logAnalytics(logAction.on, logVariation.success);
  }
};

/**
 * Remove a callback for a specific event.  If no parameters are passed,
 * all event listeners will be removed.
 * @param {String} event - The name of the event
 * @param {Function} callback
 */
var off = function off(event, callback) {
  // logAnalytics(logAction.off, logVariation.attempt);
  if (_arguments.lenth === 0) {
    Object.keys(eventListeners).forEach(function (eventType) {
      eventListeners[eventType].clear();
    });
  }
  var eventCallbacks = eventListeners[event];
  if (!eventCallbacks) {
    // logAnalytics(logAction.off, logVariation.fail);
    message(event + ' is not a registered event.');
  } else {
    eventCallbacks.delete(callback);
    // logAnalytics(logAction.off, logVariation.success);
  }
};

/**
 * Trigger an event and fire all registered callbacks
 * @param {String} event - The name of the event
 * @param {*} data - Data to be passed to callback functions
 */
var triggerEvent = function triggerEvent(event, data) {
  var eventCallbacks = eventListeners[event];
  if (!eventCallbacks) {
    registerEvents(event);
    message(event + ' has been registered as a new event.');
  } else {
    eventCallbacks.forEach(function (callback) {
      return callback(data, event);
    });
  }
};

/**
 * Get the current OpenTok session object
 * @returns {Object}
 */
var getSession = internalState.getSession;

/**
 * Returns the current OpenTok session credentials
 * @returns {Object}
 */
var getCredentials = internalState.getCredentials;

/**
 * Returns the options used for initialization
 * @returns {Object}
 */
var getOptions = internalState.getOptions;

var createEventListeners = function createEventListeners(session, options) {
  Object.keys(accPackEvents).forEach(function (type) {
    return registerEvents(accPackEvents[type]);
  });

  /**
   * If using screen sharing + annotation in an external window, the screen sharing
   * package will take care of calling annotation.start() and annotation.linkCanvas()
   */
  var usingAnnotation = path('screenSharing.annotation', options);
  var internalAnnotation = usingAnnotation && !path('screenSharing.externalWindow', options);

  /**
   * Wrap session events and update internalState when streams are created
   * or destroyed
   */
  accPackEvents.session.forEach(function (eventName) {
    session.on(eventName, function (event) {
      if (eventName === 'streamCreated') {
        internalState.addStream(event.stream);
      }
      if (eventName === 'streamDestroyed') {
        internalState.removeStream(event.stream);
      }
      triggerEvent(eventName, event);
    });
  });

  if (usingAnnotation) {
    on('subscribeToScreen', function (_ref) {
      var subscriber = _ref.subscriber;

      annotation.start(getSession()).then(funct
Download .txt
gitextract_smhvk9sm/

├── .github/
│   ├── CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── LICENSE
├── README.md
├── android/
│   ├── .gitignore
│   ├── OneToOneSample/
│   │   ├── .gitignore
│   │   ├── app/
│   │   │   ├── .gitignore
│   │   │   ├── build.gradle
│   │   │   ├── proguard-rules.pro
│   │   │   └── src/
│   │   │       └── main/
│   │   │           ├── AndroidManifest.xml
│   │   │           ├── java/
│   │   │           │   └── com/
│   │   │           │       └── tokbox/
│   │   │           │           └── android/
│   │   │           │               └── onetoonesample/
│   │   │           │                   ├── MainActivity.java
│   │   │           │                   ├── config/
│   │   │           │                   │   └── OpenTokConfig.java
│   │   │           │                   └── ui/
│   │   │           │                       ├── PreviewCameraFragment.java
│   │   │           │                       ├── PreviewControlFragment.java
│   │   │           │                       └── RemoteControlFragment.java
│   │   │           └── res/
│   │   │               ├── drawable/
│   │   │               │   ├── bckg_audio_only.xml
│   │   │               │   ├── bckg_icon.xml
│   │   │               │   ├── end_call_button.xml
│   │   │               │   ├── gradient_audionly.xml
│   │   │               │   ├── gradient_backg.xml
│   │   │               │   ├── initiate_call_button.xml
│   │   │               │   └── preview.xml
│   │   │               ├── layout/
│   │   │               │   ├── activity_main.xml
│   │   │               │   ├── preview_actionbar_fragment.xml
│   │   │               │   ├── preview_camera_fragment.xml
│   │   │               │   └── remote_actionbar_fragment.xml
│   │   │               ├── values/
│   │   │               │   ├── colors.xml
│   │   │               │   ├── dimens.xml
│   │   │               │   ├── strings.xml
│   │   │               │   └── styles.xml
│   │   │               ├── values-v21/
│   │   │               │   └── styles.xml
│   │   │               └── values-w820dp/
│   │   │                   └── dimens.xml
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       └── gradle-wrapper.properties
│   │   ├── gradle.properties
│   │   ├── gradlew
│   │   ├── gradlew.bat
│   │   └── settings.gradle
│   └── README.md
├── iOS/
│   ├── .gitignore
│   ├── OneToOneSample.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── OneToOneSample.xcscheme
│   ├── Podfile
│   ├── README.md
│   └── SampleApp/
│       ├── AppDelegate.h
│       ├── AppDelegate.m
│       ├── Assets.xcassets/
│       │   ├── AppIcon.appiconset/
│       │   │   └── Contents.json
│       │   ├── Contents.json
│       │   ├── audio.imageset/
│       │   │   └── Contents.json
│       │   ├── hangUp.imageset/
│       │   │   └── Contents.json
│       │   ├── mic.imageset/
│       │   │   └── Contents.json
│       │   ├── mutedMic.imageset/
│       │   │   └── Contents.json
│       │   ├── noAudio.imageset/
│       │   │   └── Contents.json
│       │   ├── noVideo.imageset/
│       │   │   └── Contents.json
│       │   ├── reverse cameras.imageset/
│       │   │   └── Contents.json
│       │   ├── startCall.imageset/
│       │   │   └── Contents.json
│       │   └── video.imageset/
│       │       └── Contents.json
│       ├── Base.lproj/
│       │   ├── LaunchScreen.storyboard
│       │   └── Main.storyboard
│       ├── Info.plist
│       ├── MainView.h
│       ├── MainView.m
│       ├── MainViewController.h
│       ├── MainViewController.m
│       ├── UIView+Helper.h
│       ├── UIView+Helper.m
│       └── main.m
└── js/
    ├── .eslintrc.json
    ├── .gitignore
    ├── .jsbeautifyrc
    ├── Procfile
    ├── README.md
    ├── package.json
    ├── public/
    │   ├── css/
    │   │   └── style.css
    │   ├── index.html
    │   └── js/
    │       ├── app.js
    │       └── components/
    │           └── opentok-acc-core.js
    └── server.js
Download .txt
SYMBOL INDEX (108 symbols across 6 files)

FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/MainActivity.java
  class MainActivity (line 43) | public class MainActivity extends AppCompatActivity implements PreviewCo...
    method onCreate (line 83) | @Override
    method onConfigurationChanged (line 143) | @Override
    method onPause (line 149) | @Override
    method onResume (line 157) | @Override
    method onBackPressed (line 165) | @Override
    method onRequestPermissionsResult (line 173) | @Override
    method showRemoteControlBar (line 206) | public void showRemoteControlBar(View v) {
    method isCallInProgress (line 212) | public boolean isCallInProgress() {
    method getWrapper (line 216) | public OTWrapper getWrapper() {
    method initPreviewFragment (line 222) | private void initPreviewFragment() {
    method initRemoteFragment (line 229) | private void initRemoteFragment(String remoteId) {
    method initCameraFragment (line 241) | private void initCameraFragment() {
    method cleanViewsAndControls (line 248) | private void cleanViewsAndControls() {
    method reloadViews (line 265) | private void reloadViews(){
    method checkRemotes (line 274) | private void checkRemotes(){
    method setLocalView (line 289) | private void setLocalView(View localView){
    method setRemoteView (line 313) | private void setRemoteView(View remoteView) {
    method onRemoteAudioOnly (line 337) | private void onRemoteAudioOnly(boolean enabled) {
    method dpToPx (line 350) | private int dpToPx(int dp) {
    method onConnected (line 358) | @Override
    method onDisconnected (line 365) | @Override
    method onPreviewViewReady (line 374) | @Override
    method onPreviewViewDestroyed (line 380) | @Override
    method onRemoteViewReady (line 386) | @Override
    method onRemoteViewDestroyed (line 397) | @Override
    method onStartedPublishingMedia (line 405) | @Override
    method onStoppedPublishingMedia (line 412) | @Override
    method onRemoteJoined (line 417) | @Override
    method onRemoteLeft (line 429) | @Override
    method onRemoteVideoChanged (line 437) | @Override
    method onError (line 462) | @Override
    method onCameraChanged (line 477) | @Override
    method onReconnecting (line 482) | @Override
    method onReconnected (line 488) | @Override
    method onVideoQualityWarning (line 494) | @Override
    method onVideoQualityWarningLifted (line 508) | @Override
    method onError (line 513) | @Override
    method onDisableLocalAudio (line 523) | @Override
    method onDisableLocalVideo (line 531) | @Override
    method onDisableRemoteAudio (line 557) | @Override
    method onDisableRemoteVideo (line 564) | @Override
    method onCameraSwap (line 572) | @Override
    method onCall (line 579) | @Override

FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/config/OpenTokConfig.java
  class OpenTokConfig (line 3) | public class OpenTokConfig {

FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewCameraFragment.java
  class PreviewCameraFragment (line 19) | public class PreviewCameraFragment extends Fragment {
    type PreviewCameraCallbacks (line 27) | public interface PreviewCameraCallbacks {
      method onCameraSwap (line 28) | void onCameraSwap();
    method onCameraSwap (line 32) | @Override
    method onClick (line 38) | public void onClick(View v) {
    method onAttach (line 43) | @Override
    method onAttach (line 51) | @SuppressWarnings("deprecation")
    method onDetach (line 61) | @Override
    method onCreateView (line 70) | @Nullable
    method cameraSwap (line 82) | public void cameraSwap() {

FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewControlFragment.java
  class PreviewControlFragment (line 22) | public class PreviewControlFragment extends Fragment {
    type PreviewControlCallbacks (line 38) | public interface PreviewControlCallbacks {
      method onDisableLocalAudio (line 40) | void onDisableLocalAudio(boolean audio);
      method onDisableLocalVideo (line 42) | void onDisableLocalVideo(boolean video);
      method onCall (line 44) | void onCall();
    method onDisableLocalAudio (line 48) | @Override
    method onDisableLocalVideo (line 51) | @Override
    method onCall (line 54) | @Override
    method onClick (line 60) | public void onClick(View v) {
    method onAttach (line 77) | @Override
    method onAttach (line 87) | @SuppressWarnings("deprecation")
    method onDetach (line 99) | @Override
    method onCreate (line 108) | @Override
    method onCreateView (line 116) | @Nullable
    method updateLocalAudio (line 155) | public void updateLocalAudio() {
    method updateLocalVideo (line 165) | public void updateLocalVideo() {
    method updateCall (line 175) | public void updateCall() {
    method setEnabled (line 188) | public void setEnabled(boolean enabled) {
    method restart (line 202) | public void restart() {

FILE: android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/RemoteControlFragment.java
  class RemoteControlFragment (line 20) | public class RemoteControlFragment extends Fragment {
    type RemoteControlCallbacks (line 35) | public interface RemoteControlCallbacks {
      method onDisableRemoteAudio (line 36) | void onDisableRemoteAudio(boolean audio);
      method onDisableRemoteVideo (line 38) | void onDisableRemoteVideo(boolean video);
    method onDisableRemoteAudio (line 42) | @Override
    method onDisableRemoteVideo (line 45) | @Override
    method onClick (line 50) | public void onClick(View v) {
    method onAttach (line 63) | @Override
    method onAttach (line 73) | @SuppressWarnings("deprecation")
    method onDetach (line 88) | @Override
    method onCreateView (line 95) | @Nullable
    method updateRemoteAudio (line 111) | public void updateRemoteAudio(){
    method updateRemoteVideo (line 122) | public void updateRemoteVideo(){
    method show (line 133) | public void show(){
    method setEnabled (line 144) | private void setEnabled(boolean enabled) {
    method restart (line 153) | public void restart() {

FILE: js/public/js/components/opentok-acc-core.js
  function s (line 1) | function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&re...
  function _classCallCheck (line 2) | function _classCallCheck(n,e){if(!(n instanceof e))throw new TypeError("...
  function n (line 2) | function n(n,e){for(var t=0;t<e.length;t++){var o=e[t];o.enumerable=o.en...
  function n (line 2) | function n(e){_classCallCheck(this,n),this.analyticsData=e,this.analytic...
  function _classCallCheck (line 1061) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function _possibleConstructorReturn (line 1063) | function _possibleConstructorReturn(self, call) { if (!self) { throw new...
  function _inherits (line 1065) | function _inherits(subClass, superClass) { if (typeof superClass !== "fu...
  function CoreError (line 1071) | function CoreError(errorMessage, errorType) {
  function _classCallCheck (line 1185) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function _possibleConstructorReturn (line 1187) | function _possibleConstructorReturn(self, call) { if (!self) { throw new...
  function _inherits (line 1189) | function _inherits(subClass, superClass) { if (typeof superClass !== "fu...
  function SDKError (line 1195) | function SDKError(errorMessage, errorType) {
  function defineProperties (line 1217) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _classCallCheck (line 1219) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function OpenTokSDK (line 1322) | function OpenTokSDK(credentials) {
  function defineProperties (line 1705) | function defineProperties(target, props) { for (var i = 0; i < props.len...
  function _classCallCheck (line 1707) | function _classCallCheck(instance, Constructor) { if (!(instance instanc...
  function State (line 1710) | function State() {
Condensed preview — 80 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (258K chars).
[
  {
    "path": ".github/CONDUCT.md",
    "chars": 3242,
    "preview": "**opentok/one-to-one-sample-apps** Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming en"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 2136,
    "preview": "# Contributing to OpenTok One-to-One Communication Sample Apps\n\n## Code of Conduct\n\nPlease read our [Code of Conduct](ht"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 771,
    "preview": "## New issue checklist\n<!-- Before submitting this issue, make sure you have done the following -->\n\n- [ ] I have read a"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 209,
    "preview": "## Pull request checklist\n\n- [ ] All tests pass. Demo project builds and runs.\n- [ ] I have resolved any merge conflicts"
  },
  {
    "path": "LICENSE",
    "chars": 1090,
    "preview": "LICENSE\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 TokBox, Inc.\n\nPermission is hereby granted, free of charge, to any pe"
  },
  {
    "path": "README.md",
    "chars": 4143,
    "preview": "# DEPRECATED: OpenTok One-to-One Communication Sample App<br/>Version 1.3\n\n<img src=\"https://assets.tokbox.com/img/vonag"
  },
  {
    "path": "android/.gitignore",
    "chars": 298,
    "preview": "# built components files\n*.jar\n\n# files for the dex VM\n*.dex\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\n\n#"
  },
  {
    "path": "android/OneToOneSample/.gitignore",
    "chars": 97,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": "android/OneToOneSample/app/.gitignore",
    "chars": 13,
    "preview": "/build\n/libs\n"
  },
  {
    "path": "android/OneToOneSample/app/build.gradle",
    "chars": 1076,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.0\"\n\n    defaultC"
  },
  {
    "path": "android/OneToOneSample/app/proguard-rules.pro",
    "chars": 658,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
  },
  {
    "path": "android/OneToOneSample/app/src/main/AndroidManifest.xml",
    "chars": 1286,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/MainActivity.java",
    "chars": 24302,
    "preview": "package com.tokbox.android.onetoonesample;\n\nimport android.Manifest;\nimport android.app.ProgressDialog;\nimport android.c"
  },
  {
    "path": "android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/config/OpenTokConfig.java",
    "chars": 593,
    "preview": "package com.tokbox.android.onetoonesample.config;\n\npublic class OpenTokConfig {\n\n    // *** Fill the following variables"
  },
  {
    "path": "android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewCameraFragment.java",
    "chars": 2422,
    "preview": "package com.tokbox.android.onetoonesample.ui;\n\nimport android.app.Activity;\nimport android.support.v4.app.Fragment;\nimpo"
  },
  {
    "path": "android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/PreviewControlFragment.java",
    "chars": 6760,
    "preview": "package com.tokbox.android.onetoonesample.ui;\n\nimport android.app.Activity;\nimport android.support.graphics.drawable.Vec"
  },
  {
    "path": "android/OneToOneSample/app/src/main/java/com/tokbox/android/onetoonesample/ui/RemoteControlFragment.java",
    "chars": 5036,
    "preview": "package com.tokbox.android.onetoonesample.ui;\n\nimport android.app.Activity;\nimport android.support.v4.app.Fragment;\nimpo"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/bckg_audio_only.xml",
    "chars": 228,
    "preview": "<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    android:shape=\"rectangle\">\n    <solid android"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/bckg_icon.xml",
    "chars": 432,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"106dp\"\n        android:height="
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/end_call_button.xml",
    "chars": 422,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"105dp\"\n    android:height=\"105dp\"\n"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/gradient_audionly.xml",
    "chars": 238,
    "preview": "<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:startColor=\"@color/"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/gradient_backg.xml",
    "chars": 220,
    "preview": "<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:startColor=\"@color/"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/initiate_call_button.xml",
    "chars": 440,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"105dp\"\n        android:height="
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/drawable/preview.xml",
    "chars": 173,
    "preview": "<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    android:shape=\"rectangle\">\n    <stroke androi"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/layout/activity_main.xml",
    "chars": 4617,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout xmlns:android=\"http://schemas.an"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/layout/preview_actionbar_fragment.xml",
    "chars": 1844,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/layout/preview_camera_fragment.xml",
    "chars": 625,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/layout/remote_actionbar_fragment.xml",
    "chars": 1235,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values/colors.xml",
    "chars": 634,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"gradientStart\">#5B5B5B</color>\n    <color name=\"grad"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values/dimens.xml",
    "chars": 600,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"border\">1dp</dimen>"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values/strings.xml",
    "chars": 656,
    "preview": "<resources>\n    <string name=\"app_name\">OneToOneSample</string>\n    <string name=\"network_quality\">Network connection is"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values/styles.xml",
    "chars": 475,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values-v21/styles.xml",
    "chars": 327,
    "preview": "<resources>\n\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item nam"
  },
  {
    "path": "android/OneToOneSample/app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "android/OneToOneSample/build.gradle",
    "chars": 574,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "android/OneToOneSample/gradle/wrapper/gradle-wrapper.properties",
    "chars": 233,
    "preview": "#Thu Jan 19 16:41:06 CET 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "android/OneToOneSample/gradle.properties",
    "chars": 855,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "android/OneToOneSample/gradlew",
    "chars": 4971,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "android/OneToOneSample/gradlew.bat",
    "chars": 2404,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "android/OneToOneSample/settings.gradle",
    "chars": 15,
    "preview": "include ':app'\n"
  },
  {
    "path": "android/README.md",
    "chars": 6872,
    "preview": "![logo](../tokbox-logo.png)\n\n# OpenTok One-to-One Communication Sample App for Android\n\n## Quick start\n\nThis section sho"
  },
  {
    "path": "iOS/.gitignore",
    "chars": 324,
    "preview": ".DS_Store\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!defau"
  },
  {
    "path": "iOS/OneToOneSample.xcodeproj/project.pbxproj",
    "chars": 14348,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "iOS/OneToOneSample.xcodeproj/xcshareddata/xcschemes/OneToOneSample.xcscheme",
    "chars": 4293,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0800\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "iOS/Podfile",
    "chars": 112,
    "preview": "\nplatform :ios, '9.0'\n\ntarget 'OneToOneSample' do \n  pod 'OTAcceleratorCore', '1.0.3'\n  pod 'SVProgressHUD'\nend\n"
  },
  {
    "path": "iOS/README.md",
    "chars": 3659,
    "preview": "![logo](../tokbox-logo.png)\n\n# OpenTok One-to-One Communication Sample App for iOS<br/>Version 1.3\n\n## Quick start\n\nThis"
  },
  {
    "path": "iOS/SampleApp/AppDelegate.h",
    "chars": 335,
    "preview": "//\n//  AppDelegate.h\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class OTAcce"
  },
  {
    "path": "iOS/SampleApp/AppDelegate.m",
    "chars": 2465,
    "preview": "//\n//  AppDelegate.m\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import \"OTAcc"
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 3007,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/audio.imageset/Contents.json",
    "chars": 372,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"audio.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n  "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/hangUp.imageset/Contents.json",
    "chars": 375,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"hangUp.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/mic.imageset/Contents.json",
    "chars": 366,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mic.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n    "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/mutedMic.imageset/Contents.json",
    "chars": 405,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"mutedMicLineCopy.png\",\n      \"scale\" : \"1x\"\n    "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/noAudio.imageset/Contents.json",
    "chars": 390,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"noSoundCopy.png\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/noVideo.imageset/Contents.json",
    "chars": 390,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"noVideoIcon.png\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/reverse cameras.imageset/Contents.json",
    "chars": 402,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"reverse cameras.png\",\n      \"scale\" : \"1x\"\n    }"
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/startCall.imageset/Contents.json",
    "chars": 384,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"startCall.png\",\n      \"scale\" : \"1x\"\n    },\n    "
  },
  {
    "path": "iOS/SampleApp/Assets.xcassets/video.imageset/Contents.json",
    "chars": 384,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"videoIcon.png\",\n      \"scale\" : \"1x\"\n    },\n    "
  },
  {
    "path": "iOS/SampleApp/Base.lproj/LaunchScreen.storyboard",
    "chars": 3086,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "iOS/SampleApp/Base.lproj/Main.storyboard",
    "chars": 15674,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "iOS/SampleApp/Info.plist",
    "chars": 1845,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "iOS/SampleApp/MainView.h",
    "chars": 753,
    "preview": "//\n//  MainView.h\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface MainV"
  },
  {
    "path": "iOS/SampleApp/MainView.m",
    "chars": 4574,
    "preview": "//\n//  MainView.m\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import \"MainView.h\"\n#import \"UIView+Help"
  },
  {
    "path": "iOS/SampleApp/MainViewController.h",
    "chars": 169,
    "preview": "//\n//  MainViewController.h\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@inter"
  },
  {
    "path": "iOS/SampleApp/MainViewController.m",
    "chars": 5789,
    "preview": "//\n//  MainViewController.m\n//\n// Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import \"MainView.h\"\n#import \"M"
  },
  {
    "path": "iOS/SampleApp/UIView+Helper.h",
    "chars": 191,
    "preview": "//\n//  UIView+Helper.h\n//\n//  Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface"
  },
  {
    "path": "iOS/SampleApp/UIView+Helper.m",
    "chars": 2756,
    "preview": "//\n//  UIView+Helper.m\n//\n//  Copyright © 2016 Tokbox, Inc. All rights reserved.\n//\n\n#import \"UIView+Helper.h\"\n\n@impleme"
  },
  {
    "path": "iOS/SampleApp/main.m",
    "chars": 201,
    "preview": "#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n  @autoreleasepool {\n      return U"
  },
  {
    "path": "js/.eslintrc.json",
    "chars": 550,
    "preview": "{\n  \"extends\": \"airbnb\",\n  \"env\": {\n    \"browser\": true,\n    \"node\": true\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 5"
  },
  {
    "path": "js/.gitignore",
    "chars": 12,
    "preview": "node_modules"
  },
  {
    "path": "js/.jsbeautifyrc",
    "chars": 172,
    "preview": "{\n    \"js\":{\n        \"indent_size\": 2,\n        \"space_after_anon_function\": true,\n        \"end_with_newline\": true,\n    "
  },
  {
    "path": "js/Procfile",
    "chars": 19,
    "preview": "web: node server.js"
  },
  {
    "path": "js/README.md",
    "chars": 1863,
    "preview": "![logo](../tokbox-logo.png)\n\n# OpenTok One-to-One Communication Sample App for JavaScript<br/>Version 1.3\n\n## Quick star"
  },
  {
    "path": "js/package.json",
    "chars": 637,
    "preview": "{\n  \"name\": \"one-to-one-sample\",\n  \"version\": \"1.0.4\",\n  \"description\": \"One to One sample app\",\n  \"main\": \"server.js\",\n"
  },
  {
    "path": "js/public/css/style.css",
    "chars": 4391,
    "preview": "html,\nbody {\n    margin: 0;\n    padding: 0;\n    box-sizing: border-box;\n    font-family: sans-serif;\n}\n\n.clickable {\n  c"
  },
  {
    "path": "js/public/index.html",
    "chars": 2022,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <title>OT Accelerator Core</title>\n\n    <link re"
  },
  {
    "path": "js/public/js/app.js",
    "chars": 5470,
    "preview": "/* global otCore */\nconst options = {\n  credentials: {\n    apiKey: \"\",  //Replace with your OpenTok API key \n    session"
  },
  {
    "path": "js/public/js/components/opentok-acc-core.js",
    "chars": 74085,
    "preview": "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0)"
  },
  {
    "path": "js/server.js",
    "chars": 476,
    "preview": "/* eslint-env es6 */\n\n/*\n * Dependencies\n */\nconst express = require('express');\nconst bodyParser = require('body-parser"
  }
]

About this extraction

This page contains the full source code of the opentok/one-to-one-sample-apps GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 80 files (234.8 KB), approximately 60.0k tokens, and a symbol index with 108 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!