Skip to content

Audio not playing after returning from background on iOS Chrome and a possible solution #1753

@mogamoga1024

Description

@mogamoga1024

The Problem

iOSのChromeにて、バックグラウンドから復帰時に音が鳴りません。

Safariでも同じ現象が起こりそうですが未確認です。

Reproducible Example

No response

Reproduction Steps

  1. 以下のHTMLをiOSのChromeで読み込む
  2. 再生ボタンを押す
  3. タブを変えるか、スマホをスリープさせるか、Chromeをバックグラウンドにする
  4. 再度、このページをフォアグラウンドにする
  5. そしてもう一回再生ボタンを押す
  6. 音が鳴らない(絶望)
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>実験</title>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/howler.min.js"></script>
</head>
<body>
  <button id="sound">再生</button>
  <div id="message"></div>
  <script src="main.js"></script>
</body>
</html>
let sound = null;
const $sound = document.querySelector("#sound");
const $message = document.querySelector("#message");

// 再生ボタンがクリックされたときはBGMを再生する
$sound.addEventListener("click", async () => {
    sound?.stop();
    if (sound === null) {
        sound = await createSound({
            src: "bgm.mp3",
            volume: 1,
            html5: false,
        });
    }

    $message.innerText = Howler.ctx.state;
    
    sound.play();
});

// ページが非表示になったときはBGMを停止する
document.addEventListener("visibilitychange", () => {
    if (document.hidden) {
        sound?.stop();
    }
});

// Howlオブジェクトの生成
function createSound(option) {
    const sound = new Howl(option);
    return new Promise((resolve, reject) => {
        sound.once("load", () => {
            resolve(sound);
        });
        sound.once("loaderror", () => {
            reject();
        });
    })
}

Possible Solution

以下のようにコードを書いたら直りました。

sound.play();

↑これを
↓こうする

if (Howler.ctx.state === "suspended" || Howler.ctx.state === "interrupted") {
    Howler.ctx.resume().then(() => {
        sound.play();
    });
}
else {
    sound.play();
}

参考:https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/state#resuming_interrupted_play_states_in_ios_safari

このissueはこの事実を周知させるためにあげました。
何かのヒントになれば嬉しいです。

全体は以下の通りです。

let sound = null;
const $sound = document.querySelector("#sound");
const $message = document.querySelector("#message");

// 再生ボタンがクリックされたときはBGMを再生する
$sound.addEventListener("click", async () => {
    sound?.stop();
    if (sound === null) {
        sound = await createSound({
            src: "bgm.mp3",
            volume: 1,
            html5: false,
        });
    }

    $message.innerText = Howler.ctx.state;
    
    if (Howler.ctx.state === "suspended" || Howler.ctx.state === "interrupted") {
        Howler.ctx.resume().then(() => {
            sound.play();
        });
    }
    else {
        sound.play();
    }
});

// ページが非表示になったときはBGMを停止する
document.addEventListener("visibilitychange", () => {
    if (document.hidden) {
        sound?.stop();
    }
});

// Howlオブジェクトの生成
function createSound(option) {
    const sound = new Howl(option);
    return new Promise((resolve, reject) => {
        sound.once("load", () => {
            resolve(sound);
        });
        sound.once("loaderror", () => {
            reject();
        });
    })
}

Context

No response

Howler.js Version

2.2.4

Affected Browser(s)/Versiuon(s)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions