I am building a radio streaming app. The sound is working, including when the app is in the background and when the phone is locked. However, I can't get the MediaPlayer info to appear on the lock screen.
I am attempting to use a combination of AVPlayer
, AVAudioSession
, and MPNowPlayingInfoCenter
. I have looked at other questions on Stack Overflow (this one, especially), but it seems like their solutions aren't working for me.
I will try to lay out the important aspects of my app:
Info.plist
Added Required background modes: App plays audio or streams audio/video using AirPlay
AppDelegate.swift
I added the following code to didFinishLaunchingWithOptions
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
and then I overrode remoteControlReceived
override func remoteControlReceived(with event: UIEvent?) {
let rc = event!.subtype
print("does this work? \(rc.rawValue)")
}
Streaming Model
In a struct, I created a radio model using AVPlayer
. The stream is successfully sent to the ViewController.
ViewController
In viewDidLoad, the following code is run
override func viewDidLoad() {
super.viewDidLoad()
self.becomeFirstResponder()
UIApplication.shared.beginReceivingRemoteControlEvents()
}
I also overrode the following two functions in the ViewController, following another tutorial:
override var canBecomeFirstResponder: Bool {
return true;
}
override func remoteControlReceived(with event: UIEvent?) {
let type = event?.subtype
if (type == UIEvent.EventSubtype.remoteControlTogglePlayPause) {
//if ([self.radioManager.player.])
}
}
Lastly, I wrote the following function, that I've been adding to as I read new tutorials. I run this function after the stream has started playing:
func setNowPlayingInfo() {
UIApplication.shared.beginReceivingRemoteControlEvents()
MPRemoteCommandCenter.shared()
MPRemoteCommandCenter.shared().playCommand.addTarget {event in
return .success
}
MPRemoteCommandCenter.shared().pauseCommand.addTarget {event in
return .success
}
MPRemoteCommandCenter.shared().nextTrackCommand.addTarget {event in
return .success
}
MPRemoteCommandCenter.shared().previousTrackCommand.addTarget {event in
return .success
}
var nowPlayingInfo = [String: Any]()
// prepare title and subtitle
nowPlayingInfo[MPMediaItemPropertyTitle] = "Test"
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyTitle: self.trackTitle.text,
MPMediaItemPropertyArtist: self.nameLabel.text
]
}
One weird thing is that when I have added the line MPNowPlayingInfoCenter.default().playbackState = .playing
, the MediaPlayer is shown. When I've tested it out on an actual phone, though (compared to the simulator), the app stops, because that property is only for MacOS.
When the app is streaming, and I try opening Youtube, the YouTube video starts on mute. That makes me think the phone recognizes my app's AVAudioSession. Additionally, when I call print(MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPMediaItemPropertyTitle])
after running setNowPlayingInfo()
, the correct info is printed.
Any suggestions are greatly appreciated. I apologize for the really long question.
Edit
Maybe this issue is caused by my AVPlayer not being initialized properly? Here is the initialization code in a .swift
file that communicates with the View Controller through a delegate
struct RadioManager {
var player: AVPlayer = AVPlayer.init()
var streamPlaying = false
var badRadioURL = "http://server.badradio.biz:8000/"
var delegate: RadioManagerDelegate?
mutating func initializeRadio() {
let urlString = "\(badRadioURL)stream"
guard let url = URL.init(string: urlString)
else {
return
}
let playerItem = AVPlayerItem.init(url: url)
player = AVPlayer.init(playerItem: playerItem)
}
mutating func stream() {
print("loading")
player.play()
streamPlaying = true
}
Okay, I solved it. My app was fine; the issue was that the simulator wasn't acting like an actual device. When I tested it on an actual iPad, the lock screen info displayed perfectly. It still doesn't display on the simulator, though. Thank you for your time.