2021年卒業の内定者アルバイトとしてチームに参加

今西勇太氏:「Electronで動画再生プレイヤー開発」というタイトルで発表します。よろしくお願いします。

まず始めに自己紹介をします。今西勇太と言います。私は今大学生で、2021年卒業の内定者アルバイトとして、動画配信事業部の配信基盤グループにお世話になっています。(※取材当時)お世話になっているのは、内定を承諾した2020年の3月からなので、もうそろそろ1年経つかなという感じです。

趣味はいろいろとあるんですが、ここに書いていないことでは、ドット絵を描くことにちょっと挑戦してみようかなと最近思っています。仲良くしていただけるとうれしいです。

ここで少し余談になるんですが、内定者アルバイトとしてのふだんの働き方に軽く触れたいと思います。この先、新卒としてDMMに入社を考えている方の選択肢になればいいなと思っています。

今年度は、このご時世で私の大学もオンライン授業やオンラインゼミがメインでした。私の場合は4年次ということもあって、ほとんどゼミがメインだったんですが、金曜日をゼミの日にして月曜日から木曜日を内定者アルバイトという働き方にしています。

私のチームは、2週間でスプリントを回しているんですが、毎週の“ふりかえり”のミーティングを水曜日にズラしてもらうなど、そのあたりは融通してもらっていて、すごく働きやすいです。

今日話すのは「Electron」での動画再生プレイヤー開発の話で、1から10まで話すと日が暮れてしまうと思うので、今回は直近でリリースした機能の実装をメインで話そうと思います。Electronで始めるときに何からしたらいいのかなど、今回話しきれない部分に関しては、公式のドキュメントが詳しくまとまっているので、そちらを見てもらえればと思います。

デスクトップアプリが作成できるフレームワーク「Electron」

まずはElectronについて概要をサクッと説明します。今回視聴しているのは、恐らくWebフロントエンドエンジニアが大半なのかなと思っているんですが、そういった方々にとっても馴染みが深いであろうJavaScriptや、HTMLや、CSSなどの技術を用いて、デスクトップアプリケーションを作成できるフレームワークがElectronです。

クロスプラットフォーム対応で、WindowsやmacOSなどの対応が一元的に管理できるメリットがあります。それから、このElectronの中身ですが描画部分をChromiumで、管理をNode.jsが担当して動いています。

Chromiumが動いているということはChrome対応だけでかまわないので、Internet ExplorerやSafariなどのブラウザー間の差分で苦しまずに済むところがいいなと思っています。クロスプラットフォーム対応ができると書いたんですが、一方でMacとWindowsでアプリの起動方式がOSレベルで違ったり、そういうところの差分で苦しんだりすることは意外とあるので、そこは気をつけないといけないなと思っています。

Electronのアプリケーションがどんな感じに動いているのかについて説明します。Electronのアプリケーションのアーキテクチャに関しては、MainプロセスとRendererプロセスという2つのプロセスがあって、Mainプロセス1つにつきRendererプロセスが複数紐づいています。

MainプロセスではBrowserWindowインスタンスを作ったり、破棄したりします。BrowserWindowインスタンスは、いわゆるデスクトップアプリを開いたときに展開される一つひとつのウィンドウだと思ってくれて大丈夫だと思います。BrowserWindowインスタンスを作ることでウィンドウを開き、BrowserWindowインスタンスを破棄することでウィンドウを閉じます。

作成されるすべてのウィンドウと、対応されるRendererプロセスをこのMainプロセスで管理しています。Backend Node.jsをイメージしてもらえればいいのかなと思っています。

先ほどMainプロセスで作成されたBrowserWindowインスタンスがこのRendererプロセスに渡ってきて、Rendererプロセス内でそれが実行されることでWebページが描画されます。Rendererプロセスの中で言えば、HTML、CSS、JSを使ってChromeの画面に描画するイメージです。

MainプロセスとRendererプロセスの間を線で結んでいるんですが、ここでプロセス間通信ができて、データやイベントの受け渡しが柔軟にできます。API通信をイメージしてもらえればいいと思います。

「DMM Player V2」に同時再生機能をリリース

ここまで軽くElectronの説明をしたんですが、ここからが今日のメインテーマで、動画再生のためのデスクトップアプリ「DMM Player V2」の新機能を実装したというお話です。

まずDMM Player V2とは何なのかですが、Silverlight製だった先代のプレイヤーに代わる新しい動画再生プレイヤーとして、Electron製が開発されました。DMM.comのサイトでダウンロードした動画をWindowsやMacなどのパソコン上で再生できるプレイヤーです。現在、私が主に面倒を見ています。

新機能をリリースしました。何かというと、複数ウィンドウでの同時再生機能です。YouTubeを想像してください。YouTubeでタブを開いて、動画を再生して、そのタブはそのままで、また別のタブを開いて別の動画を再生したりすると思うのですが、要はあれができる、そんな機能です。

YouTubeと違うところは、ファイル関連付けができるところですね。ファイル関連付けさえ行っていれば、その動画が開かれるときに動画プレイヤーが開かれて、プレイヤーの中で再生が始まります。

ファイル関連付けと同時再生機能を組み合わせることによって、プレイヤーが起動していない状態から、見たい動画を複数選択して一気にダブルクリックすることで、ポンポンッと一気にプレイヤーが開かれて動画の再生ができる機能です。イメージはこんな感じですね。3つが一気に開かれて、テレビで複数チャンネルを同時に見るようなイメージでいてもらえればいいのかなと思っています。

新機能実装のための要件と設計

この機能を実装するにあたっての要件の整理をしてみたいと思います。前提として、すでに開いているプレイヤーから「ファイルを開く」というボタンを押して、新しく動画を開くか、先ほど言ったようにファイル関連付けによって動画ファイルを開く、の2パターンあるんですが、各々のBrowserWindowインスタンスを良い感じに立ち上げることを考えなきゃいけないです。

この機能に限った話ではないんですが、機能を作るにあたってデグレーションがないように気をつけなきゃいけないなと思っていて、この複数同時再生機能をoffにした場合も、これまでのプレイヤーの機能すべてで、今までとまったく同じユーザー体験を提供できるようにしなきゃいけません。

それからデータの持ち方も気をつけなきゃいけなくて、共通してもつべきデータと共通させないべきデータがあって、例えば認証情報は共通にしておかないと、1つ動画を開いてログインして再生して、もう1つ動画を開きたいとなったときに、そこでまた認証を求められたらユーザー体験としては悪いと思うので、1回認証したらそのデータを使い回すのが必要です。

共通させないほうがいいデータは音量とかですね。この動画は大音量で見たいけど、この動画はちょっと控えめの音量で見たいとかがあると思うので、同期させちゃいけないデータです。

それでは実際の設計を考えていきたいと思います。まず毎度お馴染みのMainプロセスとRendererプロセスがあって、Mainプロセスは動画プレイヤーが起動するときに最初に再生する動画の情報ですね。ダウンロードされている動画のパスをBrowserWindowインスタンスを立ち上げるときに、各Rendererプロセスにここの動画を再生してくださいね、という情報を渡しています。

Rendererプロセス側ではユーザーがUIから変更するいろいろな設定ですね。例えばログインをしたり、音量を変えたり、同時再生のon/offを設定したりとか、そういうのをlocalStorageに保存して都度参照するようにします。先ほど言ったような、音量以外の同期しておくべきログイン認証などの情報はlocalStorageに保存するときに各Rendererプロセス同士で同期されるように設定しなきゃいけません。

実装でつまずいたポイントと解決方法

これで設計が一通りできたので、あとはうまくこの設計に沿って書いていけば無事にめでたしめでたしと。実装ができて機能が完成しましたと……。悲しいことにそうはいかなかったんですね。

何が悪かったのかなんですが、もうピンと来ている方もいるかもしれませんが、さっきの設計でいけなかったことが1つあります。何かというとこの赤字の部分です。同時再生のon/offはlocalStorageに入れちゃダメでした。

少し噛み砕いて、何がいけなかったのかを説明します。このlocalStorageはブラウザーの持ち物なんですね。Chromiumの持ち物で、Rendererプロセスが立ち上がるまではこのlocalStorageのデータを参照できないんですね。

すでにプレイヤーが起動されている状態なら問題ないんですが、例えば関連付け再生をメインで使っているユーザーだと、プレイヤーを起動していない状態で最初から複数ファイルを選択して、関連付け再生を起動したいという方もいると思うんです。

そういうときに、最初に起動されるMainプロセスのタイミングでは、各Rendererプロセス内のlocalStorageを参照しに行けません。参照をしに行けないということは、on/offのどちらになっているかわからないので、同時再生の機能を使えないということになってしまいます。これでは致命的ですね。

そこで今回、同時再生設定の保存先を変更しました。localStorageやindexedDBなどブラウザーがもっているクライアントサイドストレージはタイミング的に参照ができないので、今回はアプリケーションディレクトリ内にJSONファイルとして保存するという策をとりました。今回は設定なので、覗かれて困るようなデータではなかったため、この方法を採用しました。

もし覗かれて困るような、センシティブな値やデータの場合には、クライアントサイドでもたないようにするなどの工夫が必要になってくるのかなと思っています。

今回はelectron-storeというライブラリを使いました。electron-storeはアプリケーションディレクトリ内への保存や読み込みのプロセスを扱いやすくラップしてくれるんですね。なので今回はこのライブラリを採用しました。

自分が開発した機能には責任をもつ

これで正真正銘、あとは書くだけです。設計ができたのであとは書くだけの状態になり、無事リリースまでたどり着きました。ただ、今日の話はこれで終わりではなくて、もう1つ最後にあります。

それがログを見るようにしましょうという話です。当たり前で、私が言うまでもない話かもしれませんが、リリース後にユーザーの反応を見るのはやっぱり大事だと思っています。私のチームでは、自分を含めたほぼ全員がフロントエンド、バックエンドに関係なく、ほぼ全員がクエリを書いてユーザーの動向を分析して、機能の改善に役立てています。

これは個人的な気持ちの話ですが、フロントエンドエンジニアが全員SQLが書けるべきとは思いませんが、自分が開発した機能には責任をもつという意味で、ログを仕込んでクエリを書いて自分で調査して、それを改善につなぐことができて困ることはないと思っているので、ぜひやってみてもらえたらと思います。今回、同時再生機能の利用者率を調べた結果がこちらです。

赤がoffにしている人、もしくは設定をいじっていない人です。青が設定をonにしている人なんですが、有効化している人の率はまだまだ少ないのが現状です。

原因の1つがレスポンシブ対応だと思っています。複数の動画を開くとき、ウィンドウを小さくして見るユーザーが多いと思うんですが、そこのレスポンシブ対応については現在最新版で対応中でして、この動画が流れる頃にはリリースされているかもしれないので、ぜひ楽しみにしてもらえたらと思っています。

ぜひ使ってもらって、気になる点や要望、不満などがありましたら、お寄せいただければうれしいです。

最後にまとめです。Electronでは、ブラウザーに依存せずにクライアントサイドでのデータ保存ができます。localStorageにせよindexedDBにせよ、アプリケーションディレクトリ内にデータを入れているのに変わりはないんですが、参照するタイミングですね。

Rendererプロセスが立ち上がっていないと、そのあたりは参照ができないので、ブラウザーに依存せずにデータ保存ができます。そこは用途に応じて使い分けるとよさそうかなと思います。もっとよい方法があるぞという方がいたら、あとでこっそりTwitterなどで教えてもらえたらうれしいです。

こっちは個人的な話になるんですが、フロントエンドエンジニアでもSQLを書いて、軽くでもリリースの効果測定ができて科学的に改善を行っていけるといいのかなと考えています。

発表は以上になるんですが、私が所属している配信基盤グループの活動に興味がある方は上のリンク、Electronでのプレイヤー開発についてもっと知りたいという方は下の「Electron製動画再生プレイヤー『DMM Player v2』」という記事のリンクをご覧ください。

Silverlight製のプレイヤーからElectron製のプレイヤーへの移行について、詳細が載っているので、興味のある方はぜひ読んでもらえたらうれしいです。それでは私の発表は以上です。ご清聴ありがとうございました。