Play audio file using EZAudio Framework in Swift - ios

Hi I am trying to convert following Objective-C code to Swift:
EZAudioFile *audioFile = [EZAudioFile audioFileWithURL:NSURL]; //required type NSURL
[self.player playAudioFile:audioFile];
But I am unable to make it work.
let audioFile = EZAudioFile.url(EZAudioFile) //required type EZAudioFile, so I am unable to pass the NSURL of the audio file here.
player.play()
Error is : Cannot convert value of type 'NSURL' to expected argument type 'EZAudioFile'
The above objective-C code is referenced from here : EZAudio Example:Record File

I didn't test, so I may be wrong, but I think you're not using the right syntax: EZAudioFile.url(EZAudioFile) does not call the initializer you're thinking of.
I see in the EZAudioFile source that there's indeed an initializer for an audio file URL:
+ (instancetype)audioFileWithURL:(NSURL *)url
So my guess is that the syntax in Swift should rather be:
let audioFile = EZAudioFile(audioFileWithURL: yourURL)
Also, it seems that it is only a wrapper for the normal URL init, which should be something like:
let audioFile = EZAudioFile(URL: yourURL)

Related

converting video to NSData in share extension in ios

I have created a share extension for my ios app. When I click on the share option in the photo app my share extension is shown and I click on it and my controller is shown. Everything is working fine up to this. I am uploading video to youtube using the youtube api. I am using this method to create the parameter
GTLUploadParameters *uploadParameters = [GTLUploadParameters uploadParametersWithData:fileData MIMEType:#"video/*"];
Now if the video is small then it is easily converted to NSData using this code
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL URLWithString:videoURL]];
and everything is working and video is uploaded.
But if the video is large then it simply crash and exit from the share extension(I put breakpoint and found this problem. If I remove the fileData conversion then its not crashing.). So what I did was instead of converting it to NSData I used this youtube api method
GTLUploadParameters *uploadParameters = [GTLUploadParameters uploadParametersWithFileURL:[NSURL URLWithString:videoURL] MIMEType:#"video/*"];
Now app is not crashing but I am getting network error. The error is
Error Domain=NSURLErrorDomain Code=-995 "(null)"
little searching found that it is because of NSURLSession and told to use something like this
sessionConfiguration.sharedContainerIdentifier = #“com.me.myapp.containerIdentifier”;
I am using youtube api. I am not sure where to use it OR is there any other way to use youtube api in share extension with large video file.
NOTE: I am using youtube api in my app and its working fine with NSData.
Hope question is clear. I am stuck on it for a day now. Please help.
Thanks in advance.
EDIT 1:
I used this code
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:videoURL] options:0 error:&error];
filedata is nil. The error I am getting is
Error Domain=NSCocoaErrorDomain Code=260 "The file “IMG_2187.MOV”
couldn’t be opened because there is no such file."
UserInfo={NSFilePath=/file:/var/mobile/Media/DCIM/102APPLE/IMG_2187.MOV,
Consider this line:
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
This does a forced unwrapping of info[UIImagePickerControllerMediaURL] (which is bad, because if it was nil, the app would crash) and that casts it as an implicitly unwrapped optional NSURL!. That doesn't make sense. Just do a conditional unwrapping (and unwrap to a NSURL, not a NSURL!):
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
The next line calls filePathURL:
var videoFileURL = videoDataURL.filePathURL
If you wanted a file URL, you already have one, so no conversion is needed, but instead just use videoDataURL. If you really wanted a path, you'd use path method:
let videoPath = videoDataURL.path
Frankly, Apple is trying to shift us away from using string paths, so just use the original videoDataURL and avoid the use of both path and filePathURL.
You are using dataWithContentsOfMappedFile:
var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
If you really wanted to use dataWithContentsOfMappedFile, the proper Swift syntax is:
let video = NSData(contentsOfMappedFile: videoPath!)
But dataWithContentsOfMappedFile deprecated, so you should instead use:
let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
Or, bypassing that videoPath altogether, you could:
let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
Obviously, those try renditions should be done within a do block with a catch block.
By the way, as you'll see in all of my above examples, one should use let where possible.
Quite frankly, I would advise against loading it into a NSData at all. Just copy it with NSFileManager, which is a more efficient use of memory. If the video is long, it could be quite large, and you should avoid loading the whole thing into memory at any given point in time.
So you could:
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
// build your destination URL however you want
//
// let tempFolder = NSURL(fileURLWithPath: NSTemporaryDirectory())
// let destinationURL = tempFolder.URLByAppendingPathComponent("test.mov")
// or
let documents = try NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let destinationURL = documents.URLByAppendingPathComponent("test.mov")
// but just copy from the video URL to the destination URL
try NSFileManager.defaultManager().copyItemAtURL(videoDataURL, toURL: destinationURL)
} catch {
print(error)
}
}
If you're uploading this to a web service, you'd then use a NSURLSessionUploadTask, using file or stream options. The construction of this request is a separate question, but hopefully you get the idea: With large assets like photos or, especially, videos, don't instantiate a NSData with the asset if you can possibly avoid it.
Please try this if your file exist in your phone instead of [NSURL URLWithString:videoURL].
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:videoURL]];

How to load an Audio File in Swift 2 and store it as an array of floats (IOS)

I'm new to Swift and IOS programming. I want to load an audio file in Swift 2, to do some signal processing. But I'm not able to load an audio file and store it as an array of floats. Can anybody give me a hint on literature or even a working code example on how to load an audio file? I searched the forums, but none of the old topics seems to do the trick.
Here's my Code:
import UIKit
import AVFoundation
var audio: AVAudioPlayer!
let path = NSBundle.mainBundle().pathForResource("nameOfFile", ofType:"wav")!
let url = NSURL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOfURL: url)
audio = sound
} catch {
// couldn't load file
}
error message: fatal error: unexpectedly found nil while unwrapping an Optional value
Thank you in advance (and sorry for the possibly dumb question)

Error trying to upload an image to CloudKit using Swift3

I'm running into a compiler error when using the following code:
func saveImageToDisk() {
let imageData = UIImagePNGRepresentation(imageView.image!)!
let fileName = getDocumentsDirectory().appendingPathComponent("image.png")
imageData.writeToFile(fileName, atomically: true)
}
The error is: Value of type 'Data' has no member 'writeToFile'
Could this be a compiler error, or something I'm missing? Thanks
SE-0005 proposed a better translation of Objective-C APIs into Swift and that affected NSData (or just Data now). Instead of writeToFile you'll have to use write(to:options:) (or even just write(to:)). Here is the documentation for the updated method.

Swift - pathForResource inDirectory parameter

I'm making a very simple app that uses a UIWebView to display a pdf map that can be zoomed in on, panned, etc.
However, when creating a target url for the pdf, the pathForResource call isn't working right. This is my code:
var targetURL : NSURL = NSBundle.mainBundle().pathForResource(filename, ofType: type)
I get an error on the parentheses before "filename", that says Missing argument for parameter 'inDirectory' in call. I tried adding an argument for this:
var targetURL : NSURL = NSBundle.mainBundle().pathForResource(filename, ofType: type, inDirectory: "Map")
I don't know what to put for inDirectory, because I don't know what the directory is - I added the file to my project and it is in the same folder as my ViewController.swift file. Anyway, it doens't really matter, because I get the following error in the same place, Extra argument 'inDirectory in call.
What do I do?
pathForResource() does not return a NSURL object, but a String?. Declare your variable accordingly and it should work.
var targetURL : String? = NSBundle.mainBundle().pathForResource(filename, ofType: type)
Or, of course, if you would rather - just use URLForResource() instead.
var targetURL : NSURL? = NSBundle.mainBundle().URLForResource(filename, withExtension: type)
I was having this same problem. In my case it was because my variable (in your case type) needed to be unwrapped. Adding a bang ! made the error go away and made the code execute.

How to loop over multiple (audio/mp3) files in a directory with swift? - Swift, iOS8 Soundboard AVPlayer

I am trying to create a soundboard using Swift to fiddle around and learn about swift/iOS8.
This is what I have done in my tableViewController as of now:
var soundPath = NSBundle.mainBundle().pathForResource("RandomSound", ofType: "m4a")
var soundURL = NSURL.fileURLWithPath(soundPath!)
self.audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: nil)
self.audioPlayer.play()
This works to play the sound as expected. Now in order to have a few more sounds and display them in tableView, I created an array of Sound class which looks like this:
class Sound {
var name: [String]
var fileURL = NSURL()
// more fields as required
}
and then using it like this:
var sounds: [Sound] = []
sounds.name = "RandomSound"
sounds.fileURL = soundURL!
However, I want something to make it to scale better. Lets say I have a bunch of mp3 files in one folder (for example 100).
In this case I would like some mechanism, with which, I can simply point the directory and/or filetype and then the remaining heavy lifting like going through each file in the directory and finding the name/artist/and other information would be extracted from mp3 file ID3 tags (or something similar).
If not all details, at least populating the name/URL field and looping over all files in a directory should be possible to automate, but I'm unable to understand what I should be looking at to achieve this.
EDIT
This part allows me scan all files in a directory of a given filetype(s). In my case I am looking for mp3. This is what I've come up with:
soundArray: [soundElement] = []
let fileManager = NSFileManager.defaultManager()
let directoryPath = "/path/to/directory/containing/my/sound/files"
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(directoryPath)!
while let element = enumerator.nextObject() as? String {
if element.hasSuffix("mp3") { // checks the extension
// DO my sound path stuff here
//println(element)
let soundURL = NSURL.fileURLWithPath(directoryPath + element)
//Of course I'll not be playing them directly here, (I don't see why) but if I needed to ...
//self.audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: nil)
//self.audioPlayer.play()
//Instead it just makes sense to populate some array/dict containing all the sounfURLs
soundElement.name = String(element)
soundElement.fileURL = soundURL
self.soundArray.append(soundElement)
}
}
class soundElement {
var name = " "
var fileURL = NSURL()
}
I am still not clear on how to get ID3 information from mp3 files in swift. I have referred the AVAsset information at https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAsset_Class/index.html#//apple_ref/occ/cl/AVAsset but it is not clear how to use it yet.
I looked at the AVAsset (https://developer.apple.com/reference/avfoundation/avasset#//apple_ref/occ/cl/AVAsset) docs and saw that there is a metadata property on it (https://developer.apple.com/reference/avfoundation/avasset/1386884-metadata).
It is an array of AVMetadataItems (https://developer.apple.com/reference/avfoundation/avmetadataitem) so you could check the items if they contain the metadata you are looking for
(Keys are usually something like AVMetadataiTunesMetadataKeySongName in the key space AVMetadataKeySpaceiTunes or AVMetadataID3MetadataKeyAlbumTitle in the AVMetadataKeySpaceID3.
If you want an easier solution, you could check out the ID3Edit library from this guy: https://github.com/philiphardy/ID3Edit
I'd try the following:
Load your songs as AVAsset
Iterate over the metadata array of each song
Print out the keys and values of the items to identify the ones you are interested in
Once you are familiar with the structure of the metadata, you can start retrieving the ones you want.
Hope this helps

Resources