PortAudio 回调,并在别处更改变量

PortAudio callbacks, and changing a variable elsewhere

我正在使用 PortAudio 的回调 API 来设计信号处理环回库。

我想在回调中添加一个依赖于标志的分支,比如

int pa_callback(const void *inputuffer,
                 void *outputBuffer,
                 unsigned long frameCount,
                 const PaStreamCallbackTimeInfo *timeInfo,
                 PaStreamCallbackFlags statusFlags,
                 void *userData)
{
  if (do_something_flag) {
    do_something(inputBuffer, outputBuffer, frameCount);
  } else {
    do_something_else(inputBuffer, outputBuffer, frameCount);
  }

  return paContinue;
}

其中 do_something_flag 是在我程序的其他地方定期设置的。

PortAudio 回调文档指出:

Before we begin, it's important to realize that the callback is a delicate place. This is because some systems perform the callback in a special thread, or interrupt handler, and it is rarely treated the same as the rest of your code. For most modern systems, you won't be able to cause crashes by making disallowed calls in the callback, but if you want your code to produce glitch-free audio, you will have to make sure you avoid function calls that may take an unbounded amount of time to execute. Exactly what these are depend on your platform but almost certainly include the following: memory allocation/deallocation, I/O (including file I/O as well as console I/O, such as printf()), context switching (such as exec() or yield()), mutex operations, or anything else that might rely on the OS. If you think short critical sections are safe please go read about priority inversion.

我不关心 do_something_flag 的原子性。也就是说,我不在乎需要多少个周期才能获得正确的值(在合理范围内)。 根据文档,看起来我不能为 setting/reading 那个变量使用互斥量。

1) 我有哪些选择?

2) 如果我将其设置为全局并将其设置在我程序的另一部分(另一个线程)中,最糟糕的情况会发生什么?同样,我的意思是将数据破坏到程序 failure/etc.

有正确的方法吗?

我不太确定你到底想做什么,但我猜这就是你的标题所问的内容 - "Changing a variable elsewhere"。

让我们举个例子:你有一个随时间变化的变量 frequency。你如何访问这个?那么你在回调中有一个通用指针,称为 userData。这可以指向任何东西——数据结构、数组等。我真的不记得回调函数被调用的频率(它经常......我不担心速度)但是 userData 允许你有可以在你的主线程中改变的变量,而音频线程中的指针允许你直接在内存中访问它......我对线程安全的了解不是最好的,如果那不是最好的,我很抱歉解释,但我至少可以告诉你如何通过代码(下面)来做到这一点。

这是我通常做的,但你不需要自己做;我在文件的顶部设置了一个结构,如下所示:

typedef struct {
    float freq;
    float vol;
}paData;

显然,您将在代码中的某处(可能在您的 main 函数调用中)初始化它并打开音频流(datapaData 类型):

/* Open audio stream */
err = Pa_OpenStream(&(*stream),
        &inputParameters,
        &outputParameters,
        SAMPLE_RATE, bufSize, paNoFlag, 
        paCallback, &data);

打开后,您可以像这样收到回调:

static int pa_callback(const void *inputBffer,
             void *outputBuffer,
             unsigned long frameCount,
             const PaStreamCallbackTimeInfo *timeInfo,
             PaStreamCallbackFlags statusFlags,
             void *userData)
{
    // cast data so we can use it
    paData *data = (paData *)userData;

    // what's our frequency?
    printf("%f\n", data->freq);

    /* Do something with your code here */

    return paContinue;
}

希望对您有所帮助。