I have trying to play audio from URL. I tried both AVPlayer and AVAudioPlayer but none of them worked.
Here is the URL which I am trying to play.
Here is the code I am using.
// AVPlayer Code
self.avPlayerItem = AVPlayerItem.init(url: urlOfAudio)
self.avPlayer = AVPlayer.init(playerItem: avPlayerItem)
self.avPlayer.volume = 1.0
self.avPlayer.play()
// AVAudioPlayer
if let url = URL.init(string: escapeCharactorString){
do {
self.playerReference = try AVAudioPlayer.init(contentsOf: url)
guard let player = playerReference else {
return
}
player.volume = 1.0
player.prepareToPlay()
player.numberOfLoops = -1
player.play()
} catch let error {
}
}
None of them worked for me.
Please let me know where I am going wrong in it.
There is nothing wrong with your code, it is perfect but the issue is something related to server settings that audio file stored. Here is your working code which successfully playing an other mp3 file,
var avPlayer:AVPlayer?
var avPlayerItem:AVPlayerItem?
override func viewDidLoad() {
super.viewDidLoad()
// let urlstring = "http://www.noiseaddicts.com/samples_1w72b820/2514.mp3"
let urlstring = "https://s3.amazonaws.com/kargopolov/kukushka.mp3"
let url = NSURL(string: urlstring)
print("playing \(String(describing: url))")
avPlayerItem = AVPlayerItem.init(url: url! as URL)
avPlayer = AVPlayer.init(playerItem: avPlayerItem)
avPlayer?.volume = 1.0
avPlayer?.play()
}
So please try the mp3 file with different host it will solve your problem
The cause is Application Transport Security. You need to add:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsForMedia</key>
<true/>
</dict>
to your application's .plist file to load media from HTTP schemes. HTTPS schemes need no such exception.
Related
I am trying to play URL audio with AVPlayer. When I put a URL with .mp3 extension, it's working fine. but when I used a URL with no extension. it's not worked. Here's URL
Here's Code.
let url = URL(string: "https://redirector.googlevideo.com/videoplayback?ipbits=0&mn=sn-xcvoxoxu-aixe%2Csn-npoeen7k&ip=117.53.42.8&mm=31%2C29&ms=au%2Crdu&mv=m&mt=1547352278&id=o-AIUfw7X-7-vO4ebqBskvYlVvVmhmgp9WJBItzTwZ7c51&keepalive=yes&pl=24&source=youtube&fvip=6&requiressl=yes&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Ckeepalive%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csource%2Cexpire&itag=250&gir=yes&clen=4252061&txp=5511222&dur=490.541&lmt=1540081943361780&ei=G7k6XNuzA9TNVv6RjvgI&expire=1547373947&c=WEB&key=yt6&mime=audio%2Fwebm&initcwndbps=143750&signature=774AA79C717B4D9AC6A68743C5730CCBF6A8B9B4.0D91F9D2F80CF12A6623D260B9FC5BB3E69BBAE1&title=Coke-Studio-Season-10-Latthay-Di-Chaadar-Quratulain-Balouch-Farhan-Saeed")
let playerItem:AVPlayerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem: playerItem)
if player?.rate == 0
{
player.play()
} else {
player.pause()
}
Is there any other way to play audio in iOS with URL's that do not contains .mp3 or any other extension. I don't know why the player is not playing the audio file, there is no sound output on the device and there is no error shown.
I have a tableview which sets a UIImage to hold either an image url from AWS or a thumbnail generated from a video URL also from AWS. The video url refuses to display in my tableview and it throws this error in the debugger.
2017-12-29 12:20:37.053337-0800 VideoFit[3541:1366125] CredStore - performQuery - Error copying matching creds. Error=-25300, query={
class = inet;
"m_Limit" = "m_LimitAll";
"r_Attributes" = 1;
sync = syna;
}
When I click the cell to display either the image or video url, it segues to the video player correctly and then I get the error again and the triangular start button has a line through it signifying that there is no video to be played.
But when I print the url it has successfully passed so that is not the issue, the issue is AVPlayer can't handle my AWS video url for some reason. It is an https link so that means it must be secure but I already set my arbitrary loads to true
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Here is some code for displaying my videos in the videoPlayer VC and also the thumbnail generator function, perhaps there is some issue lying with these?
import UIKit
import AVKit
import MediaPlayer
class VideoPlayerVC: AVPlayerViewController {
var urlToPlay: String?
override func viewDidLoad() {
super.viewDidLoad()
print("Here is the url ---> \(String(describing: urlToPlay))")
playVideo()
}
private func playVideo() {
guard let urlFromString = urlToPlay else { print("No url to play") ;return }
let url = URL(string: urlFromString)
print("Here is the url to play ---> \(String(describing: url))")
let asset: AVURLAsset = AVURLAsset(url: url!)
let item: AVPlayerItem = AVPlayerItem(asset: asset)
let player: AVPlayer = AVPlayer(playerItem: item)
self.player = player
self.showsPlaybackControls = true
self.player?.play()
}
}
This is how I make the thumbnail, when my cellforRow atIndexPath method runs it throws this error for every video object in the tableview.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "sortedExerciseCell") as? SortedExerciseCell! {
// Do if check for videoURI and imageURI
if selectedExerciseArray[indexPath.row].imageURI != nil {
if let imageURI = URL(string: selectedExerciseArray[indexPath.row].imageURI!) {
print("It's a photo!")
// Using DispatchQueue.global(qos: .background).async loads cells in background
DispatchQueue.global(qos: .background).async {
let data = try? Data(contentsOf: imageURI)
DispatchQueue.main.async {
cell.exerciseImg.image = UIImage(data: data!)
}
}
}
} else {
if let videoURI = URL(string: selectedExerciseArray[indexPath.row].videoURI!) {
print("It's a video!")
print(videoURI)
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
cell.exerciseImg.image = self.thumbnailForVideoAtURL(url: videoURI)
// for every video object the above error is thrown!!!
}
}
}
}
cell.exerciseName.text = selectedExerciseArray[indexPath.row].name
return cell
} else {
return UITableViewCell()
}
}
// Used to just display the video thumbnail in cell, when clicked on will display video as needed
private func thumbnailForVideoAtURL(url: URL) -> UIImage? {
let asset = AVAsset(url: url)
let assetImageGenerator = AVAssetImageGenerator(asset: asset)
do {
print("Doing the video thumbnail from backend")
let imageRef = try assetImageGenerator.copyCGImage(at: CMTimeMake(1, 60) , actualTime: nil)
return UIImage(cgImage: imageRef)
} catch {
print("This is failing for some reason")
print("error")
return nil
}
}
I've looked at similar questions on stack overflow about this but none seem to give a complete answer on how to solve this problem, most chalking it up to an iOS 11 bug that can't be fixed or transport security (Already have arbitrary loads on so this can't be the issue..) anyone else have any approaches that might work?
Important note - My backend developer can only view the video url's from a webpage, in other words he must make a basic website to display the video after downloading it from the web. I'm not sure if this is standard procedure for handling video url's from AWS but I decided to try loading the url with "loadHTMLString" in a custom UIViewController conforming to WKUIDelegate, I see the video but the same situation happens where the triangular start button is crossed out signifying no video can be played. I'm not really sure what else I can try at this moment, any help is appreciated.
Here is one of the links I've pulled from my backend.
https://videofitapptestbucket.s3.us-west-2.amazonaws.com/100001427750
It seems that your problem is in file extension. DMS is not recognized by OS, it throws when creating image with assetgenerator.
Error Domain=AVFoundationErrorDomain Code=-11828 "Cannot Open" UserInfo={NSLocalizedFailureReason=This media format is not supported., NSLocalizedDescription=Cannot Open, NSUnderlyingError=0x6040000534d0 {Error Domain=NSOSStatusErrorDomain Code=-12847 "(null)"}}
Rename your files on server. The mp4 extension seems to work just fine with your file.
Also, subclassing AVPlayerViewController is generally not that great idea as Apple says that it will result in undefined behavior. (read: random mess). I would suggest to use class that have AVPlayer inside.
Try:
if let path = urlToPlay {
let url = URL(string: path)!
let videoPlayer = AVPlayer(url: url)
self.player = videoPlayer
DispatchQueue.main.async {
self.player?.play()
}
}
Call it in viewDidAppear() method
I am currently trying to play a video on iOS from a URL in Swift. URLs with endings like ".mp4" or ".m4v" work, but when I try to play a shared video link from Dropbox it doesn't.
I already changed the ending of the Dropbox link to "dl=1" but anyway nothing happens.
Playing a Youtube-video in a webview is not a solution for me, because I want the native iOS player.
Does anyone know what to do to play URLs from Dropbox or maybe recommend cloud services where this does work?
Thank you!
I didn't know dropbox streaming spec.
But if dropbox url doesn't have hint for playing like mp4,
you can use AVAssetLoaderDelegate like proxy server.
https://developer.apple.com/documentation/avfoundation/avassetresourceloaderdelegate
AVAssetLoaderDelegate excute when url has custom scheme.
If you use "foo" scheme, 'shouldWaitForLoadingOfRequestedResource' will be called. And you should make another request for dropbox with same http header.
Try like this
func play() {
let url = URL(string: "foo://bar.mp4")!
let asset = AVURLAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
asset.resourceLoader.setDelegate(self, queue: nil)
player.replaceCurrentItem(with: playerItem)
player.play()
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
var newRequest = URLRequest(url: URL(string: "dropbox url")!)
newRequest.allHTTPHeaderFields = loadingRequest.request.allHTTPHeaderFields
let sessionTask = URLSession.shared.dataTask(with: newRequest) { data, response, error in
if let responseData = data {
loadingRequest.dataRequest?.respond(with: responseData)
}
loadingRequest.finishLoading() // Let player know that finish loding
}
sessionTask.resume()
return true // Wait for sessionTask response.
}
I am using the AVPlayer to play the video from url.
func playVideoFromUrl(urlString: String){
let videoURL = URL(string: urlString)
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
let delegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
delegate.window?.rootViewController?.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
The url of video:- "http://gsn-input-dev.s3.amazonaws.com/public/video/00229/9229d4ad2a0c547e7bfa51e3fbef806f.mp4"
I am not getting any warning at console. Below is the screenshot of simulator. What I am doing wrong?
I have accomplished what you've wanted to do. Here is my approach:
First import AVFoundation, AVKit(I believe you had) then I have configured my viewcontroller like this
#IBOutlet weak var avPlayerView: UIView! // drag a UIView to view controller
var videoPlayer = AVPlayer()
var avPlayerViewController = AVPlayerViewController()
override func viewDidLoad() {
super.viewDidLoad()
let videoURL = URL(string: "http://gsn-input-dev.s3.amazonaws.com/public/video/00229/9229d4ad2a0c547e7bfa51e3fbef806f.mp4")
self.playVideo(url: videoURL!)
}
playVideo function is configured like below
func playVideo(url: URL) {
self.videoPlayer = AVPlayer(url: url)
self.avPlayerViewController = AVPlayerViewController()
self.avPlayerViewController.player = self.videoPlayer
avPlayerViewController.view.frame = avPlayerView.frame
self.addChildViewController(avPlayerViewController)
self.view.addSubview((avPlayerViewController.view)!)
}
Open your info.plist as Source Code
then add this to info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
screen shot is given below
Have you tried adding arbitrary load flag in your info.plist file as i see the url is a HTTP url and to make the HTTP url work, we need to specify it in app transportation security via info.plist as follows
Please try doing this as video is working perfectly fine with you code.
Read following document for more info on App Transportation Security
I hope this will help you :)
I recently found out that a device running iOS 14 using AVPlayer cannot play .mp4 files. A compatible video format that works on AVPlayer is .mov.
I also have had a trouble playing .mp4 files. When I made the URL end with .mp4 it works.
There is no error message when playing the sound. I put a print statement for testing, and the url is getting the right path. The play button clicks, and I hear a faint click sometimes, but that's it. No other sound comes out. I've tried different mp3 files. I get an error message if I delete the mp3 file. I've checked the volume.
The play button is in a second view controller. The main view controller has a table view. When user taps on the cell, it takes him to this view controller.
// DetailVC.swift
import AVFoundation
import UIKit
class DetailVC: UIViewController {
var duaPlayer = "" //is this correct???
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playbutton(sender: AnyObject) {
do {
let url = NSBundle.mainBundle().URLForResource("track1", withExtension: "mp3")
var duaPlayer = try AVAudioPlayer(contentsOfURL: url!)
duaPlayer.prepareToPlay()
print (url)
duaPlayer.volume = 0.5
duaPlayer.play()
}
catch
{ fatalError("err")}
}
i think that AVAudioPlayer do not support streaming. For live streaming use AVPlayer
//try this, it should work
var player = AVPlayer()
func configureView() {
let url = "http://yoururl.com"
let playerItem = AVPlayerItem( URL:NSURL( string:url ) )
player = AVPlayer(playerItem:playerItem)
player.rate = 1.0;
player.play()
}
in the other hand , with AVAudioPlayer you can download the mp3 file first than play it -->
let url = "http://YourURL/music/music.mp3"
let fileURL = NSURL(string:url)
let soundData = NSData.dataWithContentsOfURL(fileURL, options: nil, error: nil)
var error: NSError?
self.player = AVAudioPlayer(data: soundData, error: &error)
if player == nil {
if let e = error {
println(e.localizedDescription)
}
}
player.prepareToPlay()
player.volume = 1.0
player.delegate = self
player.play()
PS: Please keep in mind since iOS 9: App Transport Security (ATS) must be configured to accept non ssl connection.
add this code to your info.plist->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>