Audio mixing with ADDER results in broken sound

Karl Phillip maxphil at gmail.com
Wed Nov 23 04:59:47 PST 2011


Hi all,

I'm using QtGStreamer-0.10 to play a mp3 file and I'm having difficulties
finding out why the resulting sound is so horrible. I wrote the smallest
application possible to reproduce the problem I'm facing.

I'm working on a "audio mixer" component that allows you to have multiple
audio players instantiated and running. It's job is to mix all audio
received by the players and chose to do this task myself because the
soundcard I have is terrible and can't deal with 8, 9 audio players
simultaneously. So I'm hoping to make it's job easier by sending it only
one audio stream.

Let's jump into the code! The application below sets up 2 pipelines: the
first named "_ms_pipeline" (as in master pipeline), and its responsible for
mixing the audio using only 2 elements: an ADDER linked to AUTOAUDIOSINK.

The second pipeline, named only "pipeline", loads the file from the disk
through FILESRC, decodes it, does some stuff using the following elements:
APPSRC > VOLUME > AUDIOCONVERT > AUDIORESAMPLE > CAPSFILTER.

At the end I connect the src pad of CAPSFILTER to a sink pad of the ADDER,
then set the state of the pipelines to QGst::StatePlaying to start playing
the audio.

The result is awful.

#include <QtGui/QApplication>

#include <QList>
#include <QPointer>
#include <QObject>

#include <QGlib/Error>
#include <QGlib/Connect>
#include <QGst/Init>
#include <QGst/Bus>
#include <QGst/Pipeline>
#include <QGst/Parse>
#include <QGst/Message>
#include <QGst/Utils/ApplicationSink>
#include <QGst/Utils/ApplicationSource>
#include <QGst/ElementFactory>
#include <QGst/Element>
#include <QGst/Pad>
#include <QGst/Bin>

#include <iostream>

QGst::PipelinePtr _ms_pipeline;
QGst::ElementPtr _ms_adder;
QGst::ElementPtr _ms_output;

QGst::ElementPtr appsink;

class MySink : public QGst::Utils::ApplicationSink
{
public:
    MySink(QGst::Utils::ApplicationSource *src)
    : QGst::Utils::ApplicationSink(), m_src(src) {}

protected:
    virtual void eos()
    {
        m_src->endOfStream();
    }

    virtual QGst::FlowReturn newBuffer()
    {
        m_src->pushBuffer(pullBuffer());
        return QGst::FlowOk;
    }

private:
    QGst::Utils::ApplicationSource *m_src;
};


class Player : QObject
{
public:
    Player(const char* filename);
    ~Player() {};

    MySink m_sink;
    QGst::Utils::ApplicationSource m_src;

    void onNewDecodedPad(QGst::PadPtr pad)
    {
        std::cout << "Player::onNewDecodePad\n";
        QGst::CapsPtr caps = pad->caps();
        QGst::StructurePtr structure = caps->internalStructure(0);
        if (structure->name().contains("audio/x-raw"))
            std::cout << "Player::onNewDecodePad audio/x-raw\n";

        QGst::PadPtr saidaDecoder = appsink->getStaticPad("sink");
        if (pad->link(saidaDecoder) != QGst::PadLinkOk)
            std::cout << "Player::onNewDecodePad: Failed link !!!\n";

    }
};


int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: qtplayer <file.mp3>\n";
        return -1;
    }

    QApplication app(argc, argv);

    Player player(argv[1]);

    return app.exec();
}


Player::Player(const char* filename)
: m_sink(&m_src)
{
    QGst::init(0, NULL);

   // Master pipeline setup

    _ms_pipeline = QGst::Pipeline::create("mypipe");
    if (!_ms_pipeline)
    {
        qDebug() << "MasterSink: Failed creating pipeline !!!";
        return;
    }
    _ms_pipeline->setState(QGst::StateNull);

    _ms_adder = QGst::ElementFactory::make("adder","audiomixer");
    _ms_pipeline->add(_ms_adder);

    _ms_output = QGst::ElementFactory::make("autoaudiosink","audio_out");
    _ms_pipeline->add(_ms_output);

    if (!_ms_adder->link(_ms_output))
    {
        qDebug() << "MasterSink: Failed linking to _output !!!";
        return;
    }

    _ms_pipeline->setState(QGst::StateReady);
    std::cout << "_ms_pipeline: StateReady\n";


    // This 2nd pipeline loads the file, decodes it and sends the audio
stream to the master pipeline

    QGst::PipelinePtr pipeline = QGst::Pipeline::create();

    QGst::ElementPtr filesrc = QGst::ElementFactory::make("filesrc");
    filesrc->setProperty("location", filename);
    pipeline->add(filesrc);

    QGst::BinPtr decodebin =
QGst::ElementFactory::make("decodebin2").dynamicCast<QGst::Bin>();
    pipeline->add(decodebin);
    if (!filesrc->link(decodebin))
    {
        qDebug() << "Failed: filesrc > decodebin !!!";
        return;
    }

    appsink = QGst::ElementFactory::make("appsink");
    pipeline->add(appsink);

    m_sink.setElement(appsink);

    QGst::ElementPtr appsrc = QGst::ElementFactory::make("appsrc");
    m_src.setElement(appsrc);
    m_src.setFormat(QGst::FormatDefault);

    _ms_pipeline->add(appsrc);

    QGst::ElementPtr vol = QGst::ElementFactory::make("volume");
    vol->setProperty("volume", 0.7);
    QGst::ElementPtr convert = QGst::ElementFactory::make("audioconvert");
    QGst::ElementPtr resample = QGst::ElementFactory::make("audioresample");

    QGst::ElementPtr filtercaps = QGst::ElementFactory::make("capsfilter");
    filtercaps->setProperty("caps",
QGst::Caps::fromString("audio/x-raw-int, endianness=(int)1234,
channels=(int)1, width=(int)16, depth=(int)16, signed=(boolean)true,
rate=(int)11025"));

    _ms_pipeline->add(vol);
    _ms_pipeline->add(convert);
    _ms_pipeline->add(resample);
    _ms_pipeline->add(filtercaps);

    if (!appsrc->link(vol))
    {
        qDebug() << "Failed: appsrc > vol !!!";
        return;
    }

    if (!vol->link(convert))
    {
        qDebug() << "Failed: filesrc > decodebin !!!";
        return;
    }

    if (!convert->link(resample))
    {
        qDebug() << "Failed: filesrc > decodebin !!!";
        return;
    }

    if (!resample->link(filtercaps))
    {
        qDebug() << "Failed: filesrc > decodebin !!!";
        return;
    }

    QGst::PadPtr sinkpad = _ms_adder->getRequestPad("sink%d");
    if (!sinkpad)
    {
        qDebug() << "Failed: sinkpad !!!";
        return;
    }

    QGst::PadPtr saidaConverters = filtercaps->getStaticPad("src");
    if (saidaConverters->link(sinkpad) != QGst::PadLinkOk)
    {
        qDebug() << "Failed: saida > sinkpad !!!";
        return;
    }

    QGlib::connect(decodebin, "pad-added", this, &Player::onNewDecodedPad);

    pipeline->setState(QGst::StatePlaying);
    std::cout << "pipeline: StatePlaying\n";

    QGst::State state;
    pipeline->getState(&state, NULL, 0);
    std::cout << "pipeline: state is " << state << " while playing would
be: " << QGst::StatePlaying << "\n";


    QGst::State ms_state;
    _ms_pipeline->getState(&ms_state, NULL, 0);
    if (ms_state != QGst::StatePlaying)
    {
        std::cout << "_ms_pipeline: StatePlaying *AGAIN* was: " << ms_state
<< "\n";
        _ms_pipeline->setState(QGst::StateNull);
        _ms_pipeline->setState(QGst::StatePlaying);
    }

    _ms_pipeline->getState(&ms_state, NULL, 0);
    std::cout << "_ms_pipeline: state is " << ms_state << "\n";
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20111123/77590e5b/attachment.htm>


More information about the gstreamer-devel mailing list