0
votes

I'm a newbie in gstreamer and I can simply use gst-launch to play a PCM file like this:

$ gst-launch-1.0 filesrc location=output.pcm ! audio/x-raw, format=S16LE, 
channels=1, rate=16000 ! autoaudiosink

But In my application, what I got is a char array with PCM raw data. After google it, I know that I should use appsrc as a source, but the test code have no output at all.

Is there any example code can tell me how to play this char array which contains one channel 16K PCM raw data?

Here attached my test code:

std::ifstream file("output.pcm");
char data[22120];
file.read(data, 22120);
file.close();

std::cout << "read success";

GstElement *m_pipeline;
GstElement *m_source;
GMainLoop *m_loop;
GstBuffer *m_last_buffer;
GstElement *m_sink;
GstCaps *audioCaps;

gst_init(NULL, NULL);

audioCaps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, "S16LE", "rate", G_TYPE_INT, 16000,
                                "channels", G_TYPE_INT, 1, nullptr);

if (audioCaps == nullptr)
{
    std::cout << "error" << std::endl;
    return 0;
}

m_source = gst_element_factory_make("appsrc", "source");
m_sink = gst_element_factory_make("autoaudiosink", "sink");
m_pipeline = gst_pipeline_new("audio-pipeline");
m_loop = g_main_loop_new(NULL, FALSE);

gst_bin_add_many(GST_BIN(m_pipeline), m_source, m_sink, NULL);
gst_element_link_many(m_source, m_sink, NULL);

gst_app_src_set_caps(GST_APP_SRC(m_source), audioCaps);

gst_caps_unref(audioCaps);

GstBuffer *buffer = gst_buffer_new_allocate(NULL, 22120, NULL);
gst_buffer_fill(buffer, 0, data, 22120);
gst_app_src_push_buffer(GST_APP_SRC(m_source), buffer);

gst_element_set_state(m_pipeline, GST_STATE_PLAYING);

g_main_loop_run(m_loop);

/* free resources */
gst_element_set_state(m_pipeline, GST_STATE_NULL);
gst_object_unref(m_pipeline);
1

1 Answers

0
votes

Step 1. To create my own input test file:

gst-launch-1.0 audiotestsrc num-buffers=10 ! audio/x-raw, channels=1, rate=16000, format=S16LE ! filesink location=out.raw

Step 2. Here is a sample application:

#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <stdio.h>

int main()
{
    gst_init(NULL, NULL);

    GstElement* p = gst_parse_launch("appsrc name=src ! audio/x-raw, channels=1, rate=16000, format=S16LE ! autoaudiosink", NULL);
    GstElement* appsrc = gst_bin_get_by_name(GST_BIN(p), "src");
    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(p));

    gst_element_set_state(p, GST_STATE_PLAYING);

    FILE* fp = fopen("out.raw", "rb");

    for (int i  = 0; i < 10; i++) {
            gchar buf[2048];

            fread(buf, 2048, 1, fp);

            GstBuffer *buffer = gst_buffer_new_allocate(NULL, 2048, NULL);
            gst_buffer_fill(buffer, 0, buf, 2048);
            gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
    }
    gst_app_src_end_of_stream(GST_APP_SRC(appsrc));

    gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);

    gst_element_set_state(p, GST_STATE_NULL);

    gst_object_unref(bus);
    gst_object_unref(appsrc);
    gst_object_unref(p);

    fclose(fp);
}

It simplifies a few things by using gst_parse_launch(). The complete pipeline creation and cap setting.

Further to make things simpler, the created sample file is 2048 bytes * 10 chunks. You don't need to know the original chunk size (as long as it is sample aligned - which is 2 bytes for 1 channel and 16 bit). I just didn't want to check for the file's EOF.

Basically, I think you should put the pipeline into PLAYING state before sending it any data.