網路音訊、自動播放政策和遊戲

Tom Greenaway
Hongchan Choi

我們在 2017 年 9 月宣布,Chrome 即將針對自動播放行為政策調整音訊處理方式。這項政策變更已在 2018 年 5 月隨 Chrome 66 穩定版發布。

在 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 開始,與網路音訊相關的使用者行為將開始納入 MEI。這樣一來,我們就能預測使用者在自動播放功能和常造訪網站時的預期意圖。

請注意,只有在嵌入 iframe 的父網頁將權限擴充至指定 iframe,iframe 才能獲得不需使用者互動即可自動播放的權限。

為支持社群而延後變更

當這項變更出現在 Chrome 穩定版管道時,網頁音訊開發人員社群 (特別是網頁遊戲開發人員和 WebRTC 開發人員) 就注意到了。

社群回饋指出,許多網頁遊戲和網頁音訊體驗都會受到這項異動的負面影響,特別是許多未更新的網站將無法再為使用者播放音訊。因此,我們的團隊決定延後這項異動,讓網頁音訊開發人員有更多時間更新網站。

此外,我們也趁此時機:

  • 請認真考慮這項政策變更是否為最佳做法。
  • 探索可減少受影響的音訊網站數量的做法。

就前者而言,我們最終決定,為了改善大多數使用者的使用體驗,政策調整確實必要。如要進一步瞭解這項政策異動解決的問題,請參閱本文的下一節。

針對後者,我們已調整 Web Audio 的導入方式,這將減少原本受影響的網站數量。在我們知道因這項異動而無法正常運作的網站中,其中許多都是網頁遊戲開發社群提供的範例,而這項調整意味著超過 80% 的網站將自動運作。您可以在此處查看我們對這些示例網站的分析和測試結果。以下將更詳細說明這項新調整。

我們也做出了變更,以支援 WebRTC 應用程式;在有有效擷取工作階段的情況下,系統會允許自動播放。

這項行為變更旨在解決什麼問題?

瀏覽器向來不擅長協助使用者管理音效。如果使用者開啟網頁時,收到不預期或不想要的聲音,就會導致使用者體驗不佳。我們正設法解決這個使用者體驗不佳的問題。使用者不希望瀏覽器自動播放內容,主要原因是不想要聽到不必要的聲響。

不過,有時使用者會希望內容自動播放,因此 Chrome 會播放大量遭到封鎖的自動播放內容。

因此,我們認為只要從使用者身上學習,並根據每個網站預測使用者意圖,就能打造最佳使用者體驗。如果使用者傾向讓網站播放內容,我們日後會自動播放該網站的內容。相反地,如果使用者傾向停止特定網站的自動播放內容,我們會預設禁止播放該內容。

社群提出的其中一個建議,是將分頁的音訊靜音,而不是暫停自動播放。不過,我們認為最好停止自動播放功能,讓網站知道自動播放功能已遭封鎖,並讓網站開發人員做出回應。舉例來說,有些開發人員可能只想將音訊靜音,而其他開發人員則可能希望將音訊內容暫停,直到使用者主動與內容互動為止,否則使用者可能會錯過部分音訊體驗。

協助網頁遊戲開發人員的新調整

開發人員使用 Web Audio API 最常見的方式,是建立兩種物件來播放音訊:

網路音訊開發人員會建立 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,其中一個是 AudioScheduledSourceNode 介面。實作 AudioScheduledSourceNode 介面的 AudioNode 通常稱為來源節點 (例如 AudioBufferSourceNode、ConstantSourceNode 和 OscillatorNode)。來源節點會實作 start() 方法。

來源節點通常代表遊戲播放的個別音訊片段,例如玩家收集硬幣時播放的音效,或是目前階段播放的背景音樂。遊戲開發人員在遊戲中需要任何這類音效時,很可能會在來源節點上呼叫 start() 函式。

我們發現網頁遊戲中常見這種模式,因此決定將實作方式調整為以下方式:

符合下列兩個條件時,AudioContext 會自動恢復:

  • 使用者與網頁互動。
  • 系統會呼叫來源節點的 start() 方法。

由於這項變更,大多數的網路遊戲現在會在使用者開始玩遊戲時繼續播放音訊。

推動網路發展

為了讓網路平台持續進步,有時必須做出可能會破壞相容性的變更。很抱歉,自動播放音訊的機制相當複雜,因此屬於這類變更。不過,這項轉變至關重要,才能確保網路不會停滯不前,或失去創新優勢。

不過,我們也瞭解,由於各種原因,我們無法在短期內為網站套用修正程式:

  • 網路開發人員可能會專注於新專案,因此無法立即維護舊網站。
  • 網頁遊戲入口網站可能無法控制目錄中遊戲的實作方式,而更新數百 (甚至數千) 款遊戲對發布商來說可能耗時且成本高昂。
  • 有些網站可能只是非常老舊,且因某些原因不再維護,但仍會保留供歷史參考。

以下是一段簡短的 JavaScript 程式碼片段,可攔截新 AudioContext 物件的建立作業,並在使用者執行各種互動動作時自動觸發這些物件的 resume 函式。您應在網頁中建立任何 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 內容的範圍內,否則無法協助恢復在 iframe 中例項化的 AudioContext。

提供更優質的服務

為配合政策異動,我們也推出了使用者可用來停用自動播放政策的機制,以因應自動學習功能無法正常運作,或網站因政策異動而無法正常運作的情況。這項異動將在 Chrome 71 中推出,並可在「聲音設定」中找到。使用者可將要允許自動播放的網站加入「允許」清單。

如何為新使用者建立 MEI?

如先前所述,我們會根據使用者行為,自動建立 MEI,以預測使用者在特定網站上觀看自動播放內容時的意圖。每個網站在這個索引中的分數介於 0 到 1 之間。分數越高,就表示使用者越期待從該網站播放內容。

不過,如果是新使用者設定檔,或是使用者清除瀏覽資料,系統不會在所有情況下禁止自動播放功能,而是會根據去識別化使用者匯總的 MEI 分數,使用預先指定的清單來決定哪些網站可以自動播放。這項資料只會決定建立使用者設定檔時的 MEI 初始狀態。當使用者瀏覽網頁,並與含有自動播放內容的網站互動時,個人 MEI 會覆寫預設設定。

預先提供的網站清單是透過演算法產生,而非手動挑選,因此任何網站都有資格加入。如果有足夠的使用者造訪網站,且允許在該網站上自動播放廣告,系統就會將該網站加入清單。這個門檻以百分比計算,避免偏袒大型網站。

尋找平衡點

我們已發布新的說明文件,進一步說明這項政策的決策程序和設計依據。以及預先填入的網站清單運作方式的新說明文件。

我們一向以使用者為優先,但也不想讓網頁開發社群失望。有時候,瀏覽器必須同時兼顧這兩項目標,並謹慎取得平衡。我們認為,在調整政策實施方式,並為網頁音訊開發人員提供更多時間更新程式碼後,Chrome 71 將能達到這項平衡。

意見回饋