PortAudio回调,并在其他地方更改变量

时间:2016-07-13 01:50:41

标签: c thread-safety portaudio

我使用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回调文档声明:

  

在开始之前,了解回调是一个非常重要   精致的地方。这是因为某些系统在a中执行回调   特殊线程,或中断处理程序,它很少被处理   与其余代码相同。对于大多数现代系统,你不会成为现实   能够通过在回调中进行不允许的调用来导致崩溃,但是   如果您希望您的代码产生无故障音频,您将不得不这样做   确保你避免可能需要无限量的函数调用   时间执行。究竟是什么取决于您的平台,但   几乎肯定包括以下内容:记忆   分配/解除分配,I / O(包括文件I / O以及控制台   I / O,例如printf()),上下文切换(例如exec()或yield()),   互斥操作,或任何可能依赖于操作系统的操作。如果你   认为简短的关键部分是安全的请阅读优先权   反转。

我不关心do_something_flag的原子性。也就是说,我不关心获得正确值(在合理范围内)需要多少周期。 根据文档,看起来我不能使用互斥锁来设置/读取该变量。

1)我的选择是什么?

2)如果我将其设置为全局并将其设置在我的程序的另一部分(另一个线程)中,那将会发生什么样的绝对最差?同样,我的意思是在破坏数据到程序失败等方面。

有没有正确的方法呢?

1 个答案:

答案 0 :(得分:1)

我不完全确定你正在尝试做什么,但我猜测你的标题是什么 - "在其他地方更改变量&#34 ;

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

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

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

显然,您会在代码中的某处(可能在main函数调用中)初始化此内容并打开音频流(data类型为paData):

/* 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;
}

希望有所帮助。