QAudioOutput缓冲区下溢

时间:2016-12-02 09:11:37

标签: qt audio qt5

收到消息“有缓冲区下溢!”每次写完这个简单的程序之后。

Beep.hpp:

0.028171725121151

Beep.cpp:

func textView(_ textView: UITextView, shouldInteractWithURL URL: NSURL,   inRange characterRange: NSRange) -> Bool {
    /* perform your own custom actions here */

    print(URL)

    return true // return true if you still want UIAlertController to pop up

}

main.cpp中:

#pragma once

#include <QTimer>
#include <QAudioOutput>

class Beep: public QObject
{
    Q_OBJECT

public:
    explicit Beep();
    virtual ~Beep();

    void onTimer();

private:
    QAudioOutput m_out;
    QIODevice *m_outDev;
    QTimer m_timer;
};

这个测试程序只是用零写缓冲区。有了实际数据,就会出现破解声。

写更多数据或更改时间会让情况变得更糟。这段代码出了什么问题?

2 个答案:

答案 0 :(得分:0)

使用计时器是错误的方法。

使用notify()信号

void AudioManager::init_audio(AudioManager *mgr) {
    if (mgr->stream_id == -1) return;

    mgr->audio_format.setSampleRate(mgr->context->time_base.den);
    mgr->audio_format.setSampleSize(16);
    mgr->audio_format.setChannelCount(2);
    mgr->audio_format.setCodec("audio/pcm");
    mgr->audio_format.setSampleType(QAudioFormat::SignedInt);
    QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
    if (!info.isFormatSupported(mgr->audio_format)) {
        mgr->audio_format = info.nearestFormat(mgr->audio_format);
    }

    mgr->audio_out = new QAudioOutput(mgr->audio_format, nullptr);
    mgr->audio_out->setNotifyInterval(15);
    mgr->audio_out->setBufferSize(mgr->context->time_base.den * 4); // 1 second worth of stereo data

    connect(mgr->audio_out, SIGNAL(notify()), mgr, SLOT(audio_out_notify()));
    connect(mgr->audio_out, SIGNAL(stateChanged(QAudio::State)), mgr, SLOT(audio_out_state_changed(QAudio::State)));
    qreal volume_out = (qreal)parent->volume / 100.0f;
    mgr->audio_out->setVolume(volume_out);
    mgr->audio_out_device = mgr->audio_out->start();
}

当音频播放需要更多数据时,将调用此方法

void AudioManager::audio_out_notify() {
    qDebug() << "Audio notify";
    check_audio_playback();
}

下面的大部分代码都是无关紧要的,但也称为音频已经停止播放。

void AudioManager::check_audio_playback() {
    if (stream_id == -1) return;

    pthread_mutex_lock(&audio_mutex);

    if (!audio_out->state() == QAudio::State::IdleState) {
        pthread_mutex_unlock(&audio_mutex);
        return;
    }

    if (parent->pts_start_time < 0.0) {
        if (parent->Video.stream_id == -1 && decode_pos > 65) { // start playback
            parent->pts_start_time = buffers[0].frame_time;
            parent->sys_start_time = (double)parent->timer.elapsed() / 1000.0;
            qDebug() << "Audio playback started";
        } else {
            pthread_mutex_unlock(&audio_mutex);
            return;
        }
    }

    if (playback_pos == decode_pos) {
        pthread_mutex_unlock(&audio_mutex);
        return;
    }



    AudioBuffer *buffer = nullptr;
    double current_sys_time = ((double)parent->timer.elapsed() / 1000.0) - parent->sys_start_time;

    bool bounds = false;
    int skipped = 0;

    while (!bounds) {
        if (playback_pos == decode_pos) bounds = true;
        else {
            AudioBuffer *temp_buffer = &buffers[playback_pos];
            double temp_time = temp_buffer->frame_time - parent->pts_start_time;

            if (temp_time < current_sys_time ) {
                if (buffer) {
                    buffer->used = false;
                    skipped++;
                }
                buffer = temp_buffer;
                playback_pos++; playback_pos %= MAX_AUD_BUFFERS;
            } else {
                bounds = true;
            }
        }
    }

    if (skipped > 0) qDebug("Skipped %d audio buffers on playback", skipped);

    if (buffer) {
        audio_out_device->write((const char *)buffer->data, buffer->buffer_size);
        buffer->used = false;
    }

    pthread_mutex_unlock(&audio_mutex);
}

Qt网站上的例子起初不是那么明显http://qt.apidoc.info/5.1.1/qtmultimedia/audiooutput.html但是当我把它放进去测试时它并不是太糟糕。

答案 1 :(得分:0)

原因是音频数据的来源不是生产质量模块&#34; (它是一个虚拟测试类):计时器正在漂移,因为它的实际间隔是10ms加上处理时间。

其他观察:

  • QAudioOutput::setBufferSize()更大
  • 以符合QAudioInput::read()QAudioOutput::write()
  • 大小的块进行QAudioInput::periodSize()QAudioOutput::periodSize()