Play IOS Music Library Content Using AVFoundation - ios

I'm attempting to write an IOS app that will play my iPhone music library content, showing artwork, and "announcing" title, artist, etc.
I have it working nicely using Apple's Media Player framework. I can display Playlist names and queue the songs in a selected Playlist.
I use the "MPMusicPlayerControllerNowPlayingItemDidChange" observer notification to pause playback, retrieve metadata, and do the announcements via AVSpeechSynthesizer.
I was a happy camper until I ran into the dreaded "Media Player framwork doesn't respond to observer notifications in background" issue.
So, I started looking at the AVFoundation Framework. I found a sample that plays local song files via URLs in the background and.
I'm failing miserably in attempting to retrieve Music Library content via the AVFoundation.
I have also failed in supplying content retrieved via the Media Player framework to the AVFoundation player.
(Note: The URLs retrieved from MPMediaItem are of a bogus "ipod-library://item/item.m4a?id=#########################" format. Creating AVPlayerItem with this "URL" doesn't work.)
Has anyone managed to accomplish this? I'm developing for my own usage. I have no intention of posting the app in Apple's App Store, so I'm willing to use hidden APIs or un-Apple approved methodology.
A Swift code example would be great. (Objective-C not so much)

Having fetched an MPMediaItem from the user's library, obtain its assetURL. Creating an AVPlayer from the resulting URL does work.
Actual code from one of my example apps:
func oneSong () -> (URL?, String?) {
let query = MPMediaQuery.songs()
// always need to filter out songs that aren't present
let isPresent = MPMediaPropertyPredicate(value:false,
forProperty:MPMediaItemPropertyIsCloudItem,
comparisonType:.equalTo)
query.addFilterPredicate(isPresent)
let item = query.items?[0]
return (item?.assetURL, item?.title)
}
#IBAction func doPlayOneSongAVPlayer (_ sender: Any) {
let (url, title) = self.oneSong()
if let url = url, let title = title {
self.avplayer = AVPlayer(url:url)
self.avplayer.play()
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyTitle : title
]
}
}

Related

How to play audio files from Google Drive (Swift 5)

In my project I use a Google Drive API. I get a list of the user's files and can save them to the device memory.
I also want to be able to play audio files directly from Google Drive, but I just can't do it. The AVPlayer doesn't want to play the audio file using the URL link, which I transfer to him. But if I paste this link into any browser, then the track is played.
Has anyone encountered this and knows how to fix the problem? I would be grateful for any help.
My code looks like this (it's a simplified version):
import AVKit
class MyVC: UIViewController {
...
var player: AVPlayer!
...
private func playTrack() {
let url = URL(string: "https://drive.google.com/uc?export=open&id=XXXXX" //where XXXXX is an item id
let playerItem: AVPlayerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem: playerItem)
player!.play()
}
}
For example URL link which I transfer to the AVPlayer looks like this:
https://drive.google.com/uc?export=open&id=1JzuAhQ-7R01wLhtD8zEN_sC5nvFlt7wU
But if I paste it into the browser it automatically changes and looks like this:
https://doc-0g-1s-docs.googleusercontent.com/docs/securesc/anu2dlv0j1ugsoh1pb6b8qpkkt7k1j6k/hp3dnmru336i1cpkk4f5p4bstc83b30f/1602827400000/02426681720429398713/02426681720429398713/1JzuAhQ-7R01wLhtD8zEN_sC5nvFlt7wU?e=open&authuser=0&nonce=4dd9dhoo6he8g&user=02426681720429398713&hash=o87f0k3t4iv19ugae899urmcjd14ogiq
Maybe it's important.
You files should be shared by a direct link in Google Drive to play it so you can make it manually or using API e.g.:
And then use direct links in format: https://drive.google.com/uc?export=open&id=XXXXX.

How can you extract the overall stream title from AVPlayer?

I'm using AVPlayer and AVPlayerItem in Swift to play internet radio streams.
Observing the "timedMetadata" gives me the track currently playing, however I never seem to get a handle of the radio title
See this example using VLC, I can obtain the "Now playing" part easily with timedMetadata, however I never receive the overall title of the radio "Title".
What am I missing, should I be observing something else to access the stream's/shoutcast/icecast information?
Try this:
let title = AVMetadataItem.metadataItems(from: urlAsset.commonMetadata, withKey: AVMetadataKey.commonKeyTitle, keySpace: AVMetadataKeySpace.common).first?.value as? String
print(title)
This works for media I have with metadata in the title (set using the Apple Music app). If this doesn't work for your media, please post it somewhere online along with your current code.

Free hosting video platform compatible with AVPlayer support

I am trying to play a video from my iOS app when tapping a button, but I was wondering how and where I can host my video (for free) so that I can play the video in an AVPlayer using the URL. I tried hosting the video on youtube, and setting the AVPlayer URL to the youtube video URL, but the player loads forever. I included my code, it's functional, I just need to know where I can upload my video to get a proper URL.
#IBAction func didTapPlayButton(_ sender: UIButton) {
guard let url = URL(string: "") else {
return
}
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
let player = AVPlayer(url: url)
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
// Modally present the player and call the player's play() method when complete.
present(controller, animated: true) {
player.play()
}
}
You need to host and serve your video as a binary file.
You can use an object storage (e.g. Firebase Storage or AWS S3) or serve the file through a web API.
Just set the correct Content-Type (e.g. "video/mp4" to help the player recognise the binary file type)
You can then initiate your AVPlayer with the URL of the video.
Please note that Firebase Storage has a very generous free tier, it might be all you need.
For example:
You can take a look at this video file:
https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4
This file is hosted as a binary and the Content-Type is set to video/mp4.
Try to initiate your AVPlayer with the above URL and see that it works.

To play Youtube Video in iOS app

I want to play youtube videos in my iOS App. I searched for that but the only solution I found is to embed youtube videos in the iOS app, in which video plays in webview, so in that, we can scroll and also play other videos which are in suggestion.
I don't want to play video in webview, I want to play video just like it plays in player and user cannot scroll it.
Is there any solution for that in Swift and also I don't want to use libraries which are against terms and condition of Youtube
Here's another solution if you don't want to use the API provided by YouTube and instead continue using a UIWebView.
YouTube has functionality to load any video in fullscreen in a webview without any of the scrolling features using a URL in the format https://www.youtube.com/embed/<videoId>.
For example, to load Gangnam Style using this method, simply direct the UIWebView to the URL https://www.youtube.com/embed/9bZkp7q19f0.
The API that YouTube provides to embed videos in iOS apps is indeed written in Objective-C, but it works just as well in Swift.
To install the library via CocoaPods, follow the CocoaPods setup instructions and add the following line to your Podfile:
pod ‘youtube-ios-player-helper’, ‘~> 0.1’
Once you have run pod install, be sure to use the .xcworkspace file from now on in Xcode.
To import the pod, simply use the following import statement at the top of your Swift files:
import youtube_ios_player_helper
You can then create youtube player views as follows:
let playerView = YTPlayerView()
You can include this view in your layouts as you would any other UIView. In addition, it includes all of the functions listed in the YouTube documentation. For instance, to load and play a video, use the following function:
playerView.load(withVideoId: videoId);
Where videoId is the string id found in the URL of the video, such as "9bZkp7q19f0".
There also are solutions for playing Youtube Videos in an app on Github.
Like this one: https://github.com/rinov/YoutubeKit
Or this one: https://github.com/gilesvangruisen/Swift-YouTube-Player
Just simply add the pod for the project that you want to use, install the pod in terminal, and you can use the functionality in that project.
Hope that this is helpful.
Play youtube video in Swift 4.0
if let range = strUrl.range(of: "=") {
let strIdentifier = strUrl.substring(from: range.upperBound)
let playerViewController = AVPlayerViewController()
self.present(playerViewController, animated: true, completion: nil)
XCDYouTubeClient.default().getVideoWithIdentifier(strIdentifier) {
[weak playerViewController] (video: XCDYouTubeVideo?, error: Error?) in
if let streamURLs = video?.streamURLs, let streamURL =
(streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming] ??
streamURLs[YouTubeVideoQuality.hd720] ??
streamURLs[YouTubeVideoQuality.medium360] ??
streamURLs[YouTubeVideoQuality.small240]) {
playerViewController?.player = AVPlayer(url: streamURL)
} else {
self.dismiss(animated: true, completion: nil)
}
}
}

URLs of Media Bought on iTunes

I have created an application that gets all of the songs on a device, puts some of their information in a UITableView, then plays a song of a selected cell using an AVAudioPlayer. For some reason however, it seems as though three of the songs on my device do not have urls. These songs were more recently bought, perhaps in the last two months. See the code below.
//get all the songs
var songsList: [MPMediaItem] = MPMediaQuery.songsQuery().items!
if let url = song.valueForProperty(MPMediaItemPropertyAssetURL) as! NSURL? {
self.player = try! AVAudioPlayer(contentsOfURL: url)
let playing: Bool = player.play()
print("The audio play status: " + String(playing))
}
else {
print("Failed to cast to URL")
}
For some reason, these three songs fail the type cast from AnyObject? to NSURL? meaning that the url must not exist on the device? I do not understand. My only guess is that I bought them from iTunes on another Macintosh device and they were stored on there via some cloud transfer through my iTunes account. Any explanation would be a great help.
You can't get an asset URL if the track is
A) Not on your device -- at least not completely -- but available to download/stream on demand. This can arise by not being completely played; being purchased on other devices/via Family Sharing; being an Apple Match track; yadayadayada.
B) DRM-protected. That's getting pretty rare these days I thought, but it was a big thing back a few years. If the file has an .m4p extension, that is definitely the problem. There's reports that it arises with .m4a files as well, and showing up in iTunes as "Purchased AAC audio file" indicates that it figures you're not allowed to get at said audio.

Resources