以下是我用于构建管道以在rtp流上传输原始pcm样本的代码。刚好当管道更改其状态为正在播放时,在消耗了来自函数push_buffer2的一个或两个数据包之后,管道会在其总线上生成一条错误消息,并显示以下错误:GstAppSrc错误已停止播放。未协商(-4)
static gboolean
push_buffer2(AppData * app)
{
gpointer raw_buffer;
GstBuffer *app_buffer;
GstMemory *mem;
GstFlowReturn ret;
app->num_frame++;
if (!app->isCallConnected && connectedCalls != 0) {
return TRUE;
}
char *data = app->dataQueue->pop();
if (data == NULL) {
data = (char*)malloc(sizeof(char) * 960);
memset(data, 0, 960);
}
app_buffer = gst_buffer_new();
//mem = gst_allocator_alloc(NULL, BUFFER_SIZE, NULL);
mem =
gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, data, 960,
0, 960,
NULL, NULL);
gst_buffer_append_memory(app_buffer, mem);
gst_buffer_set_size(app_buffer, BUFFER_SIZE);
/* Setting the correct timestamp for the buffer
is very important,
otherwise the
* resulting file won't be created correctly */
GST_BUFFER_TIMESTAMP(app_buffer) = (GstClockTime)((app->num_frame * 0.06)
* 1e9);
/* push new buffer */
g_signal_emit_by_name(app->source, "push-buffer", app_buffer, &ret);
gst_buffer_unref(app_buffer);
if (ret != GST_FLOW_OK) {
/* some error, stop sending data */
return FALSE;
}
//return TRUE;
return TRUE;
}
/* This signal callback is called when appsrc needs data, we add an idle handler
* to the mainloop to start pushing data into the appsrc */
static void
start_feed(GstElement * pipeline, guint size, AppData * app)
{
if (app->source_id == 0) {
//g_print("start feeding at frame %i\n", app->num_frame);
app->source_id = g_idle_add((GSourceFunc)push_buffer2, app);
}
}
/* This callback is called when appsrc has enough data
and we can stop sending.
* We remove the idle handler from the mainloop */
static void
stop_feed(GstElement * pipeline, AppData * app)
{
if (app->source_id != 0) {
//g_print("stop feeding at frame %i\n", app->num_frame);
g_source_remove(app->source_id);
app->source_id = 0;
}
}
static void runGstPipeline() {
GstBus *bus = NULL;
//GstElement *appsrc = NULL;
//GstElement *appsrc2 = NULL;
GstElement *pipeline, *mixer, *ac1, *mulawenc,
*rtppcmupay, *udpsink, *appsrc, *ac2, *ar, *wavenc,
*wavparse, *ac3;
GstCaps *caps = gst_caps_new_simple("audio/x-raw",
"format", G_TYPE_STRING, "S16LE",
"channels", G_TYPE_INT, 1,
"rate", G_TYPE_INT, 8000, NULL);
GstPad *adder_sinkpad1;
gst_init(NULL, NULL);
pipeline = gst_pipeline_new("audio-send-pipeline");
mixer = gst_element_factory_make("adder", "audio-mixer");
ac1 = gst_element_factory_make("audioconvert", "conv1");
mulawenc = gst_element_factory_make("mulawenc", "mulaw-enc");
rtppcmupay = gst_element_factory_make("rtppcmupay", "pay");
udpsink = gst_element_factory_make("udpsink", "sink");
g_object_set(udpsink,
"host", "127.0.0.1",
"port", 5000,
NULL);
appsrc = gst_element_factory_make("appsrc", "source1");
gst_app_src_set_caps(GST_APP_SRC(appsrc), caps);
ac2 = gst_element_factory_make("audioconvert", "conv2");
ar = gst_element_factory_make("audioresample", "resam1");
wavenc = gst_element_factory_make("wavenc", "enc1");
wavparse = gst_element_factory_make("wavparse", "parse1");
ac3 = gst_element_factory_make("audioconvert", "conv3");
if (!pipeline || !mixer || !ac1 || !mulawenc ||
!rtppcmupay || !udpsink || !appsrc || !ac2 || !ar || !wavenc
|| !wavparse || !ac3) {
g_printerr("One or more elements could not be created. Exiting\n");
return;
}
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bin_add_many(GST_BIN(pipeline),
mixer ,ac1 ,mulawenc ,rtppcmupay,udpsink
,appsrc ,ac2 ,ar ,wavenc ,wavparse ,ac3, NULL);
int n = 0;
if ((n = gst_element_link(mixer, ac1)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link mixer with caps-filter-1\n");
}
if ((n = gst_element_link(ac1, mulawenc)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link audio-convert-1 with mulawenc\n");
}
if ((n = gst_element_link(mulawenc, udpsink)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link mulawenc with udpsink\n");
}
if ((n = gst_element_link(appsrc, ac2)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link appsrc with caps-filter-2\n");
}
if ((n = gst_element_link(ac2, ar)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link audio-convert-2 with audio-resample\n");
}
if ((n = gst_element_link(ar, wavenc)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link audio-resample with wav-enc\n");
}
if ((n = gst_element_link(wavenc, wavparse)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link wav-enc with wav-parse\n");
}
if ((n = gst_element_link(wavparse, ac3)) == 0) {
g_print("link error: %d\n", n);
g_print("cannot link wav-parse with ac3\n");
}
adder_sinkpad1 = gst_element_get_request_pad(mixer, "sink_%u");
g_print("PadName : %s", gst_pad_get_name(adder_sinkpad1));
GstPad *srcPad = gst_element_get_static_pad(ac3, "src");
if ((n = gst_pad_link(srcPad, adder_sinkpad1)) != 0) {
g_print("pad error: %d\n", n);
g_print("cannot link audio-convert-3 with adder");
}
sendAppData = g_new0(AppData, 1);
sendAppData->pipeline = pipeline;
sendAppData->loop = g_main_loop_new(NULL, FALSE);
/* setting up pipeline, we push media data into this pipeline that will
* then be recorded to a file, encoded with a codec*/
if (sendAppData->pipeline == NULL) {
g_print("Bad pipeline\n");
return;
}
sendAppData->source = appsrc;
sendAppData->dataQueue = &dataQueue;
/* setting maximum of bytes queued */
gst_app_src_set_max_bytes((GstAppSrc *)appsrc, QUEUED_FRAMES * BUFFER_SIZE);
g_signal_connect(sendAppData->source, "need-data", G_CALLBACK(start_feed), sendAppData);
g_signal_connect(sendAppData->source, "enough-data", G_CALLBACK(stop_feed), sendAppData);
/* add watch for messages */
//bus = gst_element_get_bus(sendAppData->pipeline);
gst_bus_add_watch(bus, (GstBusFunc)on_pipeline_message, sendAppData);
gst_object_unref(bus);
/* configure the appsrc, we will push data into the appsrc from the
* mainloop */
gst_element_set_state(sendAppData->pipeline, GST_STATE_PLAYING);
sendAppData->dataQueue = new ThreadSafeQueue<char*>();
available.push(sendAppData);
/* this mainloop is stopped when we receive an error or EOS */
g_print("Creating movie...\n");
g_main_loop_run(sendAppData->loop);
g_print("Done.\n");
gst_element_set_state(sendAppData->pipeline, GST_STATE_NULL);
/* Cleaning up */
gst_object_unref(sendAppData->source);
gst_object_unref(sendAppData->pipeline);
g_main_loop_unref(sendAppData->loop);
g_free(sendAppData);
/* $$$$$$$$$$$$$$$$$$$$$$$$ STOP PIPELINE AND RETURN $$$$$$$$$$$$$$$$$$$$$$$$ */
}