ボイスチャット/カラオケアプリ/音声SNSにおける音声配信(VoIP)技術について

##ボイスチャットアプリやカラオケバトルアプリで活用できる音声配信技術
スマホでオンラインゲームをやりながらバックグラウンドでボイチャしたり、オンライン上でカラオケのコラボやバトルをするサービスが増えてきています。利用シーンに合わせたSkypeのようなものです。
[agora.io](https://hubs.ly/H0kB1_n0)にはこのようなアプリの音声配信部分を簡単に実装できるVoiceSDKがあります。
スマホの音声技術や、利用シーンに合わせたagora.io SDKの利用方法を解説します。

##スマホの音声システムについて
スマホには２つの音声システムが存在します。

- 音声通話システム
 - 用途：音声通話またはビデオ通話時
 - 特徴：エコーキャンセリング付き、音量レベルは常に0より上(完全に無音にできない)
 - 品質：最大24KHz


- メディアシステム 
 - 用途：曲や動画の再生時、ゲームプレイ時
 - 特徴：音質優先、音量レベルは0に設定可能
 - 品質：最大48KHz

agora.ioではアプリの利用用途に対して上記の音声システムを切り替える事が可能です。
setAudioProfile APIを通じて6種類の異なるオーディオシナリオ (CHATROOM_ENTERTAINMENT, EDUCATION, GAME_STREAMING, SHOWROOM, CHATROOM_GAMING, DEFAULT) を提供します。
選択されたシナリオに応じて、各ユーザーが使用する音量/音質が決定されます。

- GAME_STREAMING シナリオでは、全ユーザーはメディア音量を使用します。
- EDUCATION、SHOWROOM、または DEFAULT シナリオでは、ライブモード時のオーディエンスはメディアシスレムを、ライブモード時のホスト、および、ビデオ通話モード時の全ユーザーは通話音量を使用します。
- CHATROOM_ENTERTAINMENT、および、CHATROOM_GAMING シナリオでは、全ユーザーは通話音量を使用します。

ボイスチャットアプリとゲーム/音楽アプリを同時に起動する場合は、音声システムが干渉する場合があります。その場合はボイスチャットアプリでGAME_STREAMINGを選択してメディアシステムを利用する事で解消される場合もあります。
又、iOS13ではバックグラウンドに移行すると音声通話システムが利用できなくなるようです。この場合もGAME_STREAMINGを利用して解消されます。

##Pixelシリーズについて
Googleが発表したPixelシリーズは、音声システムが独特で様々な[不具合が発生](https://www.valuewalk.com/2019/03/pixel-3-microphone-issue-call-quality/)しているようです。
アプリ側での実装やSDK側で対応できない問題が発生する場合もあります。
このようなケースではマイク付きイヤフォンの利用で解決する事が多いです。

##低帯域、パケットロス時の対応
格安SIMや、帯域制限がかかった月末、電波が弱いなど潤沢な回線でない場合での通話もあります。
agora.ioは低遅延の目的でUDPを採用していますが、UDPの弱点であるパケットロスに強い仕組みになっております。実際に50%のパケロスでも補正をかけることで快適な通話が実現できます。



##ボイスチェンジャーについて
匿名での配信や通話が要求されるアプリにはボイスチェンジャー機能が有効です。エンターテイメント性を求める場合にも有効です。
agora.ioでは[ボイスチェンジャーAPI](https://docs.agora.io/en/Voice/voice_changer_android?platform=Android)があります。
R&B風やカラオケ風にチューニングされたプリセットを選ぶパターンとピッチやDry/Wet設定など細かくチューニングするパターンがあります。

```java
// Sets the preset reverberation effect to pop music.
mRtcEngine.setLocalVoiceReverbPreset(AUDIO_REVERB_POPULAR);

// Turns off reverberation.
mRtcEngine.setLocalVoiceReverbPreset(AUDIO_REVERB_OFF);

```

```java
// Sets the pitch. The value ranges between 0.5 and 2.0. The lower the value, the lower the pitch. The default value is 1.0, which is the original pitch.
double pitch = 0.5;
rtcEngine.setLocalVoicePitch(pitch);

// Sets the local voice equalization.
// The first parameter sets the band frequency. The value ranges between 0 and 9. Each value represents the center frequency of the band: 31, 62, 125, 250, 500, 1k, 2k, 4k, 8k, and 16k Hz
// The second parameter sets the gain of each band. The value ranges between -15 and 15 dB. The default value is 0.
rtcEngine.setLocalVoiceEqualization(0, -15);
rtcEngine.setLocalVoiceEqualization(1, 3);
rtcEngine.setLocalVoiceEqualization(2, -9);
rtcEngine.setLocalVoiceEqualization(3, -8);
rtcEngine.setLocalVoiceEqualization(4, -6);
rtcEngine.setLocalVoiceEqualization(5, -4);
rtcEngine.setLocalVoiceEqualization(6, -3);
rtcEngine.setLocalVoiceEqualization(7, -2);
rtcEngine.setLocalVoiceEqualization(8, -1);
rtcEngine.setLocalVoiceEqualization(9, 1);

// The level of the dry signal in dB. The value ranges between -20 and 10.
rtcEngine.setLocalVoiceReverb(Constants.AUDIO_REVERB_DRY_LEVEL, 10);

// The level of the early reflection signal (wet signal) in dB. The value ranges between -20 and 10.
rtcEngine.setLocalVoiceReverb(Constants.AUDIO_REVERB_WET_LEVEL, 7);

// The room size of the reverberation. A larger room size means a stronger reverberation. The value ranges between 0 and 100.
rtcEngine.setLocalVoiceReverb(Constants.AUDIO_REVERB_ROOM_SIZE, 6);

// The length of the initial delay of the wet signal (ms). The value ranges between 0 and 200.
rtcEngine.setLocalVoiceReverb(Constants.AUDIO_REVERB_WET_DELAY, 124);

// The reverberation strength. The value ranges between 0 and 100. The higher the value, the stronger the reverberation.
rtcEngine.setLocalVoiceReverb(Constants.AUDIO_REVERB_STRENGTH, 78);

```

サンプルコードも[こちら](https://github.com/AgoraIO/Advanced-Audio/tree/master/iOS%26macOS/Agora-RTC-With-Voice-Changer-iOS)にあります。

##話者毎のボリューム、PANの設定
複数名参加の音声通話の場合、Aさんの音量を下げて、Bさんの音量を上げたいというようなニーズも出てきます。
デバイスや環境によって聞き手側で調整をする必要があります。又、Aさんの音は左耳、Bさんの音は右耳から聞こえるという設定も可能です。
こちらの[API](https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_rtc_engine.html#a7d851c2cabde18c2438c1ebe8bf763de)で実現可能です。




##WebRTCでの音声通話
WebRTCでのライブ配信、ビデオ通話ではカメラ映像の配信がスタンダードのように思えます。
ですが、音声だけの配信や視聴も可能です。ストリーム作成時にvideoをfalseとすることで音声のみでの配信が可能です。

```javascript
var stream = AgoraRTC.createStream({
  streamID: uid,
  audio:true,
  video:false,
  screen:false
});
```

2020/08/20追記
WebSDK3.1.2からChromeとFireFoxにおいてステレオ再生に対応しました。
Safariは現状ステレオでの再生に対応しておりません。


##音声コーデックとWebAssemblyの活用
WebSDK(WebRTC)での音声コーデックはOPUSになります。
agora.ioでの音声に対するエンコードはブラウザ側の実装になりますので、配信側で音声コーデックを選択する事はできません。（おそらく他のSDKやライブラリでも不可だと思います）
デコード（視聴側）ではWebAssemblyを活用してOPUS以外のコーデックを再生する事も可能です。
agora.ioではWebAssemblyに対応したSDKが[こちら](https://docs-preview.agoralab.co/en/Interactive%20Broadcast/web_in_app?platform=Web)に公開されています。
配信側がNativeアプリで、aacコーデックや独自コーデックで配信をし、視聴側はブラウザで視聴というケースが考えられます。


##ASMR（バイノーラルマイクロフォン・ヘッドセット）への対応
[ASMR対応のデバイス](https://www.amazon.co.jp/Roland-%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%B3%E3%83%89-%E3%83%90%E3%82%A4%E3%83%8E%E3%83%BC%E3%83%A9%E3%83%AB-%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%AD%E3%83%9B%E3%83%B3-CS-10EM/dp/B003QGPCTE)があります。
agora.io のSDKでは音声の生データにアクセスして加工する事ができます。この仕組みを用いて臨場感のある音声の配信をする事が可能になります。
サンプルは[こちら](https://github.com/AgoraIO/Advanced-Audio/tree/master/iOS%26macOS/Agora-RTC-With-ASMR)にあります。



##最後に
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=38e70004248fcd3c3dc4)
[<img width="912" alt="スクリーンショット 0001-08-15 13.41.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5d815376-9b89-08fa-9434-6fa7e8e67bcf.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=38e70004248fcd3c3dc4)