Fix iOS Now Playing integration for MPV backend

The MPV backend now properly displays Now Playing information in iOS Control Center. The fix addresses the issue where the AVAudioSession would become inactive during MPV's playback lifecycle.

Key changes:
- Added setupAudioSessionForNowPlaying() method to activate AVAudioSession with proper playback category and movie playback mode
- Re-activate audio session at critical MPV events: FILE_LOADED, PLAYBACK_RESTART, AUDIO_RECONFIG, and during periodic updates
- Initialize audio session immediately after mpv_initialize() in MPVClient

The audio session must be re-activated at multiple points during playback, not just at initialization, to ensure iOS recognizes the app as playing media.
This commit is contained in:
Arkadiusz Fal
2025-11-18 16:20:30 +01:00
parent 9c15393ab4
commit e6b6778ba1
3 changed files with 40 additions and 1 deletions

View File

@@ -504,7 +504,10 @@ final class MPVBackend: PlayerBackend {
updateControls()
}
model.updateNowPlayingInfo()
#if !os(macOS)
model.setupAudioSessionForNowPlaying()
model.updateNowPlayingInfo()
#endif
handleSegmentsThrottle.execute {
model.handleSegments(at: currentTime)
@@ -594,6 +597,11 @@ final class MPVBackend: PlayerBackend {
onFileLoaded = nil
// Reset retry state on successful load
resetRetryState()
// Re-activate audio session for Now Playing
#if !os(macOS)
model.setupAudioSessionForNowPlaying()
model.updateNowPlayingInfo()
#endif
case MPV_EVENT_PROPERTY_CHANGE:
let dataOpaquePtr = OpaquePointer(event.pointee.data)
@@ -611,10 +619,22 @@ final class MPVBackend: PlayerBackend {
onFileLoaded = nil
// Reset retry state on successful playback restart
resetRetryState()
// Re-activate audio session for Now Playing
#if !os(macOS)
model.setupAudioSessionForNowPlaying()
model.updateNowPlayingInfo()
#endif
case MPV_EVENT_VIDEO_RECONFIG:
model.updateAspectRatio()
case MPV_EVENT_AUDIO_RECONFIG:
// Re-activate audio session when audio is reconfigured
#if !os(macOS)
model.setupAudioSessionForNowPlaying()
model.updateNowPlayingInfo()
#endif
case MPV_EVENT_SEEK:
isSeeking = true

View File

@@ -135,6 +135,12 @@ final class MPVClient: ObservableObject {
checkError(mpv_initialize(mpv))
#if !os(macOS)
// Set up audio session for Now Playing support
backend?.model.setupAudioSessionForNowPlaying()
backend?.model.updateNowPlayingInfo()
#endif
let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String)
var initParams = mpv_opengl_init_params(
get_proc_address: getProcAddress,

View File

@@ -1149,6 +1149,19 @@ final class PlayerModel: ObservableObject {
}
}
func setupAudioSessionForNowPlaying() {
#if !os(macOS)
do {
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.playback, mode: .moviePlayback, options: [])
try audioSession.setActive(true, options: [])
logger.info("Audio session activated for Now Playing")
} catch {
logger.error("Failed to set up audio session: \(error)")
}
#endif
}
func updateCurrentArtwork() {
guard let video = currentVideo,
let thumbnailURL = video.thumbnailURL(quality: Constants.isIPhone ? .medium : .maxres)