Linear ArchiveArchived issues viewer
← Back to list
INS-886

ホーム画面でアプリを閉じて、その後 復帰して開くと BGMが2重で再生される

StatusDone
TeamInstansys
Assigneeasuki.uehata@instansys.co.jp
PriorityMedium
Created2026/06/22 08:33
Completed2026/06/23 12:44
Archived2026/07/01 01:10
Bug

Description

6/22 14:53 の 大幅なsound機能更新 マージ後 発生している 問題。

Comments (1)

asuki.uehata@instansys.co.jp2026/06/22 09:09

最小修正(推奨): inactive 時に _bgmTrack も destroy する。

   // 実機では sound.stopAll() で全停止済み。内部の「現在再生中」状態も
   // クリアして実態と一致させる。desired(_mainDesired / _scenarioDesired)は
   // 残すので、復帰時に reconcile が正しい1系統を鳴らし直す。
   this._bgmInstance = null;
   this._currentPlayingAlias = null;
   this._scenarioBgmAlias = null;
+  // BGM は HtmlBgmTrack 経由で <audio> を持っており、stopAll の対象外。
+  // pause だけでは復帰時に iOS が自動再生再開して新トラックと二重再生になるため、
+  // destroy() で要素ごと解放する。次回 _ensureMainPlaying が新規生成する。
+  if (this._bgmTrack) {
+    this._bgmTrack.destroy();
+    this._bgmTrack = null;
+  }
+  if (this._bgmOldTrack) {
+    this._bgmOldTrack.destroy();
+    this._bgmOldTrack = null;
+  }

_scenarioBgmTrack も同型でリークし得るので併せて destroy します。

最終 diff 案

ファイル: apps/client/src/lib/sound.ts L408-413 付近

             // 実機では sound.stopAll() で全停止済み。内部の「現在再生中」状態も
             // クリアして実態と一致させる。desired(_mainDesired / _scenarioDesired)は
             // 残すので、復帰時に reconcile が正しい1系統を鳴らし直す。
             this._bgmInstance = null;
             this._currentPlayingAlias = null;
             this._scenarioBgmAlias = null;
+            // BGM は HtmlBgmTrack 経由で <audio> を持っており @pixi/sound の
+            // stopAll の対象外。pause() だけでは iOS が AVAudioSession 復帰時に
+            // 自動再生再開し、復帰時に作られる新トラックと二重再生になるため、
+            // 要素ごと destroy() して解放する。desired は残しているので
+            // 復帰時の reconcile が新トラックを作って正しく1系統だけ鳴らす。
+            if (this._bgmTrack) {
+              this._bgmTrack.destroy();
+              this._bgmTrack = null;
+            }
+            if (this._bgmOldTrack) {
+              this._bgmOldTrack.destroy();
+              this._bgmOldTrack = null;
+            }
+            if (this._scenarioBgmTrack) {
+              this._scenarioBgmTrack.destroy();
+              this._scenarioBgmTrack = null;
+            }
             return;
  • _bgmOldTrack は crossfade 中の旧トラック退避先。inactive 時に進行中なら同じく取り残されるため一緒に destroy する。
  • _scenarioBgmTrack はシナリオ系列。シナリオ中にホームボタンされたケースで同じ症状を出すので合わせて。
  • desired (_mainDesired / _scenarioDesired) は触らない。復帰時の _recoverAudio_reconcileBgm({ forceRestart: true })_ensureMainPlaying で新トラックを作って復元される。
  • _bgmTrack が destroy 済みになっていれば、_ensureMainPlaying 内の _currentPlayingAlias === null 分岐でも整合(参照のリーク自体がなくなる)。