はじめに
MixChannelは、おもに若者世代から人気を集めているライブ配信&動画投稿コミュニティアプリです。利用者は累計1,000万ユーザーを超え、運営も6年目を迎える大きな規模のサービスとなっています。
MixChannelの主要機能の1つに、ライブ配信機能があります。これは誰でも簡単にライブ配信を行える機能であるのと同時に、その「誰でも」や「簡単に」の実現にあたって多くのトライアンドエラーを経験してきた機能でもあります。連載の第3回であり、最終回のとなる今回は前後編2回に分けて、Android版MixChannelのライブ配信機能に焦点を当て、その裏側にある技術やノウハウを紹介します。
ライブ配信とは
実装の説明に入る前に、ライブ配信について簡単に説明します。ライブ配信とは、2種類の登場人物から構成される多対一型のコミュニケーションです。1人目の登場人物は映像をブロードキャストする人(以下、配信者と呼びます)で、もう1人はそれを受信する人(以下、視聴者と呼びます)です。配信者は声や仕草で、対する視聴者はテキスト形式のコメントで、それぞれ発話を行うことで、ライブ配信コミュニケーションは進行します(図1 ) 。
図1 配信者と視聴者によるライブ配信コミュニケーション
ライブ配信コミュニケーションの最大の特徴は、時間あたりの密度の高さにあります。配信者の何気ない一言がスマホを通して瞬時に全視聴者に届けられ、数秒後には数十ものコメントとなって返ってくることはまれなケースではありません。MixChannelにおけるライブ配信機能とは、このような楽しさをスマホを1台用意するだけで味わえる機能と言えるでしょう。言い換えれば、その開発者である私たちには、スマホという限られたリソースの上でライブ配信機能を動作させ、快適な機能体験をユーザーに提供するという課題があります。
ライブ配信機能の実装
Android版MixChannelのライブ配信機能は、大きく次の3つの機構から構成されています。
カメラ入力から映像データを作成する機構
マイク入力とカラオケ音源から音声データを作成する機構
映像データと音声データをサーバに送信する機構
これらの機構の関係性は図2 のとおりです。4つの入力があって、それぞれが変換を施されたあと、端末へ、あるいはサーバへ出力されていることがわかります。各機構を詳しく説明していきます。
図2 Android版MixChannelのライブ配信機能を構成する機構
映像データの作成について
映像データの作成処理はカメラデバイスから入力を受け取る過程から始まります。カメラ入力の受け取りにはandroid.hardware.Camera APIを利用します。受け取りサイズやFPSの設定などを行ったあと、APIからテクスチャを受け取り、次の過程へと渡します。このAPIには任意のFPS値を設定できるようになっていない(正確には与えても効果がない)ため、APIを通して「利用可能なFPS値の範囲」を取得して、その中から一番大きいFPS値を設定するようにしています。また、一部のカメラデバイスは手ぶれ補正機能やオートフォーカス機能を提供しているので、その設定もここで行います。
カメラから入力されたテクスチャは次に、加工処理へと渡されます。この過程では顔認識や美肌エフェクトの生成、コントラストの調整などを行い、次の過程へと渡します。詳細な説明は割愛しますが、技術に関してのみ少し紹介すると、顔認識にはFirebase ML Kit を利用しており、エフェクトの生成に関してはOpenGL ESと独自のアルゴリズムを組み合わせて利用しています。
加工処理を経たテクスチャはここでいったん分岐します。次の過程で行うエンコード処理はおもに通信のための処理なので、この処理をスキップし、なるべく速くスクリーンに表示するためです。よって、分岐したテクスチャは一方は端末のスクリーンへ渡され、もう一方はエンコードの処理へと渡されます。テクスチャをスクリーンに表示するインタフェースとしてはandroid.view.SurfaceViewとandroid.view.TextureViewの2つがありますが、MixChannelではよりシンプルなSurfaceViewを用いて表示を行っています。
エンコード処理の過程へと渡ったテクスチャは最後にH.264形式へのエンコードを施されたあと、RTMP(Real Time Messaging Protocol )サーバへと送信されます。エンコードにはMediaCodec を利用し、また、RTMPサーバへの送信にはant-media/LibRtmp-Client-for-Android を利用しています。このライブラリはossrs/librtmp をAndroid NDK(Native Development Kit )を通して扱えるようにしたもので、byteデータをRTMP形式で送信できるC言語による軽量なモジュールです。このライブラリにはAVC形式の映像データとAAC形式の音声データの2つの入力機構が用意されており、これらの入力を時系列に沿って交互に行う必要があるので、MixChannelではその制約を守るためのラッパークラスを作成して利用しています。
音声データの作成について
MixChannelのライブ配信機能にはカラオケ機能が付属しています。これは、1万曲を超える楽曲の中から好みの楽曲を選び、そのBGMとメロディラインに沿って歌うことで、自分の歌声を視聴者に届けることができる機能です。カラオケに関するデータはBGMデータとメロディラインデータの2つに分かれて存在しており、音声データの作成処理では、マイクから受け取った歌声とこれらの2つのカラオケデータ、合計3つの音声データを合成し、エンコードすることがおもな処理となります。
音声データの作成はマイク入力を受け取る過程から始まります。この過程ではSuperpowered のAndroidAudioIOモジュールを利用し、リアルタイムに入力される音声データをbyteデータとして受け取ります。次に、受け取った音声データにボリュームの調整、およびエコーの付与を施すことで、カラオケらしい音声データへと加工を行います。加工を終えた音声データは、あらかじめダウンロードしておいたBGMデータ、およびメロディラインデータと合成し、端末のスピーカへと出力します。
作成した音声データは、端末のスピーカへの出力と同時にRTMPサーバへの送信にも使用されます。送信時は、MediaCodecを利用したエンコードを行い、RTMPサーバへと送信します。
音声データの作成処理やRTMPサーバへの送信など、ライブ配信機能に関する実装の多くはJavaではなくC/C++で記述されており、NDKを通して動作するモジュールとなっています。NDKはJavaよりも低いレイヤを扱うことができ、複雑な反面、Javaの何倍ものパフォーマンスを実現できるという特徴を持っています。1秒の遅延が大きなストレスを生んでしまうライブ配信機能の実装において、NDKは不可欠な存在です。
いかがでしたでしょうか。後編(1月15日掲載予定)ではいよいよライブ視聴機能の実装について解説します。ご期待ください。
特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現!
特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう
特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT