Calling an Objective-C function from C ++ code

I googled around and I find a million results to this question. But not one of the pages helps me. I think I have a very common problem. I play with audio programs, especially when working with audio queues. The purpose of my program is not relevant to explain the problem. But in a nutshell: I get an error when I try to call the objective-c function from C ++ code. So, here is my code that contains the error: AudioRecorder.h:

#import <Foundation/Foundation.h> @interface AudioRecorder : NSObject { } -(void)setup; -(void)startRecording; -(void)endRecording; -(void)playAlarmSound; @end 

And this is the implementation: AudioRecorder.mm:

 #import "AudioRecorder.h" #include <AudioToolbox/AudioToolbox.h> #include <iostream> using namespace std; @implementation AudioRecorder static const int kNumberBuffers = 3; ... static void HandleInputBuffer (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc ) { AQRecorderState *pAqData = (AQRecorderState *) aqData; if (inNumPackets == 0 && pAqData->mDataFormat.mBytesPerPacket != 0) inNumPackets = inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket; UInt32 size; AudioQueueGetPropertySize ( inAQ, kAudioQueueProperty_CurrentLevelMeter, &size ); char* levelMeterData = new char[size]; AudioQueueGetProperty ( inAQ, kAudioQueueProperty_CurrentLevelMeter, levelMeterData, &size ); AudioQueueLevelMeterState* meterState = reinterpret_cast<AudioQueueLevelMeterState*>(levelMeterData); cout << "mAveragePower = " << meterState->mAveragePower << endl; cout << "mPeakPower = " << meterState->mPeakPower << endl; delete levelMeterData; [self playAlarmSound]; //<--- here I get the error: Use of undeclared identifier 'self' if (pAqData->mIsRunning == 0) return; AudioQueueEnqueueBuffer ( pAqData->mQueue, inBuffer, 0, NULL ); } ... -(void)playAlarmSound { NSLog(@"Alarmsound...."); } 

When I omit "[self playAlarmSound];" then everything works fine. So, how can I call this objective-c function from my C ++ code?

+8
c ++ objective-c call
source share
2 answers

self exists only in Objective-C methods, and it is a C-style function. You need to pass self from the Objective-C method to inUserData when setting up the callback, and then return it to the correct type.

 //This is an example for using AudioQueueNewInput //Call this in an Objective-C method passing self to inUserData AudioQueueNewInput ( const AudioStreamBasicDescription *inFormat, AudioQueueInputCallback inCallbackProc, // this is where you will pass (void*)self void *inUserData, CFRunLoopRef inCallbackRunLoop, CFStringRef inCallbackRunLoopMode, UInt32 inFlags, AudioQueueRef *outAQ ); 

And your original implementation

 static void HandleInputBuffer (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc ) { AudioRecorder *ar_instance = (AudioRecorder*)aqData; ... [ar_instance playAlarmSound]; ... } 
+6
source share

This is a really common problem. self does not work here because it is not a method of the AudioRecorder class, and not because it has Objective-C code. You are in an Objective-C ++ file, so all valid Objective-C code will work. [anAudioRecorder playAlarmSound] will work fine if you have a good link to anAudioRecorder .

So, how do we get the link if we do not have access to self ? The usual way is to use the void* aqData this function as a pointer to your AudioRecorder object. When you registered this callback, you told him that the void* argument would, in this case, be a pointer to your object or AQRecorderState structure, which seems not to be used yet. Instead, you can use a pointer to self when registering so you can use this object here.

Another option would be to use a shared AudioRecorder object, in which case you call something like [AudioRecorder sharedInstance] (a class method, not an instance) to get the desired AudioRecorder object. Since another answer here details the first method, how to use the shared instance parameter: add a static instance of AudioRecorder and a method of the sharedInstance class to your AudioRecorder object, for example:

 static AudioRecorder* sharedMyInstance = nil; + (id) sharedInstance { @synchronized(self) { if( sharedMyInstance == nil ) sharedMyInstance = [[super allocWithZone:NULL] init]; } return sharedMyInstance; } // end sharedInstance() 

Then, when you want to use AudioRecorder from your callback, you can get the shared instance using [AudioRecorder sharedInstance] . This is a very useful paradigm if there is only one AudioRecorder - it removes many links.

+4
source share

All Articles