現象
AVFoundationの AVAudioPlayerNode
を使って音声を再生するiOSアプリを開発しており、Google AdMobのInterstitial広告を組み込んでいます。
一部の音声付き動画広告が終わった後、音声を再生しようとしても、なぜか再生できなくなってしまいました。
ログを見ると、AVAudioPlayerNode
の play()
を呼んだ時点で
AVAudioPlayerNode.mm:594 Player@[アドレス]: Engine is not running because it was not explicitly started or may have stopped because of an interruption. Cannot play it!
というエラーが出ていました。
確認したこと
Engine is not running ... or may have stopped
ということだったので、 play()
を呼ぶ前に AVAudioSession
の再アクティブ化や、 AVAudioEngine
の start()
を実行するようにしてみました。
いずれも成功しているようでしたが、その上で、音声が流れない問題は解決しませんでした。
解決策
Google AdMobのドキュメントを眺めていると、 audioSessionIsApplicationManaged
という項目を見つけました。
以下のような説明が書かれています (AIによる翻訳)。
アプリケーションがオーディオセッションを管理したいかどうかを示します。YESに設定すると、Google Mobile Ads SDKは動画再生ライフサイクルの間、AVAudioSessionの管理を停止します。NOに設定すると、Google Mobile Ads SDKはAVAudioSessionを管理します。これには、すべての動画がミュートされたときに AVAudioSession のカテゴリを AVAudioSessionCategoryAmbient に設定すること、再生中の動画がミュート解除されたときに AVAudioSession のカテゴリを AVAudioSessionCategorySoloAmbient に設定すること、Google Mobile Ads SDK によってレンダリングされたすべての動画がミュートまたは再生停止されたときにバックグラウンドアプリがサウンド再生を継続できるようにすることなどが含まれます。メインスレッドでのみアクセスする必要があります。
どうやら、音声の制御を自分のアプリ側で行うかAdMob SDKに任せるかを設定できるようです。
試しに以下のように1行追加してみました。
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
MobileAds.shared.start()
// 次の行を追加
MobileAds.shared.audioVideoManager.isAudioSessionApplicationManaged = true
// ...
return true
}
すると、動画広告終了後でも音声が再生できるようになりました。
AVAudioEngine
の start()
等を明示的に呼ぶ必要もありません。
これで解決したようです!めでたしめでたし👏
おわりに
Google AdMobのInterstitial広告には色々と悩まされがちで、以前にもこの広告によってUIバグが発生したことがありました。(そのときは、アプリ起動時の広告だったので、 App open
タイプの広告に切り替えることで解決しました。)
本件に関しては、AdMob側に音声の制御を任せても良いことがない気がしますし、デフォルトでtrueにしておいてくれれば…などと思ったりしました。
エラーメッセージで検索しても特に何も引っかからず苦労しましたが、なんとか解決できてよかったです。