Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 Singleton

    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()
        }
    

    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 class

    Maybe 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.


Log in to reply