C++ 解码音频后调用阻塞snd_pcm_writei是否会导致奇怪的播放?

C++ 解码音频后调用阻塞snd_pcm_writei是否会导致奇怪的播放?,c++,buffer,latency,alsa,opus,C++,Buffer,Latency,Alsa,Opus,如果我的题目很糟糕,请原谅。我妻子总是告诉我,我不擅长措辞 我已经编写了一些代码来读取由另一个线程填充的缓冲区。缓冲区由opus编解码器编码的音频数据填充。VoIP数据从远程接收,每次20毫秒。为了尽可能快地播放音频,在循环中,我一次从缓冲区中取出20毫秒的数据,然后解码,然后直接发送到snd_pcm_writei上播放 我在谷歌上搜索了一些使用snd_pcm_writei和先前编码的音频的例子,看看其他人是怎么做的。我运气不太好 我的想法是,如果我在等待互斥和编码,逻辑上看不到音频是“平滑的”

如果我的题目很糟糕,请原谅。我妻子总是告诉我,我不擅长措辞

我已经编写了一些代码来读取由另一个线程填充的缓冲区。缓冲区由opus编解码器编码的音频数据填充。VoIP数据从远程接收,每次20毫秒。为了尽可能快地播放音频,在循环中,我一次从缓冲区中取出20毫秒的数据,然后解码,然后直接发送到snd_pcm_writei上播放

我在谷歌上搜索了一些使用snd_pcm_writei和先前编码的音频的例子,看看其他人是怎么做的。我运气不太好

我的想法是,如果我在等待互斥和编码,逻辑上看不到音频是“平滑的”。我可以想象,在每20毫秒的帧之间,有一段时间间隔,没有音频被发送到扬声器。我的怀疑是否正确,这可能会产生不完美的音频

我的代码与此相关:

while( true )
{
    // We need a positive lock
    if( !buffer_lock )
        buffer_lock.lock();

    LOG_DEBUG( *logger_ ) << "After the mutex lock.";
    LOG_DEBUG( *logger_ ) << "Buffer size: " << current_audio->buffer_size_; 
    LOG_DEBUG( *logger_ ) << "Read pointer: " << current_audio->read_pointer_; 

    opus_int32 payload_size;

    LOG_DEBUG( *logger_ ) << "calling audioCanDecodeChunk()";

    // Now fisticuffs do we have enouffs?
    if( audioCanDecodeChunk( current_audio, payload_size ) )
    {
        LOG_DEBUG( *logger_ ) << "We have enough current_audio buffer.";

        // Are we dank?
        if( payload_size<0 or payload_size>MAX_PACKET )
        {
            LOG_ERROR( *logger_ ) << "Decoding error, payload size (" << payload_size << ") is outsize range.";
            break; // Terminal
        }

        // We have enough!
        // Advance the read pointer
        current_audio->read_pointer_+= 4;

        // Copy it out
        memcpy( payload_buffer, current_audio->buffer_+current_audio->read_pointer_, payload_size );

        // Release it
        buffer_lock.unlock();

        // Now thingify it
        int samples_decoded = opus_decode( opus_decoder_,
                (const unsigned char *)payload_buffer,
                payload_size,
                (opus_int16 *)pcm_buffer,
                MAX_FRAME_SIZE,
                0 );

        // How did we do?
        if( samples_decoded<0 )
        {
            // What hap?
            LOG_ERROR( *logger_ ) << "Error decoding samples: " << opus_strerror( samples_decoded );
            break;
        }
        else
        {
            // Now we have our PCM!
            int bytes_decoded = current_audio->recording_.channels*sizeof( opus_int16 )*samples_decoded;

            LOG_DEBUG( *logger_ ) << "We have decoded " << bytes_decoded << " bytes payload: " << payload_size;

            // Now write
            if( (error = snd_pcm_writei( playback_handle_, pcm_buffer, samples_decoded ))!=samples_decoded )
            {
                LOG_ERROR( *logger_ ) << "snd_pcm_writei error: " << snd_strerror( error );
            }
        }

        // Advance pointer
        current_audio->read_pointer_+= payload_size;

    } // If we don't have enough let it slide and unlock
    else if( current_audio->done_ ) // Were we issued a flush?
    {
        LOG_DEBUG( *logger_ ) << "We are done.";

        // We are done with this loop
        break;
    }
    else
    {
        // Wait for it (an update)
        LOG_DEBUG( *logger_ ) << "Before wait_buffer wait. Done: " << ( current_audio->done_ ? "true" : "false" ) <<
            "Size: " << current_audio->buffer_size_ 
            << ", Read: " << current_audio->read_pointer_;
        current_audio->wait_buffer_.wait( buffer_lock );
        LOG_DEBUG( *logger_ ) << "After wait_buffer wait";
    }

} // End while( true )
while(true)
{
//我们需要一个正锁
如果(!缓冲区锁定)
buffer_lock.lock();

LOG_DEBUG(*logger_)如果写入20毫秒数据块之间的时间正好是20毫秒,则在写入新数据块时,设备的缓冲区将为空。即使是最小的延迟也会导致运行不足

为了防止缓冲区不足,您必须尽可能保持缓冲区已满。这意味着在开始时,您必须在块之间填充缓冲区,而不必等待


当发送方的时钟运行速度快于设备的时钟时,数据流最终将运行不足。这可以通过测量时钟差、更改发送方的传输速率或动态重新采样数据来避免。

PCM设备的缓冲区大于20毫秒,不是吗?是的。我可能没有提到我为什么要这样做是的。我也会编辑我的问题。这是一个VoIP类型的应用程序,数据一次接收20毫秒。所以我只是想尽快播放。所以发送方的时钟和设备的时钟不同步?问题更多的是,是否会有明显的延迟,因为我在调用函数之前正在解码。例如,如果我只是直接从PCM缓冲区传递数据,那么从获取缓冲区数据到调用play函数之间的时钟周期会少得多。但在我的示例中,我首先获取缓冲区,然后对其进行解码,最后将其传递给play函数。因此,我担心所有这些计算都会导致速度减慢音频播放。