【问题标题】:PortAudio callbacks, and changing a variable elsewherePortAudio 回调,并在别处更改变量
【发布时间】:2016-11-15 10:27:45
【问题描述】:

我正在使用 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 回调文档指出:

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

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

1) 我有哪些选择?

2) 如果我将其设为全局并将其设置在程序的另一部分(另一个线程)中,那么绝对最坏的情况是什么?再说一次,我的意思是指将数据损坏到程序故障/等等。

有正确的方法吗?

【问题讨论】:

    标签: c thread-safety portaudio


    【解决方案1】:

    我不完全确定您到底想做什么,但我猜这就是您的标题所要求的 - “在别处更改变量”。

    让我们举个例子:你有一个随时间变化的变量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;
    }
    

    希望对您有所帮助。

    【讨论】:

    • 是的,这很完美。我非常关心线程安全、原子性和全局变量,我没有看到简单的答案:PA 为您提供了这种机制。
    • 你不用担心自己学习一个新的 API 很困难......幸运的是,当我学习 PortAudio 时有一位很棒的老师,所以它让事情变得容易多了。祝你工作顺利!
    • 嗨@yun.cloud,我最近开始使用portaudio进行语音采集和处理,在实现它时遇到了一些问题。我在此处的 stackoverflow 上发布了问题(stackoverflow.com/questions/44645466/…)。非常感谢任何形式的帮助。
    猜你喜欢
    • 1970-01-01
    • 2017-03-16
    • 2014-08-06
    • 2015-06-25
    • 1970-01-01
    • 2017-05-16
    • 2018-10-07
    • 1970-01-01
    • 2014-11-28
    相关资源
    最近更新 更多