PortAudio如何通过回调将音频数据缓冲到设备中,以及输出指针的行为如何?

时间:2019-05-27 14:51:22

标签: c++ c linux debian portaudio

我正在使用带有ALSA的Debian 9和PortAudio来创建和应用程序,该应用程序可以将任意音频数据发送到24通道MOTU 24Ao设备。设备为USB 2.0。我的应用程序成功打开一个流以将数据发送到设备,并使用回调(PaStreamCallback)通过memcpy操作将数据提供给输出缓冲区。只要应用程序继续运行,流就保持打开状态。每当准备好发送数据时,回调就会将数据提供给设备,如果没有要播放的数据,则回调会静音。

该应用程序可以正常运行,但仅需要一定时间(约5分钟)。此后,数据开始以“转移和损坏的方式”播放。例如,我尝试在通道1中播放一个正弦波,并在其他23个通道中播放一个零正弦波,持续时间为400毫秒。每当我按键盘上的一个键时,就会播放该音乐。刚开始时,所有操作都可以与回调一起正常工作,并且当我按下该键时,数据会在相应的通道上播放。 5分钟后,当我按键时,通道1和通道9开始播放数据。两个通道上的数据都不是正确的正弦波,而是信号的错误重构。当我按住启动键时,这种情况持续约1分钟。在这段时间之后,正弦波开始正常播放,但现在在第9通道开始播放,而在其他23个通道上保持静音。在其他时间段后,此行为将重复出现,但现在涉及通道9和17,最终使通道17播放正弦波。

这种情况反复发生,并且看起来输出缓冲区以循环的方式映射我的数据,即通道1映射到9,过一会儿,它映射到17,然后又回到1。 8个通道的偏移量(1 + 8 = 9、9 + 8 = 17和17 + 8 = 1)。当我尝试在Windows中实现相同的代码时,这种奇怪的变化永远不会发生。

我曾经尝试过切换MOTU设备,甚至尝试过干净安装Debian,而没有PortAudio。

我播放的信号始终存储在一个浮动缓冲区中,该缓冲区具有从左到右,从上到下的线性数组形式的矩阵状结构。每个矩阵有24列(每个通道1个)和一定数量的行,该行数由每个信号的持续时间以及用于创建它们的采样频率(所有信号为44.1 kHz)确定。每个矩阵都包含在Symbol对象中,该对象可以:确定要消耗的矩阵剩余行数(Symbol::remainingRows()),获取表示矩阵中哪些行的当前索引保留在此索引(Symbol::getMatrixRowIndex()之后使用,从某个行索引(Symbol::samplesFromRow())开始获取指向矩阵中所有样本的指针,并增加表示以下行的行索引尚未消耗(Symbol::increaseIndexBy(int increase))。通过这种结构,以下是我的PaCallback:

int MotuPlayer::paCallback(const void *inputBuffer, void *outputBuffer,
                            unsigned long framesPerBuffer,
                            const PaStreamCallbackTimeInfo* timeInfo,
                            PaStreamCallbackFlags statusFlags,
                            void *userData)
    {      
        float *out = (float*)outputBuffer;
        MotuPlayer *player = (MotuPlayer*)userData;
        Symbol* symbol = player->getCurrentPlayingSymbol();
        unsigned long i;
        (void) timeInfo; /* Prevent unused variable warnings. */
        (void) statusFlags;
        (void) inputBuffer;

        if(symbol != 0)
        {
            unsigned long rowsRemaining = symbol->remainingRows();
            if( rowsRemaining <= framesPerBuffer)
            {
                //Copy the remaining samples into the buffer
                memcpy(out, symbol->samplesFromRow((int)symbol->getMatrixRowIndex()), sizeof(float)*rowsRemaining*24);

                //Fill the rest of the buffer with zeros
                out += 24*rowsRemaining;
                memcpy(out, player->getZeros(), sizeof(float)*24*(framesPerBuffer-rowsRemaining));
                player->signalSymbolCallback(TapsNoError);
                player->currentPlayingSymbol = 0;
            }
            else
            {
                //Fill all the frames of the buffer with data from matrix and increase the index by the frames consumed
                memcpy(out, symbol->samplesFromRow((int)symbol->getMatrixRowIndex()), sizeof(float)*framesPerBuffer*24);
                symbol->increaseIndexBy(framesPerBuffer);
            }
        }
        else
        {
            memcpy(out, player->getZeros(), sizeof(float)*24*framesPerBuffer);
        }

        return paContinue;

由于相同的代码在Windows中没有表现出这种现象,因此我无法确定问题的原因。我想知道PortAudio是否使用某种环形缓冲区将我的数据播放到硬件中,是否可能是问题所在。在我看来,输出缓冲区指针的行为是问题的根源,但实际上并不知道有什么解决方案。

0 个答案:

没有答案