Hiroppy
Presentation APIを使ってみる

Presentation APIを使ってみる

2018 / 08 / 21
Hiroppy

Hiroppy

JavaScript Engineer


この記事は1年以上更新されていません
この記事は Hatena Blog からの移行記事です

今作っている Fusuma というスライドツールに Presentation API を追加してみました。

blog.hiroppy.me

GitHub - hiroppy/fusuma: ✍️ Fusuma makes slides with Markdown easily.

✍️ Fusuma makes slides with Markdown easily. Contribute to hiroppy/fusuma development by creating an account on GitHub.

github.com
GitHub - hiroppy/fusuma: ✍️ Fusuma makes slides with Markdown easily.

Presentation API とは?

Presentation API - Web APIs | MDN

The Presentation API lets a user agent (such as a Web browser) effectively display web content through large presentation devices such as projectors and network-connected televisions. Supported types of multimedia devices include both displays which are wired using HDMI, DVI, or the like, or wireless, using DLNA, Chromecast, AirPlay, or Miracast.

developer.mozilla.org
Presentation API - Web APIs | MDN

ステータスは 勧告候補 で、今現在は chrome のみ実装されています。 この API は、Keynote や PowerPoint でプレゼンテーションモードにすると他のディスプレイに出力できるようになる機能をブラウザで実現できます。 ディスプレイの他にも、Chrome Cast や AirPlay 等にも映し出すことも可能です。

とりあえずディスプレイが一枚繋がっているかネットワーク以下に Chrome Cast 等があれば使えます。

いままではどのようにやっていたか?

今までもこのように別画面でフルスクリーンにスライドを表示する実装は出来ていました。 これを実現するためには、localStorage でページ情報と挿入イベントのリッスンを行います。 大きな違いとしては、自動で他のディスプレイにフルスクリーンで表示できる点が大きいです。

今までの場合は、window.openでレシーバー側を表示し、それを他のディスプレイに移し、フルスクリーンにするという手順が必要でした。

これからは、対応していなければ localStorage の方を使う実装となりました。 また、Presentation API で表示されたレシーバーからは localStorage は参照できません。

Chrome のサンプルコードは以下を参照

Presentation Receiver API Sample

Sample illustrating the use of Presentation Receiver API.

googlechrome.github.io

コントローラー

接続処理

presentation api
async function connect() {
  return new Promise((resolve, reject) => {
    const presentationRequest = new PresentationRequest(["?presenter=view"]);

    navigator.presentation.defaultRequest = presentationRequest;

    presentationRequest.addEventListener("connectionavailable", (e) => {
      const presentationConnection = e.connection;
      resolve(presentationConnection); // presentationConnectionからternimate以外の操作を行う
    });

    presentationRequest.start().catch((err) => reject(err));
  });
}
localStorage

localStorage なので特になし

メッセージング

presentation api
presentationConnection.send(
  JSON.stringify({
    page: 1,
  }),
);
localStorage
localStorage.setItem(
  "page",
  JSON.stringify({
    date: Date.now(),
    page: 1,
  }),
);

レシーバー

接続処理

presentation api

接続という処理はなく、イベントを登録していく感じとなります。 navigator.presentation.receiver.connectionList に接続されているコネクションのリストが入っています。

function addEvent(name, cb) {
  if (navigator.presentation && navigator.presentation.receiver) {
    navigator.presentation.receiver.connectionList.then((list) => {
      list.connections.forEach((connection) => {
        connection.addEventListener(name, cb);
      });

      list.addEventListener("connectionavailable", (event) => {
        cb(event.connection);
      });
    });
  }
}

addEvent("close", (e) => {
  console.log(e);
});
localStorage

localStorage なので特になし

メッセージング

presentation api
navigator.presentation.receiver.connectionList.then((list) => {
  list.connections.forEach((connection) => {
    connection.addEventListener("message", (e) => {
      const page = JSON.parse(e.data).page;
    });
  });
});
localStorage
window.addEventListener("storage", (e) => {
  if (e.key === "page") {
    const page = JSON.parse(e.newValue).page;

    window.slide.bespoke.slide(page);
  }
});

問題点

  • ライブリロードされると、レシーバーが破棄されるため毎回開き直し
  • レシーバー側では、ショートカットキーが使えず、右クリックから検証を押さないとインスペクターが開けない
  • シークレットウィンドウだと、起動はするがメッセージが送れない
    • UnknownError: Mismatch in incognito status: request = 1, response = 0

とりあえずデバッグが大変めんどくさかったです。

今後

Presentation API と localStorage の互換性があるライブラリを書くかもしれません。 しかし、Chrome Cast などはブラウザの域から外れ、localStorage では対応できないため完璧な対応はできないと思います。 message 周りを抽象化したいなーって実装してて感じました。

すごい便利な機能なので早くほかのブラウザにも入ってほしいと思っています。


関連記事