如何在使用SpeakCFString时设置语音回调



我正在尝试使用语音合成管理器的C CoreFoundation接口。如何注册语音回调(如kSpeechSpeechDoneCallBackkSpeechTextDoneCallBack)?我知道如何使用过时的SetSpeechInfo函数;你如何使用新的SetSpeechProperty?当我尝试使用它时,它会导致"Segmentation fault:11",而不是调用我注册的函数。

根据Speech Channel Properties,我认为您应该传入一个long CFNumberRef,其值是所需的函数指针。

这里有一个简单的例子,主线程注册一个回调并等待语音结束。但是调度线程没有调用回调,而是给出错误"EXC_BAD_ACCESS(代码=13,地址=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 %pn", 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;
}

重读文档后,我意识到我对CFNumberCreate的调用是错误的;我给了它数字的,而它实际上需要一个指针来数字。因此,在这种情况下,我需要传入一个指向函数指针的指针和一个指向结构指针的指针:

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

多么愚蠢的错误!

最新更新