Solved iOS call object/function from Objective-C to cpp
-
Hi All,
How to call object/function from inside Objective-C *.m file ?
On iOS I'm recording from microphone using QAudioRecorder but when call arrives, even if I discard this call, and then do stop/pause on QAudioRecorder app hangs, no error in debug, I have to kill it.
This could be related to the fact that iOS prevents microphone use when there is a call.
I have created a piece of code to get notified when call is comming in order to stop/pause QAudioRecorder hoping that I will be able to resume when call was ended/discarded
So I have this notification now, how to call some function from inside Objective-C ?
Here are my codes
cl_objc_call.h#ifndef __CLObjCCall__ #define __CLObjCCall__ #include <stdio.h> class CL_ObjCCall { public: static int CL_objectiveC_Call(); }; #endif
cl_objc_call.mm
#include "cl_objc_call.h" #include "cl_objc_func.h" myCLClass* CL_obj; int fake; int CL_ObjCCall::CL_objectiveC_Call() { CL_obj=[[myCLClass alloc]init]; [CL_obj iosCallObserver:(fake)]; return 1; }
cl_objc_func.h
#ifndef __CLObjCFunc__ #define __CLObjCFunc__ #import <Foundation/Foundation.h> #import <CallKit/CXCallObserver.h> #import <CallKit/CXCall.h> @interface myCLClass:NSObject @property (nonatomic, strong) CXCallObserver *callObserver; -(int)iosCallObserver:(int)fake; -(void)iosCallObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call; @end #endif
cl_objc_func.m
#import "cl_objc_func.h" @implementation myCLClass //Your objective c code here.... -(int)iosCallObserver:(int)fake { CXCallObserver *callObserver = [[CXCallObserver alloc] init]; [callObserver setDelegate:self queue:nil]; self.callObserver = callObserver; return 1; } - (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call { if(call.onHold) { NSLog(@"********** voice call onHold **********/n"); } else if(call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false) { NSLog(@"********** voice call incoming **********/n"); //here I need to call Qt to stop recorder } else if (call.hasConnected) { NSLog(@"********** voice call connected **********/n"); } else if(call.hasEnded) { NSLog(@"********** voice call disconnected **********/n"); } } @end
calling Objective-C from Qt:
CL_ObjCCall::CL_objectiveC_Call()
Any Idea highly appreciated.
Best,
Marek -
You can call ObjC functions from cpp when you declare them as external (e.g. external void objC_function(void);) in your cpp file.
In your .mm file you can write this function just like a normal c function. Inside this function you can access ObjC objects.If you want to call cpp functions from ObjC code you can do that with call back functions.
For example:
ObjC (.mm) file:void (*ptrCallBack)(int arg) = nil; // declare a pointer to the call back function // use this function to set the call back function (later called from cpp code) void setCallBackFunction(void (*cbFunction)(int arg)) { ptrCallBack = cbFunction; }
// write a function to call the callback function from your ObjC or Swift code void call_CallBack(int arg) { if(ptrCallBack != nil) ptrCallBack(arg); }
However you must declare *external setCallBack(void (cbFunction(int arg)); in your cpp file.
In your cpp code:
myClass *ptrToMyClass = nullptr; // init this pointer after the instantiation of myClass. void objC_callbackFunction(int arg) { // do something with arg // if you have a pointer to your cpp class, than you can call class member functions if(ptrToMyClass) ptrToMyClass->memberFunction(arg); } // call this in your cpp code to set the call back function setCallBack(&objC_callbackFunction);
Note, this don't work with c++ class member functions.
I know, this is a little bit ugly to use this workaround with call back functions. But it works when you consider a few things like nil pointer check.
-
@ad1170 I tried to rewrite these functions to ios notation like:
-(int)iosCallObserver:(int)fake;
but still I would have to set callback from CL_ObjCCall something like this:
[CL_obj setCallBack:(&objC_callbackFunction)];I have noticed that inside
cl_objc_func.m
I can access my Singletonelse if(call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false) { NSLog(@"********** voice call incoming **********/n"); //here I need to call Qt to stop recorder Config::get().stopRecorder() }
And it works, just how to call some function from Singleton to my Recorder class, easiest it would be via signal but I have error: no matching function to connect to Singleton&
In Singleton.cpp file if I define
extern "C" void stop_recorder()
then I can call this stop_recorder() function but it does not know about Recorder classMaybe its late, but more help needed ;)
Best,
Marek -
OK, I think I have solved this problem, but Thanks for help.
So for posterity:I have Singleton in my application and I can call functions from Singleton inside .mm file
else if(call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false) { NSLog(@"********** voice call incoming **********/n"); //here I need to call Qt to stop recorder Config::get().stopRecorder() }
Then in Singleton I have void pointer and two extern functions defined
void *pointer extern "C" void first_function(); extern "C" void second_function();
Inside class that I need to have access to I'm initiating this pointer
Config::get().pointer=(void*)this
In Singleton cpp (which is called from .mm file, BTW I have changed cl_obj_func.m to cl_obj_func.mm without changing anything inside .m or .h file)
void Config::stopRecorder() { qDebug()<<"Config::stopRecorder"; first_function(); } void first_function() { second_function(); }
second_function is defined in config.h (Singleton as extern) but body is in main class
void stop_recorder2() { Recorder *r=(Recorder*)Config::get().recorder; r->stopRecorder(); }
So in short, from Singleton I call first extern function which calls second extern function from file in main class, so I have all headers included and Recorder object is known to compiler.
Best,
Marek -
Hi Marek,
glad to hear that your issue is solved. I've seen, i forgot the extern "C" ... in my post, sorry.
At the time where i have implemented this, I had found this way, but your way seems to be better.