LoginSignup
66
75

More than 5 years have passed since last update.

AndroidでWebRTCを使った電話アプリを実装する【初心者向け】

Last updated at Posted at 2017-07-03

AndroidでWebRTCを使った電話アプリの実装方法を解説します。
WebRTCは、リアルタイムでビデオチャットやボイスチャット、テキストなどのデータ送信ができるものです。

今回は、ボイスチャットを実装していきます。ビデオは取り扱いません。

WebRTCを1から実装しようとすると大変なので、今回は、SkyWayというサービスとそのSDKを利用します。
このSDKを使うと、AndroidのみならずiOSやweb(javascript)でWebRTCを簡単に利用するアプリを作ることができます。

また、初心者向けを意識しているので、外部ライブラリは、SkyWaySDK以外は導入せずに実装していきます。
「動いた、すげぇ」を重視しているので、エラーハンドリングやonPauseなどのライフサイクルでの適切な処理は省いています。

実装したソースコードは、こちらにあります。

はじめに

念のため今回開発を行った環境を。

  • macOS : 10.11.6 (El Capitan)
  • Android Studio : 2.3.3
  • 使ったエミュレータ : API24

多少違っても問題ないです。

1. アプリのひな形を作る

わかってる人は次の下準備まで飛ばしてください。

  1. Start a new Android Studio project をクリック

Welcome_to_Android_Studio_と_1__bash.png
2. アプリ名と、ドメイン(それぞれ適当でいいです)を入力してNext

Create_New_Project_と_Welcome_to_Android_Studio.png
3. MinimumSDKは適当に決めてNext(今回は、API version19にしてみました)

Create_New_Project_と_Welcome_to_Android_Studio.png
4. [Empty Activity]が選択されていることを確認して、Next

Create_New_Project.png
5. Activity Name はデフォルトのMainActivityのままで、Finish

Create_New_Project_と_Welcome_to_Android_Studio.png

これで、プロジェクトが作成されます。

2. 下準備(SkyWayの導入)

  1. まず、プロジェクト一覧画面を変更します。画像の矢印のボタンをクリックして、「Project」をクリックしてください。

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_AndroidでWebRTCを使った電話アプリを実装する【初心者向け】.png
2. デフォルトの「Android」のナビゲーション画面はわかりにくいので、以降「Project」のナビゲーション画面を使います。これは、実際のファイル・フォルダ構造と同じように表示されるのでわかりやすいです。画像のターゲットアイコンを押すと、右側のエディタで開いているファイルの場所を表示してくれます。

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_AndroidでWebRTCを使った電話アプリを実装する【初心者向け】_と_1__bash.png
3. SkyWayのAndroidのSDKをダウンロードし(Source code (zip)をクリック)、解凍して、SkyWay.aarをプロジェクトのapp/libsディレクトリにコピーしてください。

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_SkyWay-Android-SDK-0_2_2.png
4. SkyWay.aarをプロジェクトに取り込むために、app/build.gradleを編集します。追記が終わったらSync Nowを押してください。aarファイルが読み込まれます。

app/build.gradle
dependencies {
    compile(name: 'SkyWay', ext: 'aar') // <- この行
    compile fileTree(dir: 'libs', include: ['*.jar'])
    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'
}
// この下の行も
repositories {
    flatDir {
        dirs 'libs'
    }
}

app_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_Import_SkyWay_aar_·_kawasin73_webrtc_sample_android_8318afb.png
5. 次に、SkyWayに会員登録してください。利用するドメインは、ひとまずは、localhostとしてください。
6. この後表示される「APIキー」と「利用可能ドメイン」はこの後利用するので注意しておいてください
7. appディレクトリを右クリックして、「New」->「File」で、gradle.propertiesファイルを作成して、先ほど表示された、「APIキー」と「利用可能なドメイン」を入力してください。

app/gradle.properties
skywayApiKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
skywayHost=localhost

gradle_properties_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_Add_API_KEY_·_kawasin73_webrtc_sample_android_6fac224_と_1__bash.png
8. app/.gitignoregradle.propertiesを追記してください。これにより、ソースコードをgithubに公開した時に、app/gradle.propertiesは公開されないため、APIキーを他者に知られずにソースコードを公開できます。

_gitignore_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_AndroidでWebRTCを使った電話アプリを実装する【初心者向け】_と_Add_API_KEY_·_kawasin73_webrtc_sample_android_6fac224_と_1__bash.png
9. app/build.gradleに以下の追記をします。これにより、javaのコードから、BuildConfig. SKYWAY_API_KEYBuildConfig. SKYWAY_HOSTでアクセスできるようになります。追記が終わったら、Sync Now を押してください。

app/build.gradle
    buildTypes {
        debug {
            buildConfigField "String", "SKYWAY_API_KEY", "\"${project.property("skywayApiKey")}\""
            buildConfigField "String", "SKYWAY_HOST", "\"${project.property("skywayHost")}\""
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField "String", "SKYWAY_API_KEY", "\"${project.property("skywayApiKey")}\""
            buildConfigField "String", "SKYWAY_HOST", "\"${project.property("skywayHost")}\""
        }
    }

AndroidでWebRTCを使った電話アプリを実装する【初心者向け】_と_app_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_app_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample_.png
10. AndroidManifest.xmlを編集します。これは、Androidアプリが実行されるときに必要な権限を宣言するものです。

app/src/main/AndroidManifest.xml
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

AndroidManifest_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_1__bash.png
11. 以上でSkyWayを使うための下準備は完了です。

3. 自分のpeerIDを表示する

まず、自分のPeerIdを表示する部分の実装を進めていきます。SkyWayによって自動で割り当てられるPeerIdを確認することができるようになります。

ここでは、

  • Peer クラスインスタンスの作成
  • Logでログを出す
  • TextViewに動的に値をセットする

を行っていきます。

  1. まず、Peerクラスのインスタンスを作成します。これが作成されることで通信ができるようになります。以下のコードを入力してください。「Select Classes to Import」が出てきたらOKを押してください。
MainActivity.java
// MainActivityのすぐ下
private Peer peer;

// onCreate の中
PeerOption options = new PeerOption();
options.key = BuildConfig.SKYWAY_API_KEY;
options.domain = BuildConfig.SKYWAY_HOST;
peer = new Peer(this, options);
Navigator.initialize(peer);

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

Select_Classes_to_Import_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample_.png
2. 次に、自分のPeerIdを取得して、Logに出力してみましょう。

MainActivity.java
// MainActivityの下
private String TAG = getClass().getSimpleName();
private String currentId;

// onCreateの中
showCurrentPeerId();

// onCreateの下
    private void showCurrentPeerId() {
        peer.on(Peer.PeerEventEnum.OPEN, new OnCallback() {
            @Override
            public void onCallback(Object o) {
                if (o instanceof String) {
                    currentId = (String) o;
                    Log.d(TAG, "currentId: " + currentId);
                }
            }
        });
    }

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png
3. この状態で実際にアプリを起動してみましょう。画面上部の緑色の三角ボタンが実行ボタンです。動かす機体を選んで実行しましょう。ソースコードのコンパイルやアプリのインストールに時間がかかりますが、画面下に実行状況が表示されるので待ちましょう。

Select_Deployment_Target_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_AndroidでWebRTCを使った電話アプリを実装する【初心者向け】_と_MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample_.png
4. 起動されたら、ログを確認しましょう。画面下の「Android Monitor」をクリックするとログ画面が開きます。開かない場合は、「logcat」を選択するとログが流れてきます。すると、確かに、ログで自分の、PeerIdが表示されているのが確認できます。

MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample__と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_AndroidでWebRTCを使った電話アプリを実装する【初心者向け】.png
5. 次に、TextViewをjavaから操作するために、TextViewにidをつけます。idの追加などは、GUI画面で設定もできますが、今後のことを考えて、CUI画面で設定していきます。画面下のTextタブをクリックすると、CUI画面に切り替えることができます。Hello World!とあるデフォルトのTextViewにidを追記してください。

activity_main.xml
android:id="@+id/id_textview"

MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample__と_activity_main_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_LoginActivity_java_-_collegino_android_-____AndroidStudioProjects_collegino_an.png
6. 次に、MainActivityから、PeerIdを表示します。ここまで出来たらもう一度アプリを実行してみてください。Idが表示されているはずです。

MainActivity.java
// MainActivity の下に
private TextView idTextView;

// onCreate の中に
idTextView = (TextView) findViewById(R.id.id_textview);

// showCurrentPeerId の中に
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        idTextView.setText("ID: " + currentId);
    }
});

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

4. 通話できるユーザーの一覧を表示する

通話が出来るユーザーの一覧を表示していきます。
ここでは、

  • ListViewでの表示

を行っていきます。

  1. まず、ListViewのダミーデータを画面に表示するところから始めていきます。activity_main.xmlLinearLayoutListViewを追加し、TextViewを、LinearLayoutの中に移動させます。
activity_main.xml
    <LinearLayout
        android:id="@+id/head_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/id_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />
    </LinearLayout>

    <ListView
        android:id="@+id/listview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@+id/head_layout"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

activity_main_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png
2. 次に、ListViewの中の1行1行のViewを作成します。app/src/res/layoutの中に、Layout resource fileとしてlist_item.xmlを作成してください。rootは、LinearLayoutで大丈夫です。そして、TextViewを作成してください。

list_item.xml
    <TextView
        android:id="@+id/item_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"/>

list_item_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png
3. 次に、MainActivityにListViewのロジックを作成していきます。以下を追記して、実行するとListViewが表示されていると思います。書く順番としては、内部クラスであるMyAdapterを最初に書くとエラーが出ずにスムースに書けます。

MainActivity.java
// MainActivity の最終行の一つ上に
    private class MyAdapter extends ArrayAdapter<String> {
        private LayoutInflater inflater;

        MyAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<String> objects) {
            super(context, resource, objects);
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            View view = inflater.inflate(R.layout.list_item, null, false);
            TextView textView = (TextView) view.findViewById(R.id.item_textview);
            String name = getItem(position);
            textView.setText(name);
            return view;
        }
    }

// MainActivityの下に
    private ListView listView;
    private MyAdapter adapter;
    private List<String> idList = new ArrayList<String>();

// onCreateの中に
        listView = (ListView) findViewById(R.id.listview);

        adapter = new MyAdapter(this, 0, idList);
        listView.setAdapter(adapter);

        idList.clear();
        idList.add("Hello1");
        idList.add("Hello2");
        idList.add("Hello3");
        idList.add("Hello4");
        adapter.notifyDataSetChanged();

MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample_.png

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png
4. 最後にダミーデータの代わりに、peerIdを表示させます。実行してみると、自分のidだけがListViewに表示されます。もし、複数端末で同時に起動すると複数のidが表示されます。

MainActivity.java
// onCreate内の以下を削除
        idList.clear();
        idList.add("Hello1");
        idList.add("Hello2");
        idList.add("Hello3");
        idList.add("Hello4");
        adapter.notifyDataSetChanged();

// showCurrentPeerId の下に追記
    private void refreshPeerList() {
        Log.d(TAG, "Refreshing");
        peer.listAllPeers(new OnCallback() {
            @Override
            public void onCallback(Object o) {
                if (o instanceof JSONArray) {
                    JSONArray array = (JSONArray) o;
                    idList.clear();
                    for (int i = 0; i < array.length(); i++) {
                        try {
                            String id = array.getString(i);
                            idList.add(id);
                            Log.d(TAG, "Fetched PeerId: " + id);
                        } catch (JSONException e) {
                            Log.e(TAG, "Parse ListAllPeer", e);
                        }
                    }
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            adapter.notifyDataSetChanged();
                        }
                    });
                }
            }
        });
    }

// onCreateに追記
refreshPeerList();

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png
5. 最後に「refresh」ボタンを押すとListViewが更新されるように変更します。activity_main.xmlMainActivity.javaにそれぞれ追記します。

activity_main.xml
        <Button
            android:id="@+id/refresh_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Refresh" />
MainActivity.java
// onCreateの中に追記
        Button refreshBtn = (Button) findViewById(R.id.refresh_btn);
        refreshBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                refreshPeerList();
            }
        });

activity_main_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

5. 通話のための権限を揃える

Androidで使う一部の機能はアプリを利用するユーザーから権限を認められないと利用することができません。

AndroidManifest.xmlに記載することで権限は利用できるようになるのですが、一部の機能は、Dangerous Permissionsとして、AndroidManifest.xmlに記載した上でさらに利用するときにダイアログを出して許可してもらう必要があります。

今回のアプリでは、RECORD_AUDIODangerous Permissionsに指定されているので、アプリを起動したときに、権限を要求するダイアログを出す処理を記述します。

なお、Dangerous Permissionsの概念は、Android6.0(API23)以降に導入されたもので、それ以前のAndroid端末を対象とする場合は不要です。

これらのコードは、実行時のパーミッション リクエストを参考に作成しました。コメントは必要ないので入力する必要はありません。

MainActivity.java
// MainActivity の下に
private static final int RECORD_AUDIO_REQUEST_ID = 1;

// onCreate の下に

    private void checkAudioPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Manifest.permission.RECORD_AUDIO is not GRANTED");
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.RECORD_AUDIO)) {
                Log.d(TAG, "shouldShowRequestPermissionRationale = false");
                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.
            } else {
                // No explanation needed, we can request the permission.
                Log.d(TAG, "request Permission RECORD_AUDIO");
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.RECORD_AUDIO},
                        RECORD_AUDIO_REQUEST_ID);
                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case RECORD_AUDIO_REQUEST_ID: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "request Permission RECORD_AUDIO GRANTED!");
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                } else {
                    Log.d(TAG, "request Permission RECORD_AUDIO DENIED!");
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }
            // other 'case' lines to check for other
            // permissions this app might request
        }
    }

// onCreate の中に
checkAudioPermission();

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

これらのコードを書いた上で、実行すると以下のようなダイアログが表示されます。許可を押してください。

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

また、本来であれば、許可されなかった時に、許可を再申請する処理などのエラー処理が必要になります。
今回はサンプルアプリなのでその辺りの細かいエラー処理は省いて実装しています。

6. 通話(発信)を実装する

ここから、peerを使った発信の処理を行っていきます。
ListViewでクリックされたPeerIdに対して発信をする処理を書きます。

まずは、ListViewのクリックを検知する処理を書きます。
Logを確認すると、クリックが検出できていることがわかります。

MainActivity.java
// onCreate の中に
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                String selectedPeerId = idList.get(i);
                if (selectedPeerId == null) {
                    Log.d(TAG, "Selected PeerId == null");
                    return;
                }
                Log.d(TAG, "SelectedPeerId: " + selectedPeerId);
            }
        });

Android_Emulator_-_Nexus_5X_API_24_5554_と_MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample__と_MainActivity_java_-_WebRTCSample_-____AndroidStudioProjects_WebRTCSample_.png

次に、実際に発信する処理を実装します。getMediaStreamの中で、audioFlagのみをtrueにしているので、ボイスチャットのみの利用に制限することができます。

MainActivit.java
// MainActivity の下に
private MediaConnection connection;

// refreshPeerList の下に
    private void call(String peerId) {
        Log.d(TAG, "Calling to id:" + peerId);
        if (peer == null) {
            Log.i(TAG, "Call but peer is null");
            return;
        }

        if (peer.isDestroyed || peer.isDisconnected) {
            Log.i(TAG, "Call but peer is not active");
            return;
        }

        if (connection != null) {
            Log.d(TAG, "Call but connection is already created");
            return;
        }

        MediaStream stream = getMediaStream();

        if (stream == null) {
            Log.d(TAG, "Call but media stream is null");
            return;
        }
        CallOption option = new CallOption();
        option.metadata = "test"; // TODO: metadata
        MediaConnection connection = peer.call(peerId, stream, option);

        if (connection == null) {
            Log.d(TAG, "Call but MediaConnection is null");
            return;
        }

        this.connection = connection;
        Log.d(TAG, "connection started!");
    }

    private MediaStream getMediaStream() {
        MediaConstraints constraints = new MediaConstraints();
        constraints.videoFlag = false;
        constraints.audioFlag = true;
        return Navigator.getUserMedia(constraints);
    }

// OnItemClickListener の中に
call(selectedPeerId);

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

ここまでで、発信をすることができるようになりました。

7. 終了処理を実装する

次に、発信した通話を切る処理を実装します。Buttonを追加し、クリックされたら、connectionclose()します。

activity_main.xml
        <Button
            android:id="@+id/close_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="CLOSE"/>
MainActivity.java
// getMediaStream の下に
    private void closeConnection() {
        if (connection != null) {
            connection.close();
            MainActivity.this.connection = null;
            Log.d(TAG, "Connection is Closed");
        }
    }

// onCreate の中に
        Button closeBtn = (Button) findViewById(R.id.close_btn);
        closeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                closeConnection();
            }
        });

FollowersActivity_java_-_collegino_android_-____AndroidStudioProjects_collegino_android__と_activity_main_xml_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

これで、こちらから通話を切ることができるようになりました。しかし、相手から通話が切られた時に、こちらのconnectionはつなぎっぱなしになってしまい、次の相手に発信することができません。
connectionが切れた時には、CLOSEイベントが発生するので、それを探知して、connectionclose()する処理を実装します。

MainActivity.java
// closeConnection の上に
    private void setConnectionCallback(MediaConnection connection) {
        connection.on(MediaConnection.MediaEventEnum.CLOSE, new OnCallback() {
            @Override
            public void onCallback(Object o) {
                Log.d(TAG, "Close Event is Received");
                closeConnection();
            }
        });
    }

// call の中に
setConnectionCallback(connection);

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

最後に、アプリが終了した時にも、通話を終了しPeerを終了しなくてはなりません。

MainActivity.java
// onCreate の下に
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (connection != null) {
            closeConnection();
        }
        if (peer != null && !peer.isDestroyed) {
            peer.destroy();
            peer = null;
        }
    }

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

8. 通話(着信)を実装する

ここまでで、発信については実装が完了しました。
次に、着信の時の処理を実装していきます。

着信があった時、peerインスタンスにCALLイベントが発生します。そのイベントをキャッチして、通話を開始します。

MainActivity.java
        peer.on(Peer.PeerEventEnum.CALL, new OnCallback() {
            @Override
            public void onCallback(Object o) {
                Log.d(TAG, "CALL Event is Received");
                if (o instanceof MediaConnection) {
                    MediaConnection connection = (MediaConnection) o;

                    if (MainActivity.this.connection != null) {
                        Log.d(TAG, "connection is already created");
                        connection.close();
                        return;
                    }

                    // TODO: show dialog

                    MediaStream stream = MainActivity.this.getMediaStream();

                    connection.answer(stream);

                    setConnectionCallback(connection);

                    MainActivity.this.connection = connection;
                    Log.d(TAG, "CALL Event is Received and Set");
                }
            }
        });

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

これで、着信を処理することができるようになりました。

9. エラーを抑える

実際に通話をしてログを見てみると以下のような、warningが出ていることに気づきました。

W/AudioDeviceTemplate: The application should use MODE_IN_COMMUNICATION audio mode!

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

これを解消するために、以下のコードを付け加えます。

MainActivity.java
// onCreate の中に
        Context context = getApplicationContext();
        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        am.setMode(AudioManager.MODE_IN_COMMUNICATION);

MainActivity_java_-_WebRTCPhoneSample_-____AndroidStudioProjects_WebRTCPhoneSample_.png

これで、解消されます。

最後に

TODO: 着信のダイアログを出したい

66
75
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
66
75