I have uploaded few files on parse framework and I am live streaming those files and play them in AVPlayer.
let url = currentAudioPath
let playerItem = AVPlayerItem( URL:NSURL( string:url ) )
player1 = AVPlayer(playerItem:playerItem)
player1.rate = 1.0;
self.configurePlayer()
player1.play()
I have not downloaded the entire file at once. But is there a way to retrieve the length of the song?
"AVPlayerItem" has a ".duration" property that might help you.
Look at the notes though: You won't be able to get the duration "until the status of the AVPlayerItem is AVPlayerItemStatusReadyToPlay." You could also set a KVO on the property so you could update your UI once the item duration is determined by the AVFoundation layer.
Related
I try to get file list from the Music Library (iPod Music Library), but I can't do it, my list is always empty. I sure that I have tracks in Music Library, I check it in other app - and it works. But as I remember that application sent me a request to access the Music Library. Perhaps I also need to create such a request? Help me solve the problem. I use this code to get file list:
func fetchFileList() {
let mediaItems = MPMediaQuery.songs().items
let mediaCollection = MPMediaItemCollection(items: mediaItems ?? [])
print("mediaCollectionItems: \(mediaCollection.items)") //It's always empty
//Then I'd like to get url of the track
//let item = mediaCollection.items[0]
//let pathURL = item.value(forProperty: MPMediaItemPropertyAssetURL) as? URL
//print("pathURL: \(pathURL)")
}
If you want to access the Music Library, you have to add NSAppleMusicUsageDescription key to your Info.plist with a description about what you want to do with the music.
Se apple documentation for more info: MediaPlayer Documentation
I'm trying to get my audio file duration to display on my app but my code always return 0. I hope there is a method that notifies me when the AVplayer has data from the file and then I can call my code after that to get the data. Any suggestions?
func loadAudioUrl() {
guard let url = URL(string: sampleShortAudioUrl) else {return}
audioPlayer = AVPlayer(url: url)
audioPlayer?.play()
if let duration = audioPlayer?.currentItem?.duration{
print(duration)
}
}
You can get duration, but you need to wait because content is loading. Your code assumes that it is loaded instantly.
You need to use AVPlayerItem with AVPlayer.
When AVPlayerItem status is ready to play, you can ask for duration. Complete code example is right from Apple here:
AVPlayerItem
You can't get duration from a remote audio url , you must store it's duration remotely in your database and grap it while listening or downloading . . .
I'm making an iOS app in Swift that plays a video in a loop in a small layer in the top right corner of the screen which shows a video of specific coloured item. the user then taps the corresponding coloured item on the screen. when they do, the videoName variable is randomly changed to the next colour and the corresponding video is triggered. I have no problem raising, playing and looping the video with AVPlayer, AVPlayerItem as seen in the attached code.
Where I'm stuck is that whenever the next video is shown, previous ones stay open behind it. Also, After 16 videos have played, the player disappears altogether on my iPad. I've tried many suggestions presented in this and other sites but either swift finds a problem with them or it just doesn't work.
So question: within my code here, how do I tell it "hey the next video has started to play, remove the previous video and it's layer and free up the memory so i can play as many videos as needed"?
//set variables for video play
var playerItem:AVPlayerItem?
var player:AVPlayer?
//variables that contain video file path, name and extension
var videoPath = NSBundle.mainBundle().resourcePath!
var videoName = "blue"
let videoExtension = ".mp4"
//DISPLAY VIDEO
func showVideo(){
//Assign url path
let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension)
playerItem = AVPlayerItem(URL: url)
player=AVPlayer(playerItem: playerItem!)
let playerLayer=AVPlayerLayer(player: player!)
//setplayser location in uiview and show video
playerLayer.frame=CGRectMake(700, 5, 350, 350)
self.view.layer.addSublayer(playerLayer)
player!.play()
// Add notification to know when the video ends, then replay it again. THIS IS A CONTINUAL LOOP
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil)
{ notification in
let t1 = CMTimeMake(5, 100);
self.player!.seekToTime(t1)
self.player!.play()
}
}
`
I adapted #Anupam Mishra's Swift code suggestion. It wasn't working at first but finally figured I had to take the playerLayer outside the function and close the playerLayer after I set the player to nil. Also. instead of using 'if(player!.rate>0 ...)' which would no doubt still work, I created a variable switch to indicate when to say "kill the player AND the layer" as seen below. It may not be pretty but it works! The following is for absolute newbies like myself - WHAT I LEARNED FROM THIS EXPERIENCE: it seems to me that an ios device only allows 16 layers to be added to a viewController (or superLayer). so each layer needs to be deleted before opening the next layer with its player unless you really want 16 layers running all at once. WHAT THIS CODE BELOW ACTUALLY DOES FOR YOU: this code creates a re-sizable layer over an existing viewController and plays a video from your bundle in an endless loop. When the next video is about to be called, the current video and the layer are totally removed, freeing up the memory, and then a new layer with the new video is played. The video layer size and location is totally customizable using the playerLayer.frame=CGRectMake(left, top, width, height) parameters. HOW TO MAKE IT ALL WORK: Assuming you've already added your videos to you bundle, create another function for your button tap. in that function, first call the 'stopPlayer()' function, change the 'videoName' variable to the new video name you desire, then call the 'showVideo()' function. (if you need to change the video extension, change 'videoExtension' from a let to a var.
`
//set variables for video play
var playerItem:AVPlayerItem?
var player:AVPlayer?
var playerLayer = AVPlayerLayer() //NEW playerLayer var location
//variables that contain video file path, name and extension
var videoPath = NSBundle.mainBundle().resourcePath!
var videoName = "blue"
let videoExtension = ".mp4"
var createLayerSwitch = true /*NEW switch to say whether on not to create the layer when referenced by the closePlayer and showVideo functions*/
//DISPLAY VIDEO
func showVideo(){
//Assign url path
let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension)
playerItem = AVPlayerItem(URL: url)
player=AVPlayer(playerItem: playerItem!)
playerLayer=AVPlayerLayer(player: player!) //NEW: remove 'let' from playeLayer here.
//setplayser location in uiview and show video
playerLayer.frame=CGRectMake(700, 5, 350, 350)
self.view.layer.addSublayer(playerLayer)
player!.play()
createLayerSwitch = false //NEW switch to tell if a layer is already created or not. I set the switch to false so that when the next tapped item/button references the closePlayer() function, the condition is triggered to close the player AND the layer
// Add notification to know when the video ends, then replay it again without a pause between replays. THIS IS A CONTINUAL LOOP
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil)
{ notification in
let t1 = CMTimeMake(5, 100);
self.player!.seekToTime(t1)
self.player!.play()
}
}
//NEW function to kill the current player and layer before playing the next video
func closePlayer(){
if (createLayerSwitch == false) {
player!.pause()
player = nil
playerLayer.removefromsuperlayer()
}
}
`
Why don't just use replaceCurrentItemWithPlayerItem on your player ? You will keep the same player for all your videos. I think it's a better way to do.
Edit : replaceCurrentItemWithPlayerItem has to be call on the main thread
Before moving on next track first check, is player having any videos or music, to stop it do the following checks:
Swift Code-
if player!.rate > 0 && player!.error == nil
{
player!.pause()
player = nil
}
Objective-C Code-
if (player.rate > 0 && !player.error)
{
[player setRate:0.0];
}
I am trying to use an AVPlayer to play a video that has been recorded in my app. However, the player won't play the video. I know for a fact that this is a properly recorded mp4 file, because I can take it and play it on my Mac just fine. Here's the setup for the player:
let documents = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let URL = NSURL(fileURLWithPath: "tempVideo", relativeToURL: documentsDirectory)
let asset = AVAsset(URL: URL)
let item = AVPlayerItem(asset: asset)
//videoPlayer is a property on the view controller being used
videoPlayer = AVPlayer()
//videoPlayerLayer is a property on the view controller being used
videoPlayerLayer = AVPlayerLayer(player: videoPlayer)
videoPlayerLayer.frame.size = view.frame.size
videoPlayerLayer.backgroundColor = UIColor.redColor().CGColor
view.layer.addSublayer(videoPlayerLayer!)
//wait 5 seconds
videoPlayer.play()
I know for sure that the videoPlayer is, in fact, ready to play, because I've checked its status property. I also know that videoPlayerLayer has properly been added to view.layer because its visible and takes up the whole screen. When I call videoPlayer.play(), the music playing on the device stops, but videoPlayerLayer doesn't show anything.
Any ideas? Thank you in advance for the help!
EDIT: I forgot to show that videoPlayerLayer is indeed connected to videoPlayer, I have updated my question to reflect this.
The correct answer was given by #Dershowitz123, but he or she left it in a comment so I can't mark it as correct. The solution was to change the URL to include the .mp4 extension. Thank you for your help.
I am looking for a swift coding playing sound out of the player list and not sounds added as resource to your project.
I mainly found the usage of
NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sound_name", ofType: "wav"))
println(alertSound)
but for this you need to have the sound file in your bundle. But I couldn't find any example
selecting audio files bought thru itunes and play them.
Any idea how to do this? Can I access my music layer playlist files and using them in my app?
Thanks for any code lines.
rpw
These music files are represented by MPMediaItem instances. To fetch them, you could use an MPMediaQuery, as follows:
let mediaItems = MPMediaQuery.songsQuery().items
At this point, you have all songs included in Music App Library, so you can play them with a MPMusicPlayerController after setting a playlist queue:
let mediaCollection = MPMediaItemCollection(items: mediaItems)
let player = MPMusicPlayerController.iPodMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()
You might need to filter songs by genre, artist, album and so on. In that case, you should apply a predicate to the query before fetching the media items:
var query = MPMediaQuery.songsQuery()
let predicateByGenre = MPMediaPropertyPredicate(value: "Rock", forProperty: MPMediaItemPropertyGenre)
query.filterPredicates = NSSet(object: predicateByGenre)
let mediaCollection = MPMediaItemCollection(items: query.items)
let player = MPMusicPlayerController.iPodMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()
Cheers!