Вызов функции Objective C из кода C ++ - PullRequest
8 голосов
/ 05 августа 2011

Я погуглил и нашел миллион результатов по этой теме.Но ни одна из страниц не помогает мне.Я думаю, что у меня очень распространенная проблема.Я играю с аудио-программированием, особенно работаю с аудио-очередями.Цель моей программы не имеет значения для объяснения проблемы.Но в двух словах: я получаю ошибку, когда пытаюсь вызвать функцию target-c из кода c ++.Так вот мой код, который содержит ошибку: AudioRecorder.h:

#import <Foundation/Foundation.h>


@interface AudioRecorder : NSObject {

}

-(void)setup;
-(void)startRecording;
-(void)endRecording;
-(void)playAlarmSound;

@end

И это реализация: 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....");
}

Когда я опускаю "[self playAlarmSound];»тогда все работает нормально.Итак, как мне вызвать эту функцию Objective C из моего кода C ++?

Ответы [ 2 ]

6 голосов
/ 05 августа 2011

self существует только в методах Objective-C, и это функция стиля C.Вам нужно передать self из метода Objective C в inUserData при настройке обратного вызова, а затем привести его обратно к правильному типу.

//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
);

И ваша первоначальная реализация

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];
    ...
}
4 голосов
/ 05 августа 2011

Это действительно распространенная проблема. self здесь не работает, потому что это не метод класса AudioRecorder, а не потому, что это код Objective-C. Вы находитесь в файле Objective-C ++, поэтому все действующие коды Objective-C будут работать. [anAudioRecorder playAlarmSound] будет работать нормально, если у вас есть хорошая ссылка на anAudioRecorder.

Так как же получить справку, если у нас нет доступа к self? Обычный способ - использовать аргумент void* aqData этой функции в качестве указателя на ваш AudioRecorder объект. Когда вы зарегистрировали этот обратный вызов, вы сказали ему, каким будет аргумент void*, в данном случае указатель на ваш объект или структуру AQRecorderState, которые вы, похоже, не используете. Вместо этого вы можете использовать указатель на self при регистрации, чтобы вы могли использовать этот объект здесь.

Другой вариант - использовать общий объект AudioRecorder, и в этом случае вы должны вызвать что-то вроде [AudioRecorder sharedInstance] (класс, а не экземпляр, метод), чтобы получить нужный объект AudioRecorder. Поскольку другой ответ здесь раскрывает первый метод, здесь показано, как использовать параметр общего экземпляра: добавьте статический экземпляр AudioRecorder и метод класса sharedInstance к вашему AudioRecorder объекту, например так:

static AudioRecorder* sharedMyInstance = nil;

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

Затем, когда вы захотите использовать AudioRecorder в вашем обратном вызове, вы можете получить общий экземпляр, используя [AudioRecorder sharedInstance]. Это очень полезная парадигма, если будет только один AudioRecorder - она ​​исключает много ссылок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...