Read data from file swift - ios

I was trying to read a file xyz.m4a and trying to play it. But I have an error
2018-04-24 18:11:20.010927+0530 Demo[10807:690526] NSURLConnection finished with error - code -1002
2018-04-24 18:11:20.327008+0530 Demo[10807:688427] CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
Error: The file “xyz.m4a” couldn’t be opened.
Here is my code:
func audioMethod() {
let fileName = "xyz.m4a",
audioFile = getDocumentsURL().appendingPathComponent(fileName)
if !FileManager.default.fileExists(atPath: audioFile.path) {
print("We have no file !!!!!")
}
do {
let audioData = try Data(contentsOf: audioFile)
if audioPlayer == nil {
audioPlayer = try AVAudioPlayer.init(data: audioData, fileTypeHint: "m4a")
}
audioPlayer?.play()
} catch let error {
print("Error: " + error.localizedDescription)
}
}
func getDocumentsURL() -> URL {
let urlStr = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let url = URL(string: urlStr!)
return url!
}
If I pass that URL direct in AVAudioPlayer as AVAudioPlayer.init(contentsOf: audioFile) then it works fine.
I have tried everything. But nothing works. Please let me know what is wrong with my code.

if let path = Bundle.main.path(forResource: "videoplayback", ofType: "mp4"){
let video = AVPlayer(url: URL(fileURLWithPath:path))
let videoPlayer = AVPlayerViewController()
videoPlayer.player = video
present(videoPlayer,animated: true,completion: {
video.play()
})
}
Add that Video in File Explorer
Then try with above code

Related

Saving video in locally (directory) in Swift?

I try to save given video locally after then I need those saved videos for playing video in my app. I can't handle the saving video. Here is my saving try :
func saveVideoDocumentDirectory(url : URL){
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(".MOV")
do{
let videoData = try Data(contentsOf: url)
fileManager.createFile(atPath: paths as String, contents: videoData, attributes: nil)
}catch{
//
}
}
here is the get file try
func getVideo(){
let fileManager = FileManager.default
let videoPAth = (self.getDirectoryPath() as NSString).appendingPathComponent(".MOV")
if fileManager.fileExists(atPath: videoPAth){
print(videoPAth)
play(url: URL(string: videoPAth)!)
}else{
print("No Video")
}
}
here is my play video func :
func play(url : URL)
{
let player = AVPlayer(url: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
{
playerViewController.player!.play()
}
}
Instead of Filemanager.createFile(), try using write instead.
let videoData = try Data(contentsOf: url)
try videoData.write(to: paths, options: .atomic)
Also, I recommend creating a folder first (from this answer).
extension URL {
static func createFolder(folderName: String) -> URL? {
let fileManager = FileManager.default
// Get document directory for device, this should succeed
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
// Construct a URL with desired folder name
let folderURL = documentDirectory.appendingPathComponent(folderName)
// If folder URL does not exist, create it
if !fileManager.fileExists(atPath: folderURL.path) {
do {
// Attempt to create folder
try fileManager.createDirectory(atPath: folderURL.path,
withIntermediateDirectories: true,
attributes: nil)
} catch {
// Creation failed. Print error & return nil
print(error.localizedDescription)
return nil
}
}
// Folder either exists, or was created. Return URL
return folderURL
}
// Will only be called if document directory not found
return nil
}
}
Then, you can save like this:
guard let folderURL = URL.createFolder(folderName: "StoredVideos") else {
print("Can't create url")
return
}
let permanentFileURL = folderURL.appendingPathComponent(nameOfYourFile).appendingPathExtension("MOV")
let videoData = try Data(contentsOf: url)
try videoData.write(to: permanentFileURL, options: .atomic)
This will save you the hassle of NSSearchPathForDirectoriesInDomains.

Audio Stream via firebase

I have uploaded some songs in firebase Storage directly,I just want to stream the song in AVAudioPlayer.
Below is the code which I am trying:
var mainRef: FIRStorageReference {
return FIRStorage.storage().reference(forURL: "gs://musicapp-d840c.appspot.com")
}
var audioStorageRef: FIRStorageReference{
return mainRef.child("SongsPath")
}
audioStorageRef.downloadURL { url, error in
if let error = error {
print(error.localizedDescription)
} else {
if let url = url {
do {
self.audioPlayer = try AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: String(describing: url)) as URL)
self.audioPlayer.play()
} catch {}
let storyboard = UIStoryboard(name: "AudioPlayer", bundle: nil)
let audioVc = storyboard.instantiateViewController(withIdentifier: "AudioPlayerViewController") as! AudioPlayerViewController
audioVc.playThisSong = String(describing: url)
self.present(audioVc, animated: false, completion: nil)
}
}
}
Here the song url from the firebase is passing but it is skipping the self.audioPlayer.play. ,I just want to stream the audio. Can I get a proper solution for this?
This is not an answer for streaming.
This is an answer for downloading the file, storing it locally, and playing the audio after the file has finished downloading.
Get a Firebase storage reference using a path string with the file extension. Get a file url to store it on the device using the same path string that we use for the Firebase storage reference.
Initiate the download task using write(toFile: URL). Store the download task in a variable to add observers. When the download is successful, play the audio.
In Swift 4:
var player: AVAudioPlayer?
let pathString = "SongsPath.mp3"
let storageReference = Storage.storage().reference().child(pathString)
let fileUrls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let fileUrl = fileUrls.first?.appendingPathComponent(pathString) else {
return
}
let downloadTask = storageReference.write(toFile: fileUrl)
downloadTask.observe(.success) { _ in
do {
self.player = try AVAudioPlayer(contentsOf: fileUrl)
self.player?.prepareToPlay()
self.player?.play()
} catch let error {
print(error.localizedDescription)
}
}
This is minimal code. Implement error handling as you see fit.
Firebase example of downloading locally

How to play mp3 file in swift3?

I have started to learn ios development and am stuck in one place. My code to play mp3 file is
var bombSoundEffect: AVAudioPlayer!
let path = Bundle.main.path(forResource: "faded", ofType:"mp3")!
let url = NSURL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: (url as NSURL) as URL)
bombSoundEffect.play()
} catch {
print("couldn't load file :(")
}
if bombSoundEffect != nil {
bombSoundEffect.stop()
bombSoundEffect = nil
}
However, when I click on the button, my file doesn't play. The song is playing perfectly normally.
Try with the follow code:
var bombSoundEffect: AVAudioPlayer?
func playAudio() {
let url = Bundle.main.url(forResource: "faded", withExtension: "mp3")!
do {
bombSoundEffect = try AVAudioPlayer(contentsOf: url)
guard let bombSound = bombSoundEffect else { return }
bombSound.prepareToPlay()
bombSound.play()
} catch let error {
print(error.localizedDescription)
}
}
There's lots wrong with your code, but it's a sunny day, so try something like this…
func playSound() {
guard let url = Bundle.main.url(forResource: "faded", withExtension: "mp3") else { return }
let bombSoundEffect = try? AVAudioPlayer(contentsOf: url)
bombSoundEffect?.play()
}

Play an mp3 file downloaded to filemanager using AVPlayer

I'm working on a project in swift3 and I have a particular UIViewController to download an mp3 to my filemanager and using that path saved I wants to play an mp3 using AVPlayer. My code doesn't work, I think Im missing something. How would I achieve this?. My code to download the file to the filemanager as below
func downloadSong() {
if let audioUrl = URL(string: "https://www.googleapis.com/download/storage/v1/b/feisty-beacon-159305.appspot.com/o/Aal%20Izz%20Well%20-%20Remix(MyMp3Song).mp3?generation=1490097740630162&alt=media") {
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!//since it sys first this may only plays the first item
// destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
print("destinationUrl is :",destinationUrl)
// to check if it exists before downloading it
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("The file already exists at path")
self.dest = destinationUrl.path
// if the file doesn't exist
} else {
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: location, to: destinationUrl)
print("file path is :",destinationUrl.path)
print("File moved to documents folder")
} catch let error as NSError {
print(error.localizedDescription)
}
}).resume()
}
}
}
And once I save that file, using its file path which is "destinationUrl.path" I initiate my player as bellow in a different UIViewController. As for now I have hardcoded the path I save. The code as bellow.
override func viewDidLoad() {
super.viewDidLoad()
//path I have saved in file manager is set to the url
let url = NSURL.fileURL(withPath:"/Users/auxenta/Library/Developer/CoreSimulator/Devices/F3840294-04AA-46BE-9E46-4342452AFB69/data/Containers/Data/Application/670C0EA1-B375-498E-8847-8707D391D7BF/Documents/Aal Izz Well - Remix(MyMp3Song).mp3") as NSURL
self.playerItem = AVPlayerItem(url: url as URL)
self.player=AVPlayer(playerItem: self.playerItem!)
let playerLayer=AVPlayerLayer(player: self.player!)
playerLayer.frame = CGRect(x: 0, y: 0, width: 10, height: 50) // actually this player layer is not visible
self.view.layer.addSublayer(playerLayer)
}
#IBAction func playBtnPressed(_ sender: Any) {
if player?.rate == 0 // this means if its not playing
{
player!.play()
print("playing")
playbutton.setImage(UIImage(named: "pausebutton"), for: UIControlState.normal)
//trackTime
trackTime()
} else {
// getFileFromFieManager()
print("pause")
player!.pause()
playbutton.setImage(UIImage(named: "playbutton"), for: UIControlState.normal)
}
}
Your problem is the URL set to the AVPlayer. In fact hardcoding a path in iOS doesn't work, it can change at any time.
You need to use code it the same way as you destinationUrl:
if let audioUrl = URL(string: "https://www.googleapis.com/download/storage/v1/b/feisty-beacon-159305.appspot.com/o/Aal%20Izz%20Well%20-%20Remix(MyMp3Song).mp3?generation=1490097740630162&alt=media") {
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!//since it sys first this may only plays the first item
// destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
print("destinationUrl is :",destinationUrl)
self.playerItem = AVPlayerItem(url: destinationUrl)
self.player=AVPlayer(playerItem: self.playerItem!)
let playerLayer=AVPlayerLayer(player: self.player!)
.
.
.
}
Normally it should work. Hope it helps.
You can use codes in the below. I hope I could helped you out. First you need to create path for the source file that you wanted to be play
let path = Bundle.main.path(forResource: "yourFileName", ofType: "mp3")
let soundUrl = URL(fileURLWithPath: path!)
do{
try btnSound = AVAudioPlayer(contentsOf: soundUrl)
btnSound.prepareToPlay()
}
catch let err as NSError{
print(err.debugDescription)
}
After you created these in the viewDidLoad method. You can create function for the playing sound like;
func playSound() {
if btnSound.isPlaying {
btnSound.stop()
}
btnSound.play()
}
after all of these you can able to play mp3 files in swift.

How to copy remote server file in document directory in swift

I know how to get a remote URL in Swift
let remoteURL = NSURL(string: "https://myserver/file.txt")!
I know how to get a local URL in Swift
let localURL = NSURL(fileURLWithPath: documentsFolder + "/my_local_file.txt")
and unfortunately this does not work
NSFileManager.defaultManager().copyItemAtURL(remoteURL, toURL: localURL)
with the following error
The file “file.txt” couldn’t be opened because URL type https isn’t supported.
Is there a way how to perform this?
You can use NSURLSessionDownloadTask to download the file:
func downloadFile(url: URL) {
let downloadRequest = URLRequest(url: url)
URLSession.shared.downloadTask(with: downloadRequest) { location, response, error in
// To do check resoponse before saving
guard let tempLocation = location where error == nil else { return }
let documentDirectory = FileManager.default.urlsForDirectory(.documentDirectory, inDomains: .userDomainMask).last
do {
let fullURL = try documentDirectory?.appendingPathComponent((response?.suggestedFilename!)!)
try FileManager.default.moveItem(at: tempLocation, to: fullURL!)
print("saved at \(fullURL) ")
} catch NSCocoaError.fileReadNoSuchFileError {
print("No such file")
} catch {
// other errors
print("Error downloading file : \(error)")
}
}.resume()
}
let stringURL = "https://wordpress.org/plugins/about/readme.txt"
downloadImage(url: URL(string: stringURL)!)
Update: SWIFT 2.2
func downloadFile(url: NSURL) {
let downloadRequest = NSURLRequest(URL: url)
NSURLSession.sharedSession().downloadTaskWithRequest(downloadRequest){ (location, response, error) in
guard let tempLocation = location where error == nil else { return }
let documentDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
let fullURL = documentDirectory?.URLByAppendingPathComponent((response?.suggestedFilename)!)
do {
try NSFileManager.defaultManager().moveItemAtURL(tempLocation, toURL: fullURL!)
} catch NSCocoaError.FileReadNoSuchFileError {
print("No such file")
} catch {
print("Error downloading file : \(error)")
}
}.resume()
}
let stringURL = "https://wordpress.org/plugins/about/readme.txt"
let url = NSURL.init(string: stringURL)
downloadFile(url!)
You should download it first, then save it to a local file.
Code example can be found here: (using AFNetworking)
How I properly setup an AFNetworking Get Request?

Resources