2011-08-05 24 views
8

私は周りを探索し、私はこの主題に対して百万の結果を見つけました。しかし、どのページも私を助けません。私は非常に共通の問題があると思います。私は、特にオーディオキューで作業するオーディオプログラミングで遊んでいます。私のプログラムの目的は、問題の説明には関係ありません。しかし簡単に言えば、C++コードからobjective-c関数を呼び出そうとするとエラーが発生します。 AudioRecorder.h:だからここにエラーが含まれている私のコードですC++コードから目的のC関数を呼び出す

#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...."); 
} 

"[自己playAlarmSound];"すべてうまくいく。 C++コードからこのObjective-C関数をどのように呼び出すのですか?

答えて

6

selfはObjective-Cメソッドにのみ存在し、それはCスタイルの関数です。コールバックを設定するときにObjective-Cメソッドのselfを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]; 
    ... 
} 
+0

あなたが正しい:) – Joe

+1

本当だった@mbehanが、私は、これはの方法ではありませんので、「自己」は不足している根本的な理由があると主張するだろうこれはCスタイルの関数ではありません。 Objective-Cオブジェクトはこの関数内で使用できます。つまり、 'self'はクラスのメソッドでのみ使用できます。 – Luke

+0

私はそれが "Objective-Cメソッドにのみ存在し、それはCスタイルの関数である"と言っていると信じています。元々は、同じメッセージを伝えるはずです。 – Joe

4

これは実際には一般的な問題です。 selfは、AudioRecorderクラスのメソッドではないため、Objective-Cコードではなく、ここでは機能しません。あなたはObjective-C++ファイルを使用しているので、有効なObjective-Cコードはすべて動作します。 anAudioRecorderへの参照があれば、[anAudioRecorder playAlarmSound]は正常に動作します。

selfにアクセスできない場合は、どうすれば参考資料を入手できますか?通常の方法は、この関数のvoid* aqData引数をAudioRecorderオブジェクトへのポインタとして使用することです。このコールバックを登録すると、引数(この場合はAQRecorderStateオブジェクトまたは構造体へのポインタ)が返されますが、これはとにかく使用されていないようです。代わりに登録するとselfへのポインタを使用して、そのオブジェクトをここで使用できるようにすることができます。

別のオプションは、あなたが欲しい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を使用したい場合は、[AudioRecorder sharedInstance]を使用して共有インスタンスを取得できます。 AudioRecorderが1つしか存在しない場合、これは非常に有用なパラダイムです。これは、多くの参照渡しを排除します。

関連する問題