[webRTC for android vol1] android用のライブラリをビルド

やること

- webRTCをAndroid用にビルドして libwebrtc.aar (library的な?) を作る
- Android Studioに入れて使ってみる。ローカルのカメラを拾って表示。

ググるとちょいちょい情報はありますが、変更があったりするので、2017/04/13 現在のものを整理。

実際に繋げるのは次回
[webRTC for android vol2](http://qiita.com/nakadoribooks/items/d046fb68d59c7fffbc42)

## 成果物

https://github.com/nakadoribooks/webrtc-android/releases/tag/v0.0.1

<img src="https://j.gifs.com/k5xPXJ.gif" />

## 環境

- OS X El Capitan (version 10.11.6)
- AndroidStudio 2.3.1
- Nexus 5X Android6.0.1


## 参考

- [How to build webrtc library for Android in OSX hos](https://github.com/RestComm/restcomm-android-sdk/wiki/How-to-build-webrtc-library-for-Android-in-OSX-host)
- [Android | WebRTC ※オフィシャル](https://webrtc.org/native-code/android/)

# libwebrtc.aar を作る

## 基本的にこちら

[How to build webrtc library for Android in OSX host](https://github.com/RestComm/restcomm-android-sdk/wiki/How-to-build-webrtc-library-for-Android-in-OSX-host)

macではできないらしい。ので、Vagrant で Ubuntu 環境入れてそこで作る

## やってみる

僕の環境ではそのままやるとエラーが出たので、調整が必要です

### Vagrant の設定を作ってVagrantに入る

参考サイトのようにVagrantfile を作る

``` :Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure(2) do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://atlas.hashicorp.com/search.
  config.vm.box = "hashicorp/precise64"

  config.ssh.forward_agent = TRUE

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 4096
    vb.cpus = 2
  end

  config.vm.network "private_network", ip: "192.168.50.5"
  config.vm.synced_folder ".", "/vagrant", type: :nfs

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
   config.vm.provision "shell", inline: <<-SHELL
     sudo apt-get update
     sudo apt-get -y install wget git gnupg flex bison gperf build-essential zip curl subversion pkg-config libglib2.0-dev libgtk2.0-dev libxtst-dev libxss-dev libpci-dev libdbus-1-dev libgconf2-dev libgnome-keyring-dev libnss3-dev
     # Download the latest script to install the android dependencies for ubuntu
     curl -o install-build-deps-android.sh https://src.chromium.org/svn/trunk/src/build/install-build-deps-android.sh
     # Use bash (not dash which is default) to run the script
     sudo /bin/bash ./install-build-deps-android.sh
     # Delete the file we just downloaded... not needed anymore
     rm install-build-deps-android.sh
   SHELL
end
```
up する

```
vagrant up
```

>Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'hashicorp/precise64'...
- 略 -
==> default:     250      0 --:--:-- --:--:-- --:--:--   460
==> default: ./install-build-deps-android.sh: line 1: syntax error near unexpected token `newline'
==> default: ./install-build-deps-android.sh: line 1: `<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">'

*https://src.chromium.org/svn/trunk/src/build/install-build-deps-android.sh*
が存在しないので、エラーが出ますがそのままいきます。

```
vagrant ssh
```

### depot_tools

Googleの開発ツール的なやつ

```
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
```

```
export PATH=`pwd`/depot_tools:"$PATH"
```

### ソースコードのダウンロード

フォルダ作って移動

```
mkdir webrtc-checkout
cd webrtc-checkout
```

```
fetch --nohooks webrtc_android
```

> Running: gclient root
- 略 (※けっこう時間かかる) -
Running: git config diff.ignoreSubmodules all

```
gclient sync
```

> ________ running '/usr/bin/python src/cleanup_links.py' in '/home/vagrant/webrtc-checkout'
 略 
Do you accept the license for version 10.2.0 of the Google Play services client library? [y/n]
5＞ Downloading src/resources/audio_processing/agc/agc_no_circular_buffer.dat...
Hook 'download_from_google_storage --directory --recursive --num_threads=10 --no_auth --quiet --bucket chromium-webrtc-resources src/resources' took 598.61 secs


コミットを確認してみる

```
cd src/
git log
```

> commit 64349c7e08c7ccf7acd298393fd2662cf7b25139
Author: buildbot <buildbot@webrtc.org>
Date:   Sat Apr 15 18:08:59 2017 -0700

ブランチ見る

```
git branch
```
>＊ (no branch)
  master

とりあえずブランチ切る

```
git checkout -b nakadoribooks-build
```

```
git status
```
> Not currently on any branch.
 Untracked files:
   (use "git add <file>..." to include in what will be committed)
	resources/ConferenceMotion_1280_720_50.yuv

とりあえずコミットしとく

```
git add -A
git commit -m “develop”
```

もどって

```
cd ../
```

再度 'glient sync'

```
src/build/android/play_services/update.py download
gclient sync 
```

> ________ running '/usr/bin/python src/cleanup_links.py' in '/home/vagrant/webrtc-checkout'
Syncing projects: 100% (42/42), done.     
- 略 -
________ running 'download_from_google_storage --directory --recursive --num_threads=10 --no_auth --quiet --bucket chromium-webrtc-resources src/resources' in '/home/vagrant/webrtc-checkout'

```
cd src
```

### ビルド

いけーーー

```
tools-webrtc/android/build_aar.py
```

> INFO:root:Building: armeabi-v7a
/home/vagrant/webrtc-checkout/src/buildtools/linux64/gn: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.18' not found (required by /home/vagrant/webrtc-checkout/src/buildtools/linux64/gn)


あかん、*GLIBCXX_3.4.18 not found*

### GLIBCXX_ 問題

```
sudo strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
```
> GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_DEBUG_MESSAGE_LENGTH

16までしかない。
ググってみると
https://askubuntu.com/questions/575505/glibcxx-3-4-20-not-found-how-to-fix-this-error


```
sudo apt-get install libstdc++6
```

> Reading package lists... Done
Building dependency tree      
- 略 -
gpg:               imported: 1  (RSA: 1)
OK


```
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
```
> Ign http://us.archive.ubuntu.com precise InRelease
- 略 -
Reading package lists... Done


```
sudo apt-get upgrade
```

> Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages have been kept back:
  cpp-4.6 g++-4.6 gcc-4.6 gcc-4.6-base libgcc1 libgomp1 libquadmath0 libstdc++6 libstdc++6-4.6-dev
0 upgraded, 0 newly installed, 0 to remove and 9 not upgraded.

```
sudo apt-get dist-upgrade
```

> Reading package lists... Done
Building dependency tree       

 略 
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place

```
sudo strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
```

> GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_DEBUG_MESSAGE_LENGTH

入った！

再度。

```
tools-webrtc/android/build_aar.py
```

> — 略 -
third_party/android_tools/sdk/tools/lint: line 68: exec: java: not found
— 略 -

### java 問題

```
sudo apt-get uninstall openjdk-7-jdk
java -version
```

> java version "1.6.0_41"


```
sudo update-alternatives --config java 
```

>  0            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      auto mode
  1            /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java   1061      manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1051      manual mode
Press enter to keep the current choice[※], or type selection number: 2




```
java -version
```

> java version "1.7.0_121"
OpenJDK Runtime Environment (IcedTea 2.6.8) (7u121-2.6.8-1ubuntu0.12.04.3)
OpenJDK 64-Bit Server VM (build 24.121-b00, mixed mode)

入った。

### これでいけるはず！

再度

```
tools-webrtc/android/build_aar.py
```

> INFO:root:Building: armeabi-v7a
Done. Made 2757 targets from 172 files in 2925ms
ninja: Entering directory /tmp/tmp06LS69/armeabi-v7a
- 略 - 
[2228/2228] SOLINK ./libjingle_peerconnection_so.so
— 略 —
INFO:root:Building: arm64-v8a
Done. Made 2751 targets from 172 files in 2456ms
ninja: Entering directory /tmp/tmp06LS69/arm64-v8a
— 略 -
[2150/2150] SOLINK ./libjingle_peerconnection_so.so
— 略 -
INFO:root:Building: x86
Done. Made 2779 targets from 173 files in 2858ms
ninja: Entering directory /tmp/tmp06LS69/x86
— 略 -
[2379/2379] SOLINK ./libjingle_peerconnection_so.so
— 略 -
INFO:root:Building: x86_64
Done. Made 2779 targets from 173 files in 2517ms
ninja: Entering directory /tmp/tmp06LS69/x86_64
— 略 -
[2374/2374] SOLINK ./libjingle_peerconnection_so.so
INFO:root:Collecting common files.
INFO:root:Collecting: armeabi-v7a
INFO:root:Collecting: arm64-v8a
INFO:root:Collecting: x86
INFO:root:Collecting: x86_64

できた！

```
ls -l
```

>  ーrw-rw-r--   1 vagrant vagrant  29M Apr 16 06:53 libwebrtc.aar

macと共有してるフォルダにコピー

```
cp libwebrtc.aar /vagrant/
```

vagrant から出て確認。

```
exit
ls -hl
```

> 29M  4 16 15:56 libwebrtc.aar


# AndroidStudio に libwebrtc.aar を入れる

参考
[AppRTCDemo](https://github.com/njovy/AppRTCDemo)

- libsフォルダに libwebrtc.aar をコピー
- build.gradle (Module:app) に追記

## libsフォルダに libwebrtc.aar をコピー

![スクリーンショット 2017-04-14 23.55.35.png](https://qiita-image-store.s3.amazonaws.com/0/159266/dd06af19-ec17-0249-0b33-ea0baa2aa93b.png)

ここね

## build.gradle (Module:app) に追記

```gradle:build.gradle
// 略

dependencies {
    // 略
    compile(name:'libwebrtc', ext:'aar')
    // 略
}

repositories{
    flatDir{
        dirs 'libs'
    }
}

// 略

```

# 使ってみる

## 実装

アプリケーション

```java:MainActivity.java
package com.nakadoribooks.webrtcexample;

import android.Manifest;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_CAMERA_PERMISSION = 1;
    private WebRTC webRTC;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // checkPermission → onRequestPermissionsResult → setupWebRTC
        checkPermission();
    }

    private void checkPermission(){
        String[] permissioins = new String[]{ Manifest.permission.CAMERA};
        ActivityCompat.requestPermissions(this, permissioins, REQUEST_CODE_CAMERA_PERMISSION);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {

        if (requestCode != REQUEST_CODE_CAMERA_PERMISSION)
            return;

        webRTC = new WebRTC(this);
        webRTC.startCapture();
    }

}
```

WebRTC

```java:WebRTC.java
package com.nakadoribooks.webrtcexample;

import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.EglBase;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoRenderer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

/**
 * Created by kawase on 2017/04/13.
 */

public class WebRTC {

    private PeerConnectionFactory factory;
    private VideoCapturer videoCapturer;
    private EglBase.Context renderEGLContext;
    private Activity activity;

    WebRTC(Activity activity){
        this.activity = activity;

        // rendereContext
        EglBase eglBase = EglBase.create();
        renderEGLContext = eglBase.getEglBaseContext();

        // initialize Factory
        PeerConnectionFactory.initializeAndroidGlobals(activity.getApplicationContext(), true);
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        factory = new PeerConnectionFactory(options);
        factory.setVideoHwAccelerationOptions(renderEGLContext, renderEGLContext);

        // setupLocalStream
        setupLocalStream();
    }

    // interface -----------------

    public void startCapture(){
        _startCapture();
    }

    // implements -------------

    private void setupLocalStream() {

        SurfaceViewRenderer localRenderer = setupRenderer();

        MediaStream localStream = factory.createLocalMediaStream("android_local_stream");
        videoCapturer = createCameraCapturer(new Camera2Enumerator(activity));
        VideoSource localVideoSource = factory.createVideoSource(videoCapturer);

        VideoTrack localVideoTrack = factory.createVideoTrack("android_local_videotrack", localVideoSource);
        localStream.addTrack(localVideoTrack);

        VideoRenderer videoRender = new VideoRenderer(localRenderer);
        localVideoTrack.addRenderer(videoRender);
    }


    private void _startCapture(){
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager =
                (WindowManager) activity.getApplication().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
        int videoWidth = displayMetrics.widthPixels;
        int videoHeight = displayMetrics.heightPixels;

        videoCapturer.startCapture(videoWidth, videoHeight, 30);
    }

    private SurfaceViewRenderer setupRenderer(){
        SurfaceViewRenderer localRenderer = (SurfaceViewRenderer) activity.findViewById(R.id.local_render_view);
        localRenderer.init(renderEGLContext, null);
        localRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        localRenderer.setZOrderMediaOverlay(true);
        localRenderer.setEnableHardwareScaler(true);

        return localRenderer;
    }

    private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
        return createBackCameraCapturer(enumerator);
    }

    private VideoCapturer createBackCameraCapturer(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();

        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }

}
```

## 設定 / レイアウト

gradle

```gradle:build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.nakadoribooks.webrtcexample"
        minSdkVersion 21
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions {
        exclude 'META-INF/io.netty.versions.properties'
        exclude 'META-INF/INDEX.LIST'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile(name:'libwebrtc', ext:'aar')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    compile 'io.reactivex:rxandroid:0.24.0'
}

repositories{
    flatDir{
        dirs 'libs'
    }
}
```

Layout

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context="com.nakadoribooks.webrtcexample.MainActivity">

    <org.webrtc.SurfaceViewRenderer
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/local_render_view"
        />

</android.support.constraint.ConstraintLayout>
```

以上。