Recording and playing back audio working on simulator but not on real iPhone device [duplicate] - swift

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 3 years ago.
On the "soundPlayer.play()" line below I get an error:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value.
However, this only happens when pressing the play button on a real device.
Also please ignore that I named my button "plat" button instead of play button, hah.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVAudioRecorderDelegate, AVAudioPlayerDelegate {
#IBOutlet weak var recordBTN: UIButton!
#IBOutlet weak var platBTN: UIButton!
var soundRecorder : AVAudioRecorder!
var soundPlayer : AVAudioPlayer!
var fileName: String = "audioFile.m4a"
var player: AVAudioPlayer!
var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
//ca-app-pub-9351248624194777/2551009478 real
bannerView.rootViewController = self
bannerView.load(GADRequest())
setupRecorder()
platBTN.isEnabled = false
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func setupRecorder() {
let audioFilename = getDocumentsDirectory().appendingPathComponent(fileName)
let recordSetting = [ AVFormatIDKey : kAudioFormatAppleLossless,
AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey : 2,
AVSampleRateKey : 44100.2] as [String : Any]
do {
soundRecorder = try AVAudioRecorder(url: audioFilename, settings: recordSetting )
soundRecorder.delegate = self
soundRecorder.prepareToRecord()
} catch {
print(error)
}
}
func setupPlayer() {
let audioFilename = getDocumentsDirectory().appendingPathComponent(fileName)
do {
soundPlayer = try AVAudioPlayer(contentsOf: audioFilename)
soundPlayer.delegate = self
soundPlayer.prepareToPlay()
soundPlayer.volume = 1.0
} catch {
print(error)
}
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
platBTN.isEnabled = true
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
recordBTN.isEnabled = true
platBTN.setTitle("Play", for: .normal)
}
#IBAction func recordAct(_ sender: UIButton) {
if recordBTN.titleLabel?.text == "Record" {
soundRecorder.record()
recordBTN.setTitle("Stop", for: .normal)
platBTN.isEnabled = false
} else {
soundRecorder.stop()
recordBTN.setTitle("Record", for: .normal)
platBTN.isEnabled = false
}
}
#IBAction func playAct(_ sender: UIButton) {
if platBTN.titleLabel?.text == "Play" {
platBTN.setTitle("Stop", for: .normal)
recordBTN.isEnabled = false
setupPlayer()
soundPlayer.play() //Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
} else {
soundPlayer.stop()
platBTN.setTitle("Play", for: .normal)
recordBTN.isEnabled = false
}
}
#IBAction func playBtnPressed(_ sender: UIButton) {
playSound(soundName: "4chordsong3") //
}
#IBAction func pausePressed(_ sender: UIButton) {
if player?.play() != nil{
player.pause()
}
}
When I press the "play" button, the program immediately crashes and I get the error shown above. Is there any way I can fix this?

I found the solution. I simply added this to the setupRecorder method.:
let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSession.Category.playAndRecord)//

Related

Automatically delete data from Firebase Database

I have seen some other questions asked but I am having trouble getting it to work. I have a Mac app coded in swift and it has a Firebase login but the user types a key in that is stored on Firebase, is there a way to automatically delete that key when the user has successfully used it?
This is my database.
This is the code that is used currently.
import Cocoa
import FirebaseAuth
import FirebaseDatabase
class LoginViewController: NSViewController {
#IBOutlet weak var textUsername: NSTextField!
#IBOutlet weak var textPassword: NSSecureTextFieldCell!
#IBOutlet weak var btnLogin: NSButton!
var keyArray = \[Int64\]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
}
func getLoginState() -> Bool{
let state = UserDefaults.standard.bool(forKey: "isRegistered")
if (state) {
return true
} else {
return false
}
}
override func viewDidAppear() {
let state = self.getLoginState()
if (state){
self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "loginsegue"), sender: nil)
self.view.window?.close()
}
var ref: DatabaseReference!
ref = Database.database().reference()
let keyRef = ref.child("key1")
keyRef.observe(DataEventType.childAdded, with: { (snapshot) in
// let postDict = snapshot.value as? \[String : AnyObject\] ?? \[:\]
let keyStr = snapshot.value as? Int64
if let actualPost = keyStr{
self.keyArray.append(actualPost)
}
})
}
#IBAction override func dismissViewController(_ viewController: NSViewController) {
dismiss(self)
}
#IBAction func close(sender: AnyObject) {
self.view.window?.close()
}
#IBAction func onSignup(_ sender: Any) {
// self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "gotosignup"), sender: sender)
// self.view.window?.close()
}
func dialogOK(question: String, text: String) -> Void {
let alert: NSAlert = NSAlert()
alert.messageText = question
alert.informativeText = text
alert.alertStyle = NSAlert.Style.warning
alert.addButton(withTitle: "OK")
alert.runModal()
}
#IBAction func onLogin(_ sender: Any) {
//self.btnLogin.isEnabled = false
var isKey = false
if (!self.textUsername.stringValue.isEmpty) {
for key in keyArray{
if(Int64(self.textUsername.stringValue)! == key)
{
UserDefaults.standard.set(true, forKey:"isRegistered")
self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "loginsegue"), sender: nil)
self.view.window?.close()
isKey = true
}
}
if (!isKey){
self.dialogOK(question: "Error", text: "Invalid Key")
}
} else {
self.dialogOK(question: "Error", text: "Please Input Key")
}
}
}
You can't sort your database like that and expect a working code, even if there's any. It will make a messy code:
You need to:
Sort your database like [1220:0]. the key first. 0 & 1 as an indicator if it's used or not.
Once the user taps onLogin() you need to set the used key value to 1
Setup Cloud Functions to check if the used key is equal to 1, if yes. then remove the key.
Do the rest of the work.
Related Articles to get you started:
Extend Realtime Database with Cloud Functions
functions.database.RefBuilder

Live stream using AVPlayer not playing in iOS 11

I am trying to stream a music from remote url. I am trying to run this in iOS 11 but it not play the music.
ViewController
var session = AVAudioSession.sharedInstance()
var LQPlayer: AVPlayer?
let LOW_URL = URL(string: "http://someLInk.pls")! // not an original url provided at this time.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.avPlayerSetup()
}
func avPlayerSetup() {
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
try session.overrideOutputAudioPort(.none)
try session.setActive(true)
} catch {
print("AVPlayer setup error \(error.localizedDescription)")
}
}
func initPlayer() {
LQPlayer = AVPlayer(url: LOW_URL)
print("player allocated")
}
func deAllocPlayer() {
LQPlayer = nil
print("player deallocated")
}
#IBAction func playBtn(_ sender: Any) {
initPlayer()
LQPlayer?.play()
}
#IBAction func pauseBtn(_ sender: Any) {
LQPlayer?.pause()
deAllocPlayer()
}
}
I set Allow Arbitrary Loads YES in info.plist.
Above code the URL I given is dummy. Actual url is working fine.
Working Code with Live Video Stream
#IBOutlet weak var player_View: UIView!
var LQPlayer: AVPlayer?
let LOW_URL = URL(string:"http://www.streambox.fr/playlists/test_001/stream.m3u8")!
override func viewDidLoad() {
super.viewDidLoad()
self.avPlayerSetup()
LQPlayer = AVPlayer.init(url: LOW_URL)
let avPlayerView = AVPlayerViewController()
avPlayerView.view.frame = self.player_View.bounds
avPlayerView.player = LQPlayer
self.player_View.addSubview(avPlayerView.view)
}
func avPlayerSetup() {
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayback)
try audioSession.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
try audioSession.setActive(true)
} catch {
print("AVPlayer setup error \(error.localizedDescription)")
}
}
func initPlayer() {
LQPlayer = AVPlayer(url:LOW_URL)
print("player allocated")
}
func deAllocPlayer() {
LQPlayer = nil
print("player deallocated")
}
#IBAction func playBtn(_ sender: Any) {
// initPlayer()
LQPlayer?.play()
}
#IBAction func pauseBtn(_ sender: Any) {
LQPlayer?.pause()
deAllocPlayer()
}

FBLoginManager undeclared type

I installed FacebookSDK using Cocoapods, according to Terminal, I have installed FacebookSDK 4.8.0 (CoreKit, ShareKit and LoginKit), I imported the .h files in my BH-File.h, and already initialized everything in my AppDelegate.
For some reason, when trying to log in using a custom button, when I initialize FBLoginManager, I get an error Use of undeclared type "FBLoginManager".
this is my code
if (FBSDKAccessToken.currentAccessToken() == nil)
{
let fbLoginManager : FBSDKLoginManager =
fbLoginManager.logInWithReadPermissions(["public_profile", "email"], fromViewController: self, handler: { (loginResult, error) -> Void in
if error == nil {
print (FBSDKAccessToken.currentAccessToken().tokenString)
}
else {
print ("ERROR*****: \(error)")
}
})
}
What fixed to me was adding import FBSDKCoreKit and FBSDKLoginKit to my class, for some reason is not enough adding it in the BH-file.h
Try something like this, I just checked the code and it works (it's not exactly what you're looking for but I'm sure you can modify it as needed)
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ProfileViewController: UIViewController,FBSDKLoginButtonDelegate {
// #IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var fbLoginButton: FBSDKLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
self.fbLoginButton.delegate = self
self.fbLoginButton.readPermissions = ["public_profile"]
self.fbLoginButton.publishPermissions = ["publish_actions"]
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "fbProfileChanged:",
name: FBSDKProfileDidChangeNotification,
object: nil)
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
// If we have a current Facebook access token, force the profile change handler
if ((FBSDKAccessToken.currentAccessToken()) != nil)
{
self.fbProfileChanged(self)
} }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
//facebooks functions
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if (error != nil)
{
print( "\(error.localizedDescription)" )
}
else if (result.isCancelled)
{
// Logged out?
print( "Login Cancelled")
}
else
{
// Logged in?
print( "Logged in, segue now")
self.performSegueWithIdentifier("showHome", sender: self)
}
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
}
//see bitfountain
func fbProfileChanged(sender: AnyObject!) {
let fbProfile = FBSDKProfile.currentProfile()
if (fbProfile != nil)
{
// Fetch & format the profile picture
let strProfilePicURL = fbProfile.imagePathForPictureMode(FBSDKProfilePictureMode.Square, size: imageView.frame.size)
let url = NSURL(string: strProfilePicURL, relativeToURL: NSURL(string: "http://graph.facebook.com/"))
let imageData = NSData(contentsOfURL: url!)
let image = UIImage(data: imageData!)
self.nameLabel.text = fbProfile.name
self.imageView.image = image
self.nameLabel.hidden = false
self.imageView.hidden = false
self.nextButton.hidden = false
}
else
{
self.nameLabel.text = ""
self.imageView.image = UIImage(named: "")
self.nameLabel.hidden = true
self.imageView.hidden = true
}
}
#IBAction func nextButtonPressed(sender: UIButton) {
self.performSegueWithIdentifier("showHome", sender: self)
}
}

Crash when repeating a sound with AudioEngine in Swift

I'm trying to play sounds with different effects. In a previous viewController I record a sound, then in the next screen, it can be played with the effects. First time it works ok but the second time it crashes with error as follows:
2015-08-07 13:00:45.900 Pitch Perfect[9643:1121173] 13:00:45.900
ERROR: AVAudioEngine.mm:253: AttachNode: required condition is
false: !nodeimpl->HasEngineImpl() 2015-08-07 13:00:45.953 Pitch
Perfect[9643:1121173] Terminating app due to uncaught exception
'com.apple.coreaudio.avfaudio', reason: 'required condition is false:
!nodeimpl->HasEngineImpl()'
import UIKit
import AVFoundation
class PlaySoundsViewController: UIViewController, AVAudioPlayerDelegate {
var receivedAudio:RecordedAudio!
var audioPlayer: AVAudioPlayer!
var disabledButton:UIButton!
var firstTime:Bool = true
var audioEngine:AVAudioEngine!
var audioFile:AVAudioFile!
var audioPlayerNode:AVAudioPlayerNode!
var audioStopped:Bool!
var typeOfSound:IntegerLiteralType!
#IBOutlet weak var stopButton: UIButton!
#IBOutlet weak var reverbButton: UIButton!
#IBOutlet weak var echoButton: UIButton!
#IBOutlet weak var darthButton: UIButton!
#IBOutlet weak var chipmonkButton: UIButton!
#IBOutlet weak var snailButton: UIButton!
#IBOutlet weak var rabbitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
audioPlayer = AVAudioPlayer(contentsOfURL: receivedAudio.filePathUrl, error: nil)
audioPlayer.enableRate=true
audioPlayer.delegate=self
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayback, error: nil)
audioPlayerNode=AVAudioPlayerNode();
audioEngine = AVAudioEngine()
audioFile = AVAudioFile(forReading: receivedAudio.filePathUrl, error: nil)
audioStopped=true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func playAnimalSound(animal: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
typeOfSound = 1
audioPlayer.currentTime=0
switch animal {
case "snail":
audioPlayer.rate=0.5
case "rabbit":
audioPlayer.rate=2.0
default:
showMessage("Sound not found. How can it be?")
}
audioPlayer.play()
stopButton.hidden=false
stopButton.enabled=true
}
#IBAction func playSnailSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("snail")
}
#IBAction func playRabbitSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("rabbit")
}
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
func playAudioWithVariablePitch(pitch: Float, type: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
audioEngine.attachNode(audioPlayerNode)
switch type {
case "normal":
typeOfSound = 2
var changePitchEffect = AVAudioUnitTimePitch()
changePitchEffect.pitch = pitch
audioEngine.attachNode(changePitchEffect)
audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)
case "reverb":
typeOfSound = 3
var changeReverbEffect = AVAudioUnitReverb()
changeReverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset(rawValue: 4)!)
changeReverbEffect.wetDryMix=50;
audioEngine.attachNode(changeReverbEffect)
audioEngine.connect(audioPlayerNode, to: changeReverbEffect, format: nil)
audioEngine.connect(changeReverbEffect, to: audioEngine.outputNode, format: nil)
case "delay":
typeOfSound = 3
var changeDelayEffect = AVAudioUnitDelay()
audioEngine.attachNode(changeDelayEffect)
audioEngine.connect(audioPlayerNode, to: changeDelayEffect, format: nil)
audioEngine.connect(changeDelayEffect, to: audioEngine.outputNode, format: nil)
default:
showMessage("oops, there was an internal problem. Never mind")
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
if flag {
stopButton.hidden=true
disabledButton.enabled=true;
audioStopped=true
println("I hid stopButton and enabled the disabled one")
}
}
#IBAction func playDelaySound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "delay")
}
#IBAction func playReverbSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "reverb")
}
#IBAction func playChipmunkSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(1000.0, type: "normal")
}
#IBAction func playDarthVaderSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(-900.0, type: "normal")
}
#IBAction func stopPlaying(sender: UIButton) {
resetAudio(typeOfSound)
stopButton.hidden=true
stopButton.enabled=false;
disabledButton.enabled=true;
}
func highlightButton(button: UIButton) {
if firstTime {
firstTime=false
} else {
disabledButton.enabled=true;
}
button.enabled=false;
disabledButton=button;
}
func resetAudio(type: IntegerLiteralType) {
switch type {
case 1 :
audioPlayer.stop()
println("case 1")
case 2 :
println("case 2")
if audioEngine.running {
audioEngine.stop()
}
audioEngine.reset()
case 3 :
audioEngine.stop()
default:
break
}
audioStopped=true;
}
func showMessage(msg: String) {
var message=UIAlertView(title: "Alert", message: msg, delegate: nil, cancelButtonTitle: "ok I won't panic")
}
}
Does anybody know why it crashes? I have researched the AVAudioEngine, AVAudioPlayer and AVAudioPlayerNode classes with no results.
Thanks
I know this is an old issue, but I didn't see the correct answer above.
The reason why it crashes is actually outlined in the error message:
AttachNode: required condition is false: !nodeimpl->HasEngineImpl()
In other words, when attaching a node it is mandatory that that node is not already attached to an engine (!nodeimpl->HasEngineImpl()).
The solution is to remove the node using audioEngine.detachNode before attempting to add it again.
Finally the crashed was caused by initializing the audioPlayerNode and the audioEngine objects in the viewDidLoad function. They need to be instantiated every time you use them, apparently, or maybe after being stopped and reset.
Placing those lines in the beginning of the playAudioWithVariablePitch function directly instead of in the viewDidLoad function, solved the crash problem. I still have a problem with the playback of the pitched, reverb and echo sounds. They get cut before it's due and I still don't know why. It has to do with the completionHandler of the audioPlayerNode.scheduleFile method.
In my case, my timer was calling again and again and this code was written inside my timer
self.recognitionTask?.finish()
node.removeTap(onBus: 0)
self.request.endAudio()
self.recognitionTask = nil
//Maybe this line was causing the issue
self.audioEngine.stop()
So if you already have stopped the request, removed the tap and stopped the engine, then these lines should not be called again.
Hope this helps some one
It looks like you are resetting the engine after playing the variable pitch effect.
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
So the engine hasnt been setup again with the nodes added and the chain linked. When you try to play the playerNode, it crashes.

Audio from MPMoviePlayerController continues playing after segue to next view controller

After adding a video file, the audio from the video preview continues even after a segue to the next VC is pressed.
Is there any way to stop the audio from playing after the segue is pressed?
var objMoviePlayerController: MPMoviePlayerController = MPMoviePlayerController()
var urlVideo: NSURL = NSURL()
#IBOutlet weak var videoprofileView: UIImageView!
#IBOutlet weak var addvideoBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
var theWidth = view.frame.size.width
var theHeight = view.frame.size.height
videoprofileView.frame = CGRectMake(0, 50, theWidth, theWidth)
addvideoBtn.center = CGPointMake(theWidth/2, self.videoprofileView.frame.maxY+50)
}
#IBAction func addvideoBtn_click(sender: AnyObject) {
var ipcVideo = UIImagePickerController()
ipcVideo.delegate = self
ipcVideo.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
ipcVideo.allowsEditing = true
ipcVideo.videoMaximumDuration = 15
var kUTTypeMovieAnyObject : AnyObject = kUTTypeMovie as AnyObject
ipcVideo.mediaTypes = [kUTTypeMovieAnyObject]
self.presentViewController(ipcVideo, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
urlVideo = (info as NSDictionary).objectForKey(UIImagePickerControllerMediaURL) as! NSURL
self.dismissViewControllerAnimated(true, completion: nil)
objMoviePlayerController = MPMoviePlayerController(contentURL: urlVideo)
objMoviePlayerController.movieSourceType = MPMovieSourceType.Unknown
objMoviePlayerController.view.frame = self.videoprofileView.bounds
objMoviePlayerController.scalingMode = MPMovieScalingMode.AspectFill
objMoviePlayerController.controlStyle = MPMovieControlStyle.None
objMoviePlayerController.shouldAutoplay = true
videoprofileView.addSubview(objMoviePlayerController.view)
objMoviePlayerController.prepareToPlay()
objMoviePlayerController.play()
}
#IBAction func next_click(sender: AnyObject) {
let data:NSData = NSData(contentsOfURL: urlVideo)!
let file = PFFile(name:"video.mp4", data:data)
var currentUser = PFUser.currentUser()!
currentUser["video"] = file
currentUser.saveInBackgroundWithBlock( {
(succeeded: Bool, error: NSError?) -> Void in
if error == nil {
println("video saved")
} else {
println("couldn't save video")
}
})
}
Tell your video to stop before segueing to the next view controller.
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
objMoviePlayerController.stop()
}
MPMediaPlayback Protocol Reference