C CoreFoundation 인터페이스를 음성 합성 관리자에 사용하려고합니다. 음성 콜백을 등록하는 방법 (예 : kSpeechSpeechDoneCallBack
또는 kSpeechTextDoneCallBack
)은 무엇입니까? 나는 오래된 기능을 사용하는 방법을 알고있다 SetSpeechInfo
함수; 새로운 SetSpeechProperty
으로 어떻게 할 수 있습니까? 사용하려고하면 등록 된 함수를 호출하는 대신 "Segmentation fault : 11"이 발생합니다.SpeakCFString을 사용할 때 음성 콜백을 설정하는 방법은 무엇입니까?
Speech-Channel Properties에 따르면, 나는 값이 원하는 함수 포인터 인 long
CFNumberRef
을 전달해야한다고 생각합니다.
다음은 간단한 예입니다. 주 스레드가 콜백을 등록하고 음성이 끝나기를 기다립니다. 그러나 콜백을 호출하는 대신 디스패치 스레드에서 "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;
}