ウェブ オーディオ、自動再生ポリシー、ゲーム

Tom Greenaway

2017 年 9 月に、Chrome の自動再生動作ポリシーで音声の処理方法が変更されることをお知らせしました。このポリシーの変更は、2018 年 5 月の Chrome 66 Stable でリリースされました。

Web Audio 開発コミュニティからのフィードバックを受け、デベロッパーがウェブサイトを更新するための猶予期間を長くするため、自動再生ポリシーの Web Audio に関する部分のリリースを延期しました。また、Web Audio に関するポリシーの実装にも変更を加えました。これにより、コードを調整する必要があるウェブサイト(特にウェブゲーム)の数を減らし、ユーザーにより良いエクスペリエンスを提供できるようになります。

このポリシーの変更は、2018 年 12 月の Chrome 71 でリリースされる予定です。

ポリシーの変更は具体的にどのような影響がありますか?

自動再生とは、ウェブページの読み込み時にすぐに再生されるコンテンツのことです。コンテンツの自動再生が想定されているウェブサイトでは、この変更によりデフォルトで再生がブロックされます。ほとんどの場合、再生は再開されますが、コードを少し調整する必要がある場合もあります。具体的には、ユーザーがウェブページを操作した場合にコンテンツを再開するコードを追加する必要があります。

ただし、ユーザーが自動再生コンテンツを含むページにアクセスし、そのページに同じオリジンのページから移動した場合、そのコンテンツはブロックされません。詳細な例については、自動再生に関するポリシーに関する以前のブログ投稿をご覧ください。

また、音声の自動再生を行うウェブサイトに関するユーザーの過去の行動から学習するヒューリスティクスを追加しました。ユーザーがウェブサイトにアクセスするたびに、ほとんどの場合 7 秒を超えて音声を再生していることが検出されると、そのウェブサイトの自動再生が有効になります。

この処理は、デバイス上の Chrome プロフィールごとにローカルに保存されるインデックスを使用して行われます。このインデックスはデバイス間で同期されず、匿名化されたユーザー統計データの一部としてのみ共有されます。この指標はメディア エンゲージメント指数(MEI)と呼ばれ、chrome://media-engagement で確認できます。

MEI は、7 秒を超える音声再生が含まれるサイト訪問回数を追跡します。ユーザーの MEI に基づいて、ユーザーが特定のウェブサイトから音声を期待しているかどうかを把握し、ユーザーの意図を予測できると考えています。

ユーザーがウェブサイトのドメインで 7 秒を超える音声を再生することを頻繁に許可している場合、今後は、ユーザーがそのウェブサイトに音声の自動再生の権限があることを期待しているとみなされます。そのため、そのドメインのタブをユーザーが操作しなくても、そのウェブサイトに音声を自動再生する権限が付与されます。

ただし、この権利が無期限に保証されるわけではありません。ユーザーの行動が切り替わった場合(複数回のアクセスで、7 秒の基準時間内に音声の再生を停止したり、タブを閉じたりした場合など)は、ウェブサイトの自動再生の権利が取り消されます。

メディア HTML 要素(動画と音声)とウェブ オーディオ(JavaScript でインスタンス化された AudioContext オブジェクト)の両方の使用が MEI に貢献します。このポリシーのロールアウトに備えて、Chrome 70 以降では、Web Audio に関連するユーザー行動が MEI に反映されるようになります。これにより、自動再生とユーザーがよくアクセスするウェブサイトに関するユーザーの意図を事前に予測できるようになります。

iframe がユーザー操作なしで自動再生する権利を得られるのは、iframe を埋め込む親ウェブページがその権利を特定の iframe に拡張している場合のみです。

コミュニティをサポートするために変更を遅らせる

この変更が Chrome Stable チャンネルに表示されたとき、ウェブオーディオ デベロッパー コミュニティ(特に、このコミュニティのウェブゲーム デベロッパーと WebRTC デベロッパー)は注目しました。

コミュニティからのフィードバックでは、この変更により多くのウェブゲームやウェブ オーディオ エクスペリエンスが悪影響を受けると懸念されています。具体的には、更新されていない多くのサイトで、ユーザーにオーディオが再生されなくなることが懸念されています。そのため、ウェブオーディオ デベロッパーがウェブサイトの更新に十分な時間を確保できるように、この変更を延期することにしました。

また、この機会に以下のことを行いました。

  • このポリシーの変更が最善の対応策であったかどうかを真剣に検討します。
  • 影響を受ける音声付きウェブサイトの数を減らす方法を検討しています。

前者については、最終的に、大多数のユーザーのユーザー エクスペリエンスを向上させるために、ポリシーの変更が本当に必要であると判断しました。ポリシーの変更によって解決される問題について詳しくは、この記事の次のセクションをご覧ください。

後者については、Web Audio の実装を調整し、当初影響を受けたウェブサイトの数を減らしました。変更によって動作しなくなったことが判明したサイト(その多くはウェブゲーム開発コミュニティから例として提供されたもの)のうち、80% 以上がこの調整によって自動的に動作するようになりました。これらのサンプルサイトの分析とテストはこちらでご覧いただけます。この新しい調整について、以下で詳しく説明します。

また、WebRTC アプリケーションをサポートするように変更しました。キャプチャ セッションがアクティブな間は、自動再生が許可されます。

この行動変化は、どのような問題を解決しようとしていますか?

これまで、ブラウザはユーザーが音声を管理するのに適していませんでした。ユーザーがウェブページを開いたときに、想定していない音や望ましくない音が聞こえると、ユーザー エクスペリエンスが低下します。このユーザー エクスペリエンスの低下が、Google が解決しようとしている問題です。ユーザーがブラウザでコンテンツの自動再生を望まない主な理由は、不要なノイズです。

ただし、ユーザーがコンテンツの自動再生を希望することもあります。Chrome でブロックされた自動再生の多くは、その後ユーザーによって再生されています。

そのため、ユーザーから学び、ウェブサイトごとにユーザーの意図を予測することで、最適なユーザー エクスペリエンスを実現できると考えています。ユーザーがウェブサイトからコンテンツを再生する傾向がある場合は、今後、そのサイトのコンテンツが自動再生されます。逆に、ユーザーが特定のウェブサイトのコンテンツの自動再生を停止する傾向がある場合は、そのコンテンツの自動再生はデフォルトでブロックされます。

コミュニティから提案されたのは、自動再生を一時停止するのではなく、タブの音声をミュートするというものです。ただし、自動再生がブロックされたことをウェブサイトが認識し、ウェブサイト デベロッパーがこれに対応できるように、自動再生を停止することをおすすめします。たとえば、音声をミュートするだけでよいデベロッパーもいれば、ユーザーがコンテンツを積極的に操作するまで音声コンテンツを一時停止することを望むデベロッパーもいます。後者の場合、ユーザーが音声エクスペリエンスの一部を聞き逃す可能性があります。

ウェブゲーム デベロッパーを支援する新しい調整

デベロッパーが Web Audio API を使用する最も一般的な方法は、次の 2 種類のオブジェクトを作成して音声を再生することです。

ウェブ オーディオのデベロッパーは、音声を再生するための AudioContext を作成します。自動再生ポリシーによって AudioContext が自動的に停止された後に音声を再開するには、ユーザーがタブを操作した後に、このオブジェクトで resume() 関数を呼び出す必要があります。

    const context = new AudioContext();

    // Setup an audio graph with AudioNodes and schedule playback.
    ...

    // Resume AudioContext playback when user clicks a button on the page.
    document.querySelector('button').addEventListener('click', function() {
      context.resume().then(() => {
        console.log('AudioContext playback resumed successfully');
      });
    });

AudioNode から継承するインターフェースは多数ありますが、そのうちの 1 つが AudioScheduledSourceNode インターフェースです。AudioScheduledSourceNode インターフェースを実装する AudioNode は、通常、ソースノード(AudioBufferSourceNode、ConstantSourceNode、OscillatorNode など)と呼ばれます。ソースノードは start() メソッドを実装します。

ソースノードは通常、ゲームで再生される個々の音声スニペットを表します。たとえば、プレイヤーがコインを収集したときに再生される音や、現在のステージで再生されるバックグラウンド ミュージックなどです。ゲーム デベロッパーは、ゲームでこれらの音声が必要になるたびに、ソースノードで start() 関数を呼び出すことが非常に多いです。

ウェブゲームでこの一般的なパターンを認識した後、実装を次のように調整することにしました。

AudioContext は、次の 2 つの条件が満たされると自動的に再開されます。

  • ユーザーがページを操作した。
  • ソースノードの start() メソッドが呼び出されます。

この変更により、ほとんどのウェブゲームで、ユーザーがゲームのプレイを開始すると音声が再開されるようになりました。

ウェブの進化

ウェブ プラットフォームを進化させるために、互換性を損なう変更を加える必要が生じることがあります。残念ながら、音声の自動再生は複雑な機能であり、この変更の対象となります。ただし、ウェブが停滞したり、革新的な優位性を失ったりしないようにするには、このシフトを進めることが重要です。

ただし、さまざまな理由により、ウェブサイトの修正を短期間で適用できない場合もあります。

  • ウェブ デベロッパーは新しいプロジェクトに集中しているため、古いウェブサイトのメンテナンスはすぐに行えない場合があります。
  • ウェブゲーム ポータルでは、カタログ内のゲームの実装を管理できない場合があります。また、数百、数千に上るゲームの更新は、パブリッシャーにとって時間と費用のかかる作業です。
  • ウェブサイトによっては、古すぎて、なんらかの理由でメンテナンスが行われていないものの、歴史的目的でホストされているものもあります。

以下は、新しい AudioContext オブジェクトの作成をインターセプトし、ユーザーがさまざまな操作を行ったときにこれらのオブジェクトの resume 関数を自動的にトリガーする短い JavaScript コード スニペットです。このコードは、ウェブページで AudioContext オブジェクトを作成する前に実行する必要があります。たとえば、このコードをウェブページの タグに追加できます。

(function () {
  // An array of all contexts to resume on the page
  const audioContextList = [];

  // An array of various user interaction events we should listen for
  const userInputEventNames = [
    'click',
    'contextmenu',
    'auxclick',
    'dblclick',
    'mousedown',
    'mouseup',
    'pointerup',
    'touchend',
    'keydown',
    'keyup',
  ];

  // A proxy object to intercept AudioContexts and
  // add them to the array for tracking and resuming later
  self.AudioContext = new Proxy(self.AudioContext, {
    construct(target, args) {
      const result = new target(...args);
      audioContextList.push(result);
      return result;
    },
  });

  // To resume all AudioContexts being tracked
  function resumeAllContexts(event) {
    let count = 0;

    audioContextList.forEach(context => {
      if (context.state !== 'running') {
        context.resume();
      } else {
        count++;
      }
    });

    // If all the AudioContexts have now resumed then we
    // unbind all the event listeners from the page to prevent
    // unnecessary resume attempts
    if (count == audioContextList.length) {
      userInputEventNames.forEach(eventName => {
        document.removeEventListener(eventName, resumeAllContexts);
      });
    }
  }

  // We bind the resume function for each user interaction
  // event on the page
  userInputEventNames.forEach(eventName => {
    document.addEventListener(eventName, resumeAllContexts);
  });
})();

なお、このコード スニペットが iframe 内の AudioContext のインスタンス化を再開することはありません。ただし、このコード スニペットが iframe 自体のコンテンツのスコープに含まれている場合は例外です。

ユーザーにより良いサービスを提供する

ポリシーの変更に伴い、自動学習が想定どおりに機能しない場合や、この変更によりウェブサイトが使用できなくなった場合に対応するため、ユーザーが自動再生ポリシーを無効にできるメカニズムも導入します。この変更は、Chrome 71 の新しいポリシーとともにリリースされ、[音声設定] で確認できます。ユーザーが自動再生を許可するサイトは、許可リストに追加できます。

新規ユーザーの MEI はどのように作成されますか?

前述のように、Google は、自動再生コンテンツを含む特定のウェブサイトに関してユーザーが意図する操作を予測するために、ユーザーの行動に基づいて MEI を自動的に構築します。各ウェブサイトには、このインデックスで 0 ~ 1 のスコアが付けられます。スコアが高いほど、ユーザーがそのウェブサイトからコンテンツを再生することを期待していることを示します。

ただし、新しいユーザー プロファイルの場合や、ユーザーがブラウジング データを消去した場合は、自動再生をすべてブロックするのではなく、匿名化されたユーザーの集計 MEI スコアに基づく事前シードリストを使用して、自動再生を許可するウェブサイトを判断します。このデータは、ユーザー プロファイルの作成時に MEI の初期状態のみを決定します。ユーザーがウェブをブラウジングし、自動再生コンテンツを含むウェブサイトを操作すると、そのユーザーの個人 MEI がデフォルト設定をオーバーライドします。

事前設定されたサイトリストは、手動でキュレートされるのではなく、アルゴリズムによって生成されます。どのウェブサイトでもリストに含めることができます。サイトにアクセスするユーザーの数が十分に多く、そのサイトでの自動再生を許可している場合、そのサイトはリストに追加されます。このしきい値は、大規模なサイトを優遇しないように、割合ベースで設定されています。

バランスを取る

このポリシーの意思決定プロセスと設計の根拠について詳しく説明する新しいドキュメントを公開しました。また、事前設定されたサイトリストの仕組みに関する新しいドキュメントも公開されています。

Google は常にユーザーを最優先に考えていますが、ウェブ開発コミュニティを失望させることも望んでいません。ブラウザの場合、これらの 2 つの目標を慎重にバランスさせる必要があります。Google は、ポリシーの実装を調整し、ウェブオーディオ デベロッパーがコードを更新するための時間を延長したことで、Chrome 71 でこのバランスを実現できると考えています。

フィードバック