2011-08-05 39 views
8

Tôi đã tìm kiếm và tìm thấy một triệu kết quả cho chủ đề này. Nhưng không có trang nào giúp tôi. Tôi nghĩ rằng tôi có một vấn đề rất phổ biến. Tôi đang chơi xung quanh với lập trình âm thanh đặc biệt là làm việc với hàng đợi âm thanh. Mục đích của chương trình của tôi không quan trọng cho việc giải thích vấn đề. Nhưng trong một nutshell: Tôi nhận được một lỗi khi tôi cố gắng gọi một chức năng mục tiêu-c từ c + + mã. Vì vậy, đây là mã của tôi có chứa các lỗi: AudioRecorder.h:Gọi chức năng C Mục tiêu từ Mã C++

#import <Foundation/Foundation.h> 


@interface AudioRecorder : NSObject { 

} 

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

@end 

Và đây là việc thực hiện: 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...."); 
} 

Khi tôi bỏ qua "[tự playAlarmSound];" sau đó mọi thứ hoạt động tốt. Vậy làm cách nào để gọi hàm Objective-C này từ mã C++ của tôi?

Trả lời

6

self chỉ tồn tại trong các phương pháp Mục tiêu-C và đó là hàm kiểu C. Bạn cần phải vượt qua self từ một phương pháp Objective-C đến inUserData khi bạn thiết lập gọi lại, sau đó đưa nó trở lại đúng loại.

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

Và thực hiện ban đầu của bạn

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

@mbehan bạn đã đúng :) – Joe

+1

Đúng, nhưng tôi cho rằng nguyên nhân sâu xa 'tự' là mất tích là vì đây không phải là một phương pháp của lớp học, không phải vì đó là một chức năng kiểu C. Bất kỳ đối tượng Objective-C nào cũng có thể sử dụng trong hàm này - nó chỉ là 'self' chỉ có sẵn trong các phương thức của một lớp. – Luke

+0

Tôi tin rằng đó là những gì tôi đã nói "tự chỉ tồn tại trong các phương pháp Objective-C và đó là một chức năng kiểu C" có lỗi đánh máy ban đầu khi nó nói nhưng điều đó sẽ truyền tải cùng một thông điệp. – Joe

4

Đây thực sự là một vấn đề phổ biến. self không hoạt động ở đây vì đây không phải là phương thức của lớp AudioRecorder, không phải vì đó là mã Mục tiêu-C. Bạn đang ở trong một tệp Objective-C++, vì vậy tất cả mã Objective-C hợp lệ sẽ hoạt động. [anAudioRecorder playAlarmSound] sẽ hoạt động tốt, miễn là bạn có tham chiếu tốt đến anAudioRecorder.

Vậy làm cách nào để chúng tôi tham khảo nếu chúng tôi không có quyền truy cập vào self? Cách thông thường là sử dụng đối số void* aqData của hàm này làm con trỏ đến đối tượng AudioRecorder của bạn. Khi bạn đăng ký gọi lại này, bạn đã nói với đối số void* là gì, trong trường hợp này, con trỏ đến đối tượng hoặc cấu trúc AQRecorderState của bạn, mà bạn dường như không sử dụng. Thay vào đó, bạn có thể sử dụng con trỏ đến self khi bạn đăng ký để bạn có thể sử dụng đối tượng đó tại đây.

Một tùy chọn khác sẽ là sử dụng đối tượng được chia sẻ AudioRecorder, trong trường hợp này bạn sẽ gọi một cái gì đó như [AudioRecorder sharedInstance] (một lớp, không phải là một cá thể, phương pháp) để nhận đối tượng AudioRecorder bạn muốn. Bởi vì câu trả lời khác ở đây rõ về các phương pháp đầu tiên, dưới đây là cách sử dụng tùy chọn dụ chia sẻ: Thêm một trường hợp tĩnh của AudioRecorder và một phương pháp học sharedInstance để đối tượng AudioRecorder của bạn, như thế này:

static AudioRecorder* sharedMyInstance = nil; 

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

Sau đó, khi bạn muốn sử dụng số AudioRecorder từ cuộc gọi lại của bạn, bạn có thể lấy phiên bản dùng chung bằng cách sử dụng [AudioRecorder sharedInstance]. Đây là một mô hình rất hữu ích nếu chỉ có một AudioRecorder - nó loại bỏ rất nhiều tham chiếu đi qua.