Affdex AFDXDetector delegate functions are never called when using the camera? - ios

I’m having some trouble getting the Affdex iOS SDK to work with streaming input from the onboard camera. I’m using XCode 7.1.1 and an iPhone 5S. Here’s my initialization code:
let detector = AFDXDetector.init(delegate: self, usingCamera: AFDX_CAMERA_FRONT, maximumFaces: 1)
detector.setDetectAllEmotions(true)
detector.setDetectAllExpressions(true)
detector.maxProcessRate = 5.0
detector.licensePath = NSBundle.mainBundle().pathForResource("sdk_kevin#sideapps.com", ofType: "license”)
if let error = detector.start() {
log.warning("\(error)")
}
No error is produced by detector.start() and the app requests access to the camera the first time it is called, as expected. However, none of the delegate functions are ever called. I have tested with both AFDX_CAMERA_FRONT and AFDX_CAMERA_BACK.
I am able to process single images captured by the onboard camera as expected using the following:
let detector = AFDXDetector(delegate: self, discreteImages: true, maximumFaces: 1)
detector.setDetectAllEmotions(true)
detector.setDetectAllExpressions(true)
detector.licensePath = NSBundle.mainBundle().pathForResource("sdk_kevin#sideapps.com", ofType: "license")
if let error = detector.start() {
log.warning("\(error)")
}
detector.processImage(image)
Am I missing something obvious?

The issue appears to be the declaration of the detector variable. The lifetime of that variable is only scoped for the function if you declare it inside of the function — it is deallocated when the function exits.
Make the variable an instance variable in the class; this guarantees its lifetime is for the life of the object that it is instantiated in, and the delegate functions should also be called.

Related

iOS CoreMotion.MotionThread EXC_BAD_ACCESS is thrown after stopDeviceMotionUpdates() is called

I have a view controller that uses CoreMotion to monitor the device's Attitude.
Here is the handler that is used in the call to startDeviceMotionUpdates():
/**
* Receives device motion updates from Core Motion and uses the attitude of the device to update
* the position of the attitude tracker inside the bubble level view.
*/
private func handleAttitude(deviceMotion: CMDeviceMotion?, error: Error?) {
guard let attitude = deviceMotion?.attitude else {
GLog.Error(message: "Could not get device attitude.")
return
}
// Calculate the current attitude vector
let roll = attitude.roll
let pitch = attitude.pitch - optimalAngle
let magnitude = sqrt(roll * roll + pitch * pitch)
// Drawing can only happen on the main thread
DispatchQueue.main.async {
[weak self] in
guard let weakSelf = self else {
GLog.Log("could not get weak self")
return
}
// Move the bubble in the attitude tracker to match the current attitude
weakSelf.bubblePosX.constant = CGFloat(roll * weakSelf.attitudeScalar)
weakSelf.bubblePosY.constant = CGFloat(pitch * weakSelf.attitudeScalar)
// Set the border color based on the current attitude.
if magnitude < weakSelf.yellowThreshold {
weakSelf.attitudeView.layer.borderColor = weakSelf.green.cgColor
} else if magnitude < weakSelf.redThreshold {
weakSelf.attitudeView.layer.borderColor = weakSelf.yellow.cgColor
} else {
weakSelf.attitudeView.layer.borderColor = weakSelf.red.cgColor
}
// Do the actual drawing
weakSelf.view.layoutIfNeeded()
}
}
I added [weak self] to see if it would fix things, but it has not. This crash is not easy to reproduce.
When I am done the with VC that uses CoreMotion, I call stopDeviceMotionUpdates() in the VC's viewWillDisappear() method. This VC is the only class in the app that imports CoreMotion.
However, when I arrive in the next VC, occasionally I see EXC_BAD_ACCESS getting thrown on a co m.apple.CoreMotion.MotionThread.
Anybody know why CoreMotion would spawn a thread after the VC that used it has been dismissed? I've verified that the VC is no longer in memory when the crash happens. And yes, the two VCs I'm dealing with are presented modally.
I've examined the memory graph, and when the crash happens, these CoreMotion objects are being reported:
And:
I don't know if those objects should still be in memory after the instance of the CoreMotionManager has been deallocated or not. According to the memory graph, there is no instance of CoreMotionManager in memory.
The VC that imports CoreMotion also imports ARKit. Not sure if some crazy interaction between CoreMotion and ARKit is the problem.
There does seem to be something going on between the main thread and the MotionThread(14):
I'm not sure what to make of the main thread stack trace.
Sometimes when the CoreMotion VC is dismissed, I've noticed that there is a lag in the memory it uses getting released. The release always happens eventually.
Thanks to anybody who can help!
We have a ARSCNView member. We were not calling sceneView.session.pause() when we dismissed the VC that used the sceneView member. One line of code. That was it.
Are you passing the function handleAttitude direct to startDeviceMotionUpdates
as in startDeviceMotionUpdates(to:someQueue, withHandler:handleAttitude)
That will set up a retain cycle between your VC and CMMotionManager
Try
singletonMM.startDeviceMotionUpdates(to:someQueue) { [weak self] motion,error in
self?.handleAttitude(motion,error)
}
To prevent a strong ref to your VC.

Re-Assigning instance of AVAudioPlayer in iOS13 leads to BAD_ACCESS runtime error

I have an app, that is for many years in the AppStore and runs without any crashes (last deployment target iOS 12.4). I have some code for playing a sound on certain events in the app.
Now I tried to upgrade my app for iOS 13 and without changing any code related to that “playSound” thing, I always get this runtime error, when testing on a real device. Does not happen on simulator.
Thread 1: EXC_BAD_ACCESS (code=1, address=0x48)
PLEASE: Before you mark that question as “duplicate”, consider that this must have something to do with the release of iOS13, because before it didn’t happen and the code is just "usual".
Here is my code, also on gitHub.
I have a property in my ViewController to prevent ARC deallocating my AVAudioPlayer:
private var mySoundPlayer: AVAudioPlayer = AVAudioPlayer()
I have a routine, where the “play sound” should be performed (here happens the error, when assigning a new instance of AVAudioPlayer. The resourceURL is not the problem, the RE-ASSIGNING is the problem, I tested it with a new instance not being assigned and i did not crash.
// -------------------------------------------------
// MARK: Private Methods
// -------------------------------------------------
private func makeSoundEvent(_ soundEvent : SoundEvent) {
guard Settings().getSound() == .soundON else { return }
guard let urlToRessource : URL = soundEvent.getFileURLToSoundRessource() else { return }
do {
mySoundPlayer = try AVAudioPlayer(contentsOf: urlToRessource)
try? AVAudioSession.sharedInstance().setActive(true)
mySoundPlayer.play()
}
catch { print("Could not create AVPlayer for ressource \(urlToRessource)") }
}
And here I have the call of that subroutine, somewhere in my viewDidLoad() with a delay of 2 seconds.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.makeSoundEvent(.startFanfare)
}
I think it somehow does not work because of the async thread. But since it is on the main thread, I thought this should work.
Just remove the initialisation and it will work
private var mySoundPlayer: AVAudioPlayer!
Cheers!!!
private var mySoundPlayer: AVAudioPlayer = AVAudioPlayer()
AVAudioPlayer doesn't have init() listed as a valid initializer. The reference page shows four separate initializers, all of which take at least one parameter. If you were using the line above in code prior to iOS 13.1 without crashing, you were initializing the audio player incorrectly and probably just getting lucky that it wasn't a problem.
I don't know what changed specifically with AVAudioPlayer in iOS 13.1, but the release notes show quite a few audio-related changes, and it seems likely that some change to that class introduced a dependency on something that happens at initialization time.

CallKit error 7 when I perform a call for the first time

I've done a call kit + twilio IOS app. The problem is (as far as I can tell) with ios 12.
When I run the app on a device with IOS 11 the call start as normal. When I run the app on a device with IOS 12, when I try to make the first call I get this error :
StartCallAction transaction request failed: The operation couldn’t be
completed. (com.apple.CallKit.error.requesttransaction error 7.)
This error represent this: The requested transaction contains actions that, if performed, would exceed the maximum number of call groups for the provider. But i set the callGroupMax number to 1 ( I tried to set it 2,3 but still the same)
I found just one thread with this error on google but no solution was provided. Pleas give me a hint on what causes this error because I'm stuck on this.
This error appears only when the first call is made after a fresh install. Then I can make calls as it was intended.
This is the callkitManager class:
class CallKitManager: NSObject {
class var shared: CallKitManager {
struct Static {
static let instance: CallKitManager = CallKitManager()
}
return Static.instance
}
fileprivate let callKitProvider: CXProvider
override init() {
callKitProvider = CXProvider(configuration: type(of: self).providerConfiguration)
super.init()
callKitProvider.setDelegate(self, queue: nil)
}
static var providerConfiguration: CXProviderConfiguration {
let localizedName = NSLocalizedString("NAME", comment: "Name of application")
let configuration = CXProviderConfiguration(localizedName: localizedName)
configuration.supportsVideo = false
configuration.maximumCallsPerCallGroup = 1
configuration.ringtoneSound = "myringtone"
configuration.supportedHandleTypes = [.generic]
if let callKitIcon = UIImage(named: "callKitIcon") {
configuration.iconTemplateImageData = callKitIcon.pngData()
}
return configuration
}
I expect that the call to connect from the first time, but the result is that in the performStartCallAction() method I get the error from above.
So after 2 days I figure it out. The problem was that I use the callKit as a singleton which is wrong. You need "to mimic" a singleton using AppDelegate. See this tutorial https://www.raywenderlich.com/701-callkit-tutorial-for-ios and look in the AppDelegate and se how this was implemented.

Why doesn't my iOS (Swift) app properly recognize some external display devices?

So I have an odd issue and my google-fu utterly fails to even provide me the basis of where to start investigating, so even useful keywords to search on may be of use.
I have an iOS application written in swift. I have a model hooked up to receive notifications about external displays. On some adaptors, I'm able to properly detect and respond to the presence of an external display and programatically switch it out to be something other than a mirror (see code block below). But with another adaptor, instead of just 'magically' becoming a second screen, I'm asked to 'trust' the external device, and it simply mirrors the device screen. Not the intended design at all.
func addSecondScreen(screen: UIScreen){
self.externalWindow = UIWindow.init(frame: screen.bounds)
self.externalWindow!.screen = screen
self.externalWindow!.rootViewController = self.externalVC
self.externalWindow!.isHidden = false;
}
#objc func handleScreenDidConnectNotification( _ notification: NSNotification){
let newScreen = notification.object as! UIScreen
if(self.externalWindow == nil){
addSecondScreen(screen: newScreen)
}
}
#objc func handleScreenDidDisconnectNotification( _ notification: NSNotification){
if let externalWindow = self.externalWindow{
externalWindow.isHidden = true
self.externalWindow = nil
}
}
The worst issue here is that because I'm connecting to an external display to do this, I can't even run this code through the debugger to find out what is going on. I don't know where to even begin.
Any ideas?
Edit:
Thanks to someone pointing out wifi debugging, I can tell you my notifications are firing off, but they're both firing at the same time, one after the other, when the external adaptor is disconnected.

iOS crash: MTLRenderPassDescriptor null after rotation

I'm writing a iOS app using Metal. At some point during the MTKViewDelegate draw, I create a render pass descriptor and render things on screen,
let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
encoder.setViewport(camera.viewport)
encoder.setScissorRect(camera.scissorRect)
At the beginning of my draw function, I have a semaphore, the same code found in the Metal game template found in Xcode, and then a check to verify that the view hasn't changed size. If it has, I recreate my buffers,
let w = _gBuffer?.width ?? 0
let h = _gBuffer?.height ?? 0
if let metalLayer = view.layer as? CAMetalLayer {
let size = metalLayer.drawableSize
if w != Int(size.width) || h != Int(size.height ){
_gBuffer = GBuffer(device: device, size: size)
}
}
Everything works fine, and rotation was working fine on my iPhone6. However, when I tried on an iPad Pro, it always generate a SIGABRT when I try to rotate the device. The debugger tells me the encoder is null. I also get this exception in the console,
MTLDebugRenderCommandEncoder.mm:2028: failed assertion `(rect.x(1024) + rect.width(1024))(2048) must be <= 1536'
The exception must occur because I'm updating "camera" inside mtkView,
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
camera.setBounds(view.bounds)
}
When I run without the debugger attached, it doesn't crash.
I guess mtkView is called asynchronously and I should do something to stop the rendering midway through when mtkView is called, but the mutex should be in the library, not in my code? Although both draw and mtkView are being called from the same thread (Thread 1 in the debugger)... If I step-debug putting breakpoints in draw and mtkView, it seems I manually sync'ing and it doesn't crash. I'm a bit lost...
The full source code is here: https://github.com/endavid/VidEngine
Any ideas?
The exception message was the hint. I got distracted by the encoder being null. I guess it becomes null once the exception is thrown, but the problem wasn't in the encoder.
The code in camera.setBounds(view.bounds) wasn't updating the scissorRect...
I have a CADisplayLink that updates the CPU objects at a different rate, and the scissorRect was being updated there when it detected a change.
I've added a call to the full camera update inside mtkView() and the crash is gone now :)
I can resolve this, unchecking "Debug executable" in the Scheme

Resources