Certain songs not playing through MPMusicPlayerController - ios

I'm creating an app that can playback songs from Apple Music using the MPMusicPlayerController for people with a subscription.
I've run into a problem where certain songs fail to play whilst others work fine and I'm not sure why this would be the case.
The ID for a song that wouldn't work is 627511704. I've double checked some songs that don't work using the iTunes search API just to confirm that they do actually exist on the store which they did.
Here's the code where I attempt to queue the MPMusicPlayerController with an ID
func playWithAppleMusic(track: Track) {
guard let id = track.appleMusicID else { return }
self.appleMusicPlayer = MPMusicPlayerController.applicationMusicPlayer()
self.appleMusicPlayer?.prepareToPlay()
self.appleMusicPlayer?.setQueueWithStoreIDs([String(id)])
self.appleMusicPlayer?.currentPlaybackTime = 0
self.appleMusicPlayer?.repeatMode = .none
self.appleMusicPlayer?.shuffleMode = .off
self.appleMusicPlayer?.play()
self.startTimer()
}
I have also tried using an instance of MPMusicPlayerController.systemMusicPlayer() instead but that also did not work and wouldn't queue the song in the Apple Music app either.
Anybody know if I am doing something wrong here or is it just Apple's API being buggy again?
Thanks

Related

MPMusicPlayer Error Domain=MPErrorDomain Code=4?

I am having issue with Music player, most of the songs gives Error
Error Domain=MPErrorDomain Code=4
The testing device has Apple music subscription and the tracks gives error on the app they are working fine in Apple music app!
Here is the code:
let applicationMusicPlayer = MPMusicPlayerController.systemMusicPlayer()
applicationMusicPlayer.setQueueWithStoreIDs([ID])
if #available(iOS 10.1, *)
{
applicationMusicPlayer.prepareToPlay { (error) in
if (error != nil)
{
print("[MUSIC PLAYER] Error preparing : \(String(describing: error))")
return
}else
{
self.start_timer();
self.applicationMusicPlayer.play()
}
}
}else
//Play directly ios below version 10.1
{
self.applicationMusicPlayer.play()
}
}
But what I've tried, when the track gives this error, I went to Apple music player and played it from there its worked, then I came back to my app and play it from my app its worked also fine, so I need to go to Apple music app to play tracks not playing in my app to make them work in my app! That's so weird any idea why?
PS: the testing device has Apple music subscription
I had some similar problems when adding songs to a playlist, solved it by using:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
// Code
}
i would play around with waiting a bit before or after preparing.
5 seconds may be too much, but you can start from there

MPRemoteCommandCenter not generating remote control events MPMusicPlayerController.applicationMusicPlayer()

I'm using MPRemoteCommandCenter and MPMusicPlayerController.applicationMusicPlayer on the iPhone.
I'm trying to receive remote control events when the user is playing music and double taps on the headphone button.
If I use AVAudioPlayer, the remote commands are received perfectly.
However, if I use MPMusicPlayerController with any of its players (systemMusicPlayer, applicationMusicPlayer, or applicationQueuePlayer) the the commands do not get received. They appear to get gobbled up. For example when I double tap the remote, the music will toggle between play and stop. Instead, I need the remote events sent to my app.
Below is a sample app with my code. In the info.plist I've specified the required background mode for an app that plays audio (although its not necessary).
import UIKit
import MediaPlayer
class ViewController: UIViewController {
var mpPlayer:MPMusicPlayerController!
func remoteHandler() {
print("success")
}
override func viewDidLoad() {
super.viewDidLoad()
mpPlayer = MPMusicPlayerController.applicationMusicPlayer()
//mpPlayer = MPMusicPlayerController.systemMusicPlayer()
assert(mpPlayer != nil)
let cc = MPRemoteCommandCenter.shared()
print("cc = \(cc)")
cc.nextTrackCommand.isEnabled = true
cc.nextTrackCommand.addTarget(self, action: #selector(ViewController.remoteHandler))
cc.previousTrackCommand.isEnabled = true
cc.previousTrackCommand.addTarget(self, action: #selector(ViewController.remoteHandler))
cc.playCommand.isEnabled = true
cc.playCommand.addTarget(self, action: #selector(ViewController.remoteHandler))
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
print("AVAudioSession successfully set AVAudioSessionCategoryPlayback")
} catch let error as NSError {
print("AVAudioSession setCategory error: \(error.localizedDescription)")
}
mpPlayer.setQueueWithStoreIDs(["270139033"]) // requires iOS 10.3
mpPlayer.play()
}
}
Output is:
cc = 0x123e086c0
AVAudioSession successfully set AVAudioSessionCategoryPlayback
remoteHandler is never called.
From the Apple Developer web site.
When you use either the system or application player, you do not get
event notifications. Those players automatically handle events.
So there is no way to receive remote control events if you use MPMusicPlayerController. Looking forward to see this feature! Right now MPMusicPlayerController is the only way to play Apple Music songs.

AVAudioPlayer being interrupted by MPMusicPlayerController

I am writing an app that uses both AVAudioPlayer to play local mp3 files and MPMusicPlayerController to play system / Apple music / iTunes music.
I am maintaining a custom nowPlayingMP3Item that is being set after I play the song using AVAudioPlayer.
I could check the playback state of the MusicController, but I'd need to reload the UI if it changed from mp3 to system music...
Is there any way to observe (maybe the audio session) or something and determine whether mp3 or system music is playing and update the UI accordingly?
Thanks for any help
When there is an interruption,the audio will be paused and your audio session will been deactivated. If your app contains playing interface, you will need to update the interface. When the interruption ends, you can activate audio session and resume playback of the audio.
NotificationCenter.default.addObserver( forName: .AVAudioSessionInterruption, object: nil, queue: nil) { n in
let why = AVAudioSessionInterruptionType( rawValue: n.userInfo![ AVAudioSessionInterruptionTypeKey] as! UInt)!
if why = = .began {
// began
}
else {
// ended
}
}

ReplayKit sharing video to facebook has no commentary

I'm recording a video with commentary, and I'm using replaykit. Everything is working fine on iPhone, but when I share to facebook, my videos has no sound at all. I've downloaded a video to my mac and it's m4v with sound. But when I'm trying to share it from my mac to facebook it doesn't has sound too. On youtube it works very good. Not sure is there any way I can fix it? Can I record a screen and commentary without replaykit and pass app review?
Start:
RPScreenRecorder.shared().isMicrophoneEnabled = true
RPScreenRecorder.shared().startRecording { (error) in
if error == nil {
//TODO: show RECORDING view
print("start recording")
}
}
Stop:
RPScreenRecorder.shared().stopRecording { (previewViewController, error) in
if let previewVC = previewViewController, error == nil {
previewVC.previewControllerDelegate = self
self.present(previewVC, animated: true, completion: nil)
}
}
Seems to be Fixed by Apple
(on the latest IOS 11 Beta's update)
Ofir Malachi I will write it as an answer, I used some parts of Spitfire library, I'm doing a screenshot of this part of the screen I want to "record" every 0.1 second. I'm merging those images to a video. In the same time I'm recording audio. At the end I've got "output.mov" and "recording.m4a". I'm using AVAssetExportSession to merge it asynchronously to the mp4 file.

AVAudioSession: Some Bluetooth devices are not working properly on my App

I'm developing a swift audio/video and text chat iOS App using AVAudioSession.
Whenever I select to use some Bluetooth devices the sound played on the device is not the App audio stream. They play only the system sound sent by text chat library whenever messages are sent/received instead. It doesn't happen on all Bluetooth devices, on some of them everything works fine. On Builtin Mic and Speaker the App works fine too.
Here are the most important methods from my class to manage the device:
class MyAudioSession
{
private var mAudioSession: AVAudioSession;
init!()
{
self.mAudioSession = AVAudioSession.sharedInstance();
do {
try self.mAudioSession.setActive(false);
try self.mAudioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: .AllowBluetooth);
try self.mAudioSession.setMode(AVAudioSessionModeVideoChat);
try self.mAudioSession.setActive(true);
}
catch {
return nil;
}
}
func switchToDevice(device: AVAudioSessionPortDescription!) -> Bool
{
var ret = false;
if (device != nil) {
do {
try self.mAudioSession.setPreferredInput(device);
ret = true;
}
catch {
self.logSwitch(device, error: error);
}
}
return ret;
}
}
I'd like to understand why my App is not working fine on just SOME Bluetooth devices. These same devices work properly on the other Apps on my Cel.
I did another test: I changed all of this for MPVolumeView, and exactly the same issue occurred, so the problem seems to be on audio player.
Could anybody give me a suggestion to fix this ?
Thx.
Jorg,
While this might not be the best answer I have been able to overcome the weird Bluetooth issues. My problem seems to be similar to yours as I too was using:
AVAudioSessionCategoryPlayAndRecord
This was causing issues for me on some Bluetooth devices (not all but some).
What I wound up doing was setting the Category to:
AVAudioSessionCategoryPlayback
Then when ever I needed to record I would switch the Category over to:
AVAudioSessionCategoryRecord
Then back to Playback after completing my recording.
This was the only way at this time I could get a consistent result from switching between the different outputs (Speaker, Headphones, Bluetooth).
Hope that helps some. Guessing this is a bug in the "AVAudioSessionCategoryPlayAndRecord"

Resources