AVRecorder and AVPlayer in swift - xcode

All ,
I need to create a sample audio player and recorder, its not erroring but its not playing and perhaps not recording.. any ideas ?
#IBAction func Play(AnyObject)
{
println ("Play")
let path = NSBundle.mainBundle().pathForResource("171010", ofType:"m4a")
let fileURL = NSURL(fileURLWithPath: path)
player = AVAudioPlayer(contentsOfURL: outputFileURL, error: nil)
player.prepareToPlay()
player.delegate = self
player.play()
}
#IBAction func Record(AnyObject)
{
filename = "171010.m4a"
let paths: NSArray = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var pathComponents = [paths.lastObject as String, filename as String]
outputFileURL = NSURL.fileURLWithPathComponents(pathComponents)
settings.setValue(kAudioFormatMPEG4AAC, forKey: AVFormatIDKey)
settings.setValue(44100.0, forKey: AVSampleRateKey)
settings.setValue(2, forKey: AVNumberOfChannelsKey)
recorder = AVAudioRecorder(URL: outputFileURL, settings: settings, error: &error)
recorder.delegate = self;
recorder.prepareToRecord()
recorder.record()
}
#IBAction func Stop(AnyObject)
{
recorder.stop()
println("Stop")
}
and the globals at the top are :
class MainMenu: UIViewController , AVAudioRecorderDelegate , AVAudioPlayerDelegate {
var filename: String!
var outputFileURL: NSURL!
var recorder: AVAudioRecorder!
var error: NSError?
var settings: NSMutableDictionary = NSMutableDictionary()
var player : AVAudioPlayer! = nil
Any ideas ? I don't know if its recording and creating the file. As I am getting URL is nill on the playing function. This is wired up to a storyboard with buttons. Any help within this simple stuff in swift would be brilliant.
I have changed it to this and this should work ? Can anyone advise ?
#IBAction func Play(AnyObject)
{
println ("Play")
var audioPlayer = AVAudioPlayer()
filename = "171010.m4a"
let paths: NSArray = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var pathComponents = [paths.lastObject as String, filename as String]
outputFileURL = NSURL.fileURLWithPathComponents(pathComponents)
audioPlayer = AVAudioPlayer(contentsOfURL: outputFileURL, error: nil)
audioPlayer.prepareToPlay()
audioPlayer.delegate = self
audioPlayer.play()
}
#IBAction func Record(AnyObject)
{
filename = "171010.m4a"
let paths: NSArray = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var pathComponents = [paths.lastObject as String, filename as String]
outputFileURL = NSURL.fileURLWithPathComponents(pathComponents)
settings.setValue(kAudioFormatMPEG4AAC, forKey: AVFormatIDKey)
settings.setValue(44100.0, forKey: AVSampleRateKey)
settings.setValue(2, forKey: AVNumberOfChannelsKey)
recorder = AVAudioRecorder(URL: outputFileURL, settings: settings, error: &error)
recorder.delegate = self;
recorder.prepareToRecord()
recorder.record()
}

The player needs to be an ivar so it isn't popped off the stack before playing.
Here is a github project with a functioning recorder if you need more info.
Also, the convention is to start function names with a lowercase character.

Related

Swift2 retrieving images from Firebase

I am trying to read/display an image from Firebase. I am first encoding the image and then posting this encoded String to Firebase. This runs fine. When I try and decode the encoded string from Firebase and convert it to an image, I am getting a nil value exception.
This is how I am saving the image to Firebase
var base64String: NSString!
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
var uploadImage = image as! UIImage
var imageData = UIImagePNGRepresentation(uploadImage)!
self.base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let ref = Firebase(url: "https://XXX.firebaseio.com")
var quoteString = ["string": self.base64String]
var usersRef = ref.childByAppendingPath("goalImages")
var users = ["image": quoteString]
usersRef.setValue(users)
displayAlert("Image Posted", message: "Your image has been successfully posted!")
}
This is how I am trying to read the image from Firebase
// ViewController.swift
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var image: UIImageView!
var base64String: NSString!
#IBAction func buttonClicked(sender: AnyObject) {
sender.setTitle("\(sender.tag)", forState: UIControlState.Normal)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let ref = Firebase(url: "https://XXX.firebaseio.com/goalImages/image/string")
ref.observeEventType(.Value, withBlock: { snapshot in
self.base64String = snapshot.value as! NSString
let decodedData = NSData(base64EncodedString: self.base64String as String, options: NSDataBase64DecodingOptions())
//Next line is giving the error
var decodedImage = UIImage(data: decodedData!)
self.image.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The error says: "fatal error: unexpectedly found nil while unwrapping an Optional value"; decodedData is nil. Could someone explain what is going wrong.
Instead of
let decodedData = NSData(base64EncodedString: self.base64String as String,
options: NSDataBase64DecodingOptions())
try adding IgnoreUnknownCharacters
NSDataBase64DecodingOptions.IgnoreUnknownCharacters
Use Example: Encode a jpg, store and read from firebase
encode and write our favorite starship
if let image = NSImage(named:"Enterprise.jpeg") {
let imageData = image.TIFFRepresentation
let base64String = imageData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
let imageRef = myRootRef.childByAppendingPath("image_path")
imageRef.setValue(base64String)
read and decode
imageRef.observeEventType(.Value, withBlock: { snapshot in
let base64EncodedString = snapshot.value
let imageData = NSData(base64EncodedString: base64EncodedString as! String,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = NSImage(data:imageData!)
self.myImageView.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
EDIT 2019_05_17
Update to Swift 5 and Firebase 6
func writeImage() {
if let image = NSImage(named:"Enterprise.jpg") {
let imageData = image.tiffRepresentation
if let base64String = imageData?.base64EncodedString() {
let imageRef = self.ref.child("image_path")
imageRef.setValue(base64String)
}
}
}
func readImage() {
let imageRef = self.ref.child("image_path")
imageRef.observeSingleEvent(of: .value, with: { snapshot in
let base64EncodedString = snapshot.value as! String
let imageData = Data(base64Encoded: base64EncodedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
let decodedImage = NSImage(data: imageData)
self.myImageView.image = decodedImage
})
}
Firebase Engineer here:
I highly recommend using the new Firebase Storage API for uploading images to Firebase. It's simple to use, low cost, and backed by Google Cloud Storage for huge scale.
You can upload from NSData or an NSURL pointing to a local file (I'll show NSData, but the principle is the same):
// Data in memory
let data: NSData = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
// This can be stored in the Firebase Realtime Database
// It can also be used by image loading libraries like SDWebImage
}
}
You can even pause and resume uploads, and you can easily monitor uploads for progress:
// Upload data
let uploadTask = storageRef.putData(...)
// Add a progress observer to an upload task
uploadTask.observeStatus(.Progress) { snapshot in
// Upload reported progress
if let progress = snapshot.progress {
let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
}
}

Swift 2 - Share video with UIActivityViewController

I am trying to share a video from a URL using UIActivityViewController.
If I try with an Image I have not problems.
Share Image Works:
let imageThump = NSURL(string: "https://example.com/image.png")
let imageData = NSData(contentsOfURL: imageThump!)
let objectsToShare = [comment!, imageData!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
Share Video is not working. Why?
let videoShare = NSURL(string: "https://example.com/video.mp4")
let videoData = NSData(contentsOfURL: videoShare!)
let objectsToShare = [comment!, videoData!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
THIS IS HOW YOU DO IT ...
guard let urlData = NSData(contentsOfURL: NSURL(string:"https://example.com/video.mov)")!) else {
return
}
print(urlData)
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docDirectory = paths[0]
let filePath = "\(docDirectory)/tmpVideo.mov"
urlData?.writeToFile(filePath, atomically: true)
// File Saved
let videoLink = NSURL(fileURLWithPath: filePath)
let objectsToShare = [videoLink] //comment!, imageData!, myWebsite!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.setValue("Video", forKey: "subject")
// New Excluded Activities Code
if #available(iOS 9.0, *) {
activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard, UIActivityTypeMail, UIActivityTypeMessage, UIActivityTypeOpenInIBooks, UIActivityTypePostToTencentWeibo, UIActivityTypePostToVimeo, UIActivityTypePostToWeibo, UIActivityTypePrint]
} else {
// Fallback on earlier versions
activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard, UIActivityTypeMail, UIActivityTypeMessage, UIActivityTypePostToTencentWeibo, UIActivityTypePostToVimeo, UIActivityTypePostToWeibo, UIActivityTypePrint ]
}
self.presentViewController(activityVC, animated: true, completion: nil)
Remember that a video is usually a big file, so it'll take some time for it to be downloaded and saved. Here I used part of the first answer but adding some GCD. You'll get better results.
This is how I did it to avoid the App to stay frozen until the video is downloaded and saved:
let url = NSURL(string: "https://example.com/video.mov")
//Show activity indicator
DispatchQueue.global(qos: .background).async {
guard let urlData = NSData(contentsOf: url) else { return }
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath="\(documentsPath)/tempFile.mov"
DispatchQueue.main.async {
urlData.write(toFile: filePath, atomically: true)
//Hide activity indicator
let activityVC = UIActivityViewController(activityItems: [NSURL(fileURLWithPath: filePath)], applicationActivities: nil)
activityVC.excludedActivityTypes = [.addToReadingList, .assignToContact]
self.present(activityVC, animated: true, completion: nil)
}
}
It is not working because this class does not allow NSData to be passed to the Facebook activity type.
"UIActivityTypePostToFacebook
The object posts the provided content to the user’s wall on Facebook.
When using this service, you can provide NSString, NSAttributedString, UIImage, ALAsset, and NSURL objects as data for the activity items. You may also specify NSURL objects whose contents use the assets-library scheme."
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIActivity_Class/index.html#//apple_ref/doc/constant_group/Built_in_Activity_Types
I have been trying to get this to work as well. Haven't figured out how to get it to work; however, this is why your code is not working.

Background music not working, but no errors?

Please solve my question, why is the background music not working? This is my code, hope someone can solve it.
// Just to format it..
#IBOutlet var UsernameTextField: UITextField!
#IBOutlet var PasswordTextField: UITextField!
#IBOutlet var EmailTextField: UITextField!
#IBAction func LogIn(sender: AnyObject) {
}
func Login(){
var user = PFUser()
user.username = UsernameTextField.text!
user.password = PasswordTextField.text!
PFUser.logInWithUsernameInBackground(UsernameTextField.text, password: PasswordTextField.text, block: {
(User : PFUser?, Error : NSError?) -> Void in
if Error == nil{
dispatch_sync(dispatch_get_main_queue()){
var Storyboard = UIStoryboard(name: "Main", bundle: nil)
var MainVC : UIViewController = Storyboard.instantiateViewControllerWithIdentifier("MainVC") as! UIViewController
self.presentViewController(MainVC, animated: true, completion: nil)
}
}
else{
NSLog("Sorry, you've typed either username or password wrongly.")
}
})
}
#IBAction func signUpButton(sender: AnyObject) {
signUp() // Calling signUp function here that is declared below.
}
func signUp(){
// Do sign up stuff.
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
playBackgroundMusic("IntroMusic")
backgroundMusicPlayer.play()
let soundFilePath = NSBundle.mainBundle().pathForResource("Background", ofType: "mp3")
let soundFileURL = NSURL(fileURLWithPath: soundFilePath!)
let player = AVAudioPlayer(contentsOfURL: soundFileURL, error: nil)
player.numberOfLoops = -1 //infinite
player.play()
func signUp(){
var user = PFUser()
user.username = UsernameTextField.text!
user.password = PasswordTextField.text!
user.email = EmailTextField.text!
}
let user = PFUser()
user.username = "Name:"
user.password = "Pass:"
user.email = "Email:"
user.signUpInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if error == nil {
// Hooray! Let them use the app now.
} else {
// Examine the error object and inform the user.
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
var backgroundMusicPlayer: AVAudioPlayer!
func playBackgroundMusic(filename: String) {
//The location of the file and its type
let url = NSBundle.mainBundle().URLForResource("Background", withExtension: "mp3")
//Returns an error if it can't find the file name
if (url == nil) {
println("Could not find the file \(filename)")
}
var error: NSError? = nil
//Assigns the actual music to the music player
backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
//Error if it failed to create the music player
if backgroundMusicPlayer == nil {
println("Could not create audio player: \(error!)")
return
}
//A negative means it loops forever
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
As Leo Dabus suggested declare your player instance outside of viewDidLoad method and your code will be:
var player : AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let soundFilePath = NSBundle.mainBundle().pathForResource("Background", ofType: "mp3")
let soundFileURL = NSURL(fileURLWithPath: soundFilePath!)
player = AVAudioPlayer(contentsOfURL: soundFileURL, error: nil)
player.numberOfLoops = -1 //infinite
player.play()
}

Swift 2 error handling of audio recording code

can someone please assist me? I have some code (which I know runs properly in Xcode 6) that is having difficulty executing in Xcode 7 (due to the changes in error handling for Swift 2). I tried to convert the code using the latest Swift syntax in Xcode 7, but no recommendations were offered. Any suggestions?
//Setup audio session
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayAndRecord,error: nil)
//Initialize and prepare the recorder
audioRecorder = AVAudioRecorder(URL: filePath, settings: nil, error:nil)
audioRecorder.meteringEnabled = true;
audioRecorder.prepareToRecord()
audioRecorder.record()
}
#IBAction func stopAudio(sender: UIButton) {
recordingInProgress.hidden = true
//TODO: Stop recording the user's voice
audioRecorder.stop()
var audioSession = AVAudioSession.sharedInstance();
audioSession.setActive(false, error:nil)
}
The Error messages are for the following code:
session.setCategory(AVAudioSessionCategoryPlayAndRecord,error: nil)
Extra argument 'error' in call
audioRecorder = AVAudioRecorder(URL: filePath, settings: nil, error:nil)
Cannot find an initializer for type 'AVAudioRecorder' that accepts an argument list of type '(URL: NSURL?, settings: nil, error: nil)'
audioSession.setActive(false, error:nil)
****Extra argument 'error' in call****
try this class ive tested this and it works in the latest version of swift and Xcode
import UIKit
import AVFoundation
class RecordViewController: UIViewController {
required init(coder aDecoder: NSCoder) {
var baseString : String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
var pathComponents = [baseString, NSUUID().UUIDString + ".m4a"]
self.audioURL = NSURL.fileURLWithPathComponents(pathComponents)!
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil)
var recordSettings: [NSObject : AnyObject] = Dictionary()
recordSettings[AVFormatIDKey] = kAudioFormatMPEG4AAC
recordSettings[AVSampleRateKey] = 44100.0
recordSettings[AVNumberOfChannelsKey] = 2
self.audioRecorder = AVAudioRecorder(URL: self.audioURL, settings: recordSettings, error: nil)
self.audioRecorder.meteringEnabled = true
self.audioRecorder.prepareToRecord()
// Super init is below
super.init(coder: aDecoder)
}
you will then have to implement your buttons of course
something like this
#IBAction func recordPressed(sender: AnyObject) {
if self.audioRecorder.recording {
self.audioRecorder.stop()
self.recordButton.setTitle("RECORD", forState: UIControlState.Normal)
self.playButton.enabled = true
} else {
var session = AVAudioSession.sharedInstance()
session.setActive(true, error: nil)
self.audioRecorder.record()
self.recordButton.setTitle("PLAY", forState: UIControlState.Normal)
self.playButton.enabled = false
}
}
#IBAction func playPressed(sender: AnyObject) {
self.audioPlayer = AVAudioPlayer(contentsOfURL: self.audioURL, error: nil)
audioPlayer.play()
}
}

Cocoa/Swift: Loop through names of folder in path

I'm currently programming an os x application with swift, but I can't figure how to loop through or even get the names of all folders at a certain path. Maybe something with fm.enumeratorAtPath?
I use enumeratorAtURL. Here's some code that shows an example of how to print the directories in the user's home directory.
if let dirURL = NSURL(fileURLWithPath: NSHomeDirectory()) {
let keys = [NSURLIsDirectoryKey, NSURLLocalizedNameKey]
let fileManager = NSFileManager.defaultManager()
let enumerator = fileManager.enumeratorAtURL(
dirURL,
includingPropertiesForKeys: keys,
options: (NSDirectoryEnumerationOptions.SkipsPackageDescendants |
NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants |
NSDirectoryEnumerationOptions.SkipsHiddenFiles),
errorHandler: {(url, error) -> Bool in
return true
}
)
while let element = enumerator?.nextObject() as? NSURL {
var getter: AnyObject?
element.getResourceValue(&getter, forKey: NSURLIsDirectoryKey, error: nil)
let isDirectory = getter! as Bool
element.getResourceValue(&getter, forKey: NSURLLocalizedNameKey, error: nil)
let itemName = getter! as String
if isDirectory {
println("\(itemName) is a directory in \(dirURL.absoluteString)")
//do something with element here.
}
}
}

Resources