ライブコマースシステム構築の「はまりどころ」と「対策」

#ライブコマースについて(動画ストリーミング技術について)
近年、ライブコマースの需要が高まってきています。リアルタイムなライブ感が生み出す販売促進効果が期待できるようです。
おもにインフルエンサーによる配信が人気のようですね。

##プログラマーが言われてそうな事
**「ライブコマースくらい１ヶ月で作れるんじゃないの！？」**

。。。

各種便利なライブラリ使ったとしても作れないと私は思います。。。
たぶん「モバイルもPCも対応してね」と言われそうですし。

そんな無茶振りをされた方に対して、この記事では最後に極力工数を削減できるSDK(agora.io)を紹介致します。
[サンプルコードも公開しています](https://github.com/fu-jimoto/AgoraIO-LiveCommerce-Sample)
2021/11/12追記
[サンプルコードを追加で公開しました](https://github.com/fu-jimoto/AgoraIO-LiveCommerce-Sample/tree/v4)
 
 - Signaling SDKをRTM SDKに変更
 - WebSDKを4系に変更

##一般的な画面構成
一般的（必要最低限）な画面構成は以下のイメージになるかと思います。
特に視聴者側はどこも同じような構成が多い印象です。個性があまり出ないですが、逆に使いやすいというメリットもあると思います。
###配信側
![配信側.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/20dfa1d5-239c-bab9-2479-a71012e41af2.png)

###視聴側
![視聴側(モバイル）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/9afd6aa3-ff4f-969b-537a-b13a75778ca1.png)



##機能毎の技術(数年前ではFlash、近年ではHLS)
###映像（動画）配信部分
アクターの映像や商品を視聴者に届ける部分です。
支える技術の歴史としては、**数年前はFlash、近年ではHLS**という歴史だと思います。

###チャット部分
インターネットの誕生から共に歩んできた機能です。
技術的な歴史は以下のような感じでしょうか。
**大昔：ひたすらHTTPリクエストを叩いて最新情報を取得(通称F5アタック)
少し昔：cometあたりでしょうか？？？
現在：WebSocketによるインタラクティブな実装**

###イイね(ハート)部分
ライブを盛り上げる機能だと思います。アクターへ盛り上がり具合を一番シンプルに伝えられると思います。
こちらも技術的にはチャットと同等になります。
（テキストメッセージの送受信という部分において）


##各技術での問題点（Flash/HLS）
###映像（動画）配信部分
Flash：2020年でサポート終了
HLS：遅延が大きい。配信映像データの送信部分プロトコルがRTMPというのが主流。
配信から視聴までという一気通貫なシステム構築の難易度が高い。

###チャット部分
F5アタック：令和時代にはありえないですね。
comet：あまり流行りませんでしたね。
WebSocket：同時接続数や秒間あたりの送受信数増加による負荷対策が必要になります。


###イイね(ハート)部分
チャット部分と同様。


##一般的な解決方法
###映像（動画）配信部分
遅延対策としてはWebRTCか専用SDKとなると思います。ですが、WebRTCにおいてはHLSで有効であったCDN機能（大規模配信向け）の対応が難しくなってきます。

###チャット部分
同時接続数や秒間あたりの送受信数増加による負荷対策は根本としてサーバーのスケールがあります。
アプリの立て付けで対策するのであれば、連続で送信させない等が考えられます。

###イイね(ハート)部分
チャット部分と同様。




##[本題]agora.ioでの解決方法
###映像（動画）配信部分
**２つの課題（低遅延・大規模配信）が簡単に解決できます。
又、映像音声部分についてサーバーを用意する必要はありません。**
(Webページ用サーバーの用意は必要です）

仮に配信側PC/視聴側PC＆モバイルという構成にします。
![Architecture - Content Management.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/d2f437c7-655b-f7a1-8d8a-b94b47f0fed9.png)

**配信側で必要な最低限のコード**

```javascript
function join() {
    client = AgoraRTC.createClient({mode: 'live', codec:'vp8'});
    client.init(appId, function () {
      client.join(channel_key, channelName, gUid, function(uid) {
          localStream = AgoraRTC.createStream({streamID: uid, audio: true, video: true, screen: false});
          localStream.setVideoProfile(videoProfile);
          localStream.init(function() {
            localStream.play('agora_local',{fit: 'cover'});
          }, function (err) {
          });        
      }, function(err) {
      });
    }, function (err) {
    });
}
```

```javascript
function publish(){
    client.publish(localStream, function (err) {
    });
}
```
実際にはカメラ・マイク選択等の実装もできますが、必要最低限のコードはこれだけです。


**視聴側で必要な最低限のコード**

```javascript
function join(){
    client = AgoraRTC.createClient({mode: 'live', codec:'vp8'});
    client.init(appId, function () {
        client.join(null, channelName, null, function(uid) {
        }, function(err) {
        });
    }, function (err) {
    });
    client.on('stream-added', function (evt) {
        var stream = evt.stream;
        client.subscribe(stream, function (err) {
        });
    });
    client.on('stream-subscribed', function (evt) {
        remoteStream = evt.stream;
    });
}
```

```javascript
function playStream(){
    remoteStream.play('agora_remote'+remoteStream.getId());
}
```

今回のコードの説明はWebRTC版でしたが、配信・視聴側ともにNativeでのアプリ作成も可能です。
NativeアプリとWebRTCアプリでの相互通信も可能です。


###チャット部分
映像部分と同様にagora SDKのSignalingSDKを利用すれば負荷問題の対策を考慮する必要はありません。
こちらも同様に仮で配信側PC/視聴側PC＆モバイルという構成にします。
![Architecture - Content Management(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/a86d731d-a1e9-4bdc-a1ef-e7450eee133c.png)
チャットは視聴者も送信する為、データの流れは送受信という形になります。

**必要な最低限のコード**

```javascript
var signal = Signal(appId);
var session, channel, call;

function loginToSignaling(){
    session = signal.login(sigHostAccount,"_no_need_token");
    session.onLoginSuccess = function(uid){
        channel = session.channelJoin(channelName);
        channel.onMessageChannelReceive = function(account, uid, msg){
            var data = JSON.parse(msg);
        }
    };
}
```

```javascript
function sendMessage(){
    channel.messageChannelSend(data, function(){});
}
```

実際に大量のメッセージを受け取ってしまうとそれだけで端末負荷があがる可能性もありますので、ServerSide Signaling SDKを中間にはさんで遅延させて配信する事も可能です。

###イイね(ハート)部分
チャット部分と同様。


##最後に
agora.ioではライブコマース分野において多くの実績があります。「短納期で高機能で安定性が高くて…etc」「複数の端末、ios,chrome、様々な形式にも対応してほしい・・」 な要求をうけていらっしゃいましたら一度ご検討ください。

[**agora.ioに関するお問い合わせはこちらから**](https://hubs.ly/H0kB1_n0)
[<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://hubs.ly/H0kB1_n0)