2013-06-24 9 views
1

C CoreFoundation 인터페이스를 음성 합성 관리자에 사용하려고합니다. 음성 콜백을 등록하는 방법 (예 : kSpeechSpeechDoneCallBack 또는 kSpeechTextDoneCallBack)은 무엇입니까? 나는 오래된 기능을 사용하는 방법을 알고있다 SetSpeechInfo 함수; 새로운 SetSpeechProperty으로 어떻게 할 수 있습니까? 사용하려고하면 등록 된 함수를 호출하는 대신 "Segmentation fault : 11"이 발생합니다.SpeakCFString을 사용할 때 음성 콜백을 설정하는 방법은 무엇입니까?

Speech-Channel Properties에 따르면, 나는 값이 원하는 함수 포인터 인 longCFNumberRef을 전달해야한다고 생각합니다.

다음은 간단한 예입니다. 주 스레드가 콜백을 등록하고 음성이 끝나기를 기다립니다. 그러나 콜백을 호출하는 대신 디스패치 스레드에서 "EXC_BAD_ACCESS (code = 13, address = 0x0)"오류가 발생합니다. 사용되지 않는 함수 (--old)를 사용하면 오류없이 콜백이 호출됩니다.

// clang -g -framework ApplicationServices main.c && ./a.out 
#include <stdio.h> 
#include <pthread.h> 
#include <ApplicationServices/ApplicationServices.h> 

void checkResult(OSErr error, const char *description) { 
    if (error == 0) 
     return; 
    fprintf(stderr, "Error: %d during %s. exiting.", error, description); 
    exit(error); 
} 

struct SpeechState { 
    pthread_mutex_t mutex; 
    pthread_cond_t speakingDone; 
    int stillSpeakingCount; 
}; 

void speechDone(SpeechChannel chan, SRefCon refCon) { 
    printf("Speech done!\n"); 
    struct SpeechState *speechState = (struct SpeechState*)refCon; 

    pthread_mutex_lock(&speechState->mutex); 
    speechState->stillSpeakingCount--; 
    pthread_cond_broadcast(&speechState->speakingDone); 
    pthread_mutex_unlock(&speechState->mutex); 
} 

int main(int argc, const char * argv[]) 
{ 
    bool old = false; 
    for (int i = 1; i < argc; i++) { 
     if (0 == strcmp(argv[i], "--old")) 
      old = true; 
    } 
    SpeechChannel chan; 
    checkResult(NewSpeechChannel((VoiceSpec*)NULL, &chan), "NewSpeechChannel"); 

    struct SpeechState speechState; 
    pthread_mutex_init(&speechState.mutex, NULL); 
    pthread_cond_init(&speechState.speakingDone, NULL); 

    if (! old) { 
     // The new way seems to crash. 
     CFNumberRef doneCallbackNumber = CFNumberCreate(NULL, kCFNumberLongType, speechDone); 
     CFNumberRef refConNumber = CFNumberCreate(NULL, kCFNumberLongType, &speechState); 
     printf("Registering speechDone callback for address %p\n", speechDone); 
     checkResult(SetSpeechProperty(chan, kSpeechSpeechDoneCallBack, doneCallbackNumber), "SetSpeechProperty(sdcb)"); 
     checkResult(SetSpeechProperty(chan, kSpeechRefConProperty, refConNumber), "SetSpeechProperty(refc)"); 
     CFRelease(doneCallbackNumber); 
     CFRelease(refConNumber); 
    } else { 
     // The deprecated way to do it works. 
     checkResult(SetSpeechInfo(chan, soSpeechDoneCallBack, &speechDone), "SetSpeechInfo(sdcb)"); 
     checkResult(SetSpeechInfo(chan, soRefCon, &speechState), "SetSpeechInfo(refc)"); 
    } 

    printf("Speaking...\n"); 
    CFStringRef string = CFStringCreateWithCString(NULL, "Most people recognize me by my voice!", kCFStringEncodingUTF8); 
    checkResult(SpeakCFString(chan, string, NULL), "SpeakCFString"); 
    CFRelease(string); 

    pthread_mutex_lock(&speechState.mutex); 
    speechState.stillSpeakingCount++; 
    while (speechState.stillSpeakingCount > 0) { 
     pthread_cond_wait(&speechState.speakingDone, &speechState.mutex); 
    } 
    pthread_mutex_unlock(&speechState.mutex); 

    printf("Done!\n"); 
    return 0; 
} 

답변

1

설명서를 다시 읽은 후에 나는 CFNumberCreate이라고 잘못 알았습니다. 숫자의 값이 인 반면 실제로는 포인터에 포인터가 있습니다. 그래서이 경우 함수 포인터에 대한 포인터와 구조체 포인터에 대한 포인터를 전달해야했습니다.

void (*speechDonePtr)(SpeechChannel, SRefCon) = speechDone; 
struct SpeechState *speechStatePtr = &speechState; 
CFNumberRef doneCallbackNumber = CFNumberCreate(NULL, kCFNumberLongType, &speechDonePtr); 
CFNumberRef refConNumber = CFNumberCreate(NULL, kCFNumberLongType, &speechStatePtr); 

어리석은 실수입니다!