A blog by Devendra Tewari
The fdsink
element is useful because it can be used to write data directly to a socket. In this post, we’ll see how to setup a listener for client connections and stream directly to the client socket using fdsink
.
The code below sets up a server socket to listen for incoming client connections. Once a client connects, we send the appropriate HTTP headers, and call the function that will stream data to the client socket using fdsink
. You can find the make_socket
function in the GNU libc manual.
gpointer
client_thread(gpointer data)
{
int BUF_SIZE = 256;
char buffer[BUF_SIZE+1];
int client = (int)data;
int ret;
ret = read(client, buffer, BUF_SIZE);
while(ret != -1)
{
buffer[ret] = 0;
g_print("%s", buffer);
if (ret > 3 && strncmp(buffer, "GET", 3) == 0)
{
send(client, "HTTP/1.0 200 OK\r\n", 17, 0);
send(client, "Connection: close\r\n", 19, 0);
send(client, "Content-Type: video/webm\r\n", 26, 0);
send(client, "\r\n", 2, 0);
//... create pipeline with fdsink
}
ret = read((int)data, buffer, BUF_SIZE);
}
}
gpointer
server_thread(gpointer data)
{
int sock, client;
struct sockaddr_in addr;
size_t size;
g_print("Server thread started\n");
sock = make_socket(9001);
while(1)
{
if (listen (sock, 1) < 0)
{
g_printerr ("listener failed");
exit (EXIT_FAILURE);
}
size = sizeof(addr);
client = accept(sock, (struct sockaddr *)&addr, &size);
if (client < 0)
{
g_printerr ("accept failed");
continue;
}
g_print("connect from host %s, port %d.\n",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
g_thread_create(client_thread, (gpointer)client, TRUE, NULL);
}
}
The server above can be executed in its own thread—we use glib—thus
sthread = g_thread_create(server_thread, NULL, TRUE, NULL);
The following code snippet demonstrates how fdsink
can be setup
sink = gst_element_factory_make ("fdsink", NULL);
g_object_set (G_OBJECT (sink), "fd", client, NULL);
A client can disconnect without a warning, fdsink
does not provide any mechanism to handle such as situation. The whole pipeline can end if a single client disconnects. Luckily, the multifdsink
can be used in such a scenario, as it handles client disconnection more gracefully. The num-fds
property can be polled to detect that there are no pending clients.
Create a multifdsink
thus
sink = gst_element_factory_make ("multifdsink", NULL);
After starting the pipeline, add a new socket fd thus
g_signal_emit_by_name(sink, "add", client, G_TYPE_NONE);
The multifdsink
element has a bug that causes 100% CPU usage, but has been fixed in version 0.10.33 of GStreamer.
The following headers contain the declarations required to compile the code above
#include <gst/gst.h>
#include <glib.h>
#include <sys/socket.h>
#include <netinet/in.h>
That’s all there is to it.