title: Using GStreamer to play raw PCM-data
body: <p>Ok, I have written some code below that is supposed to open and audio output device, and whenever actual PCM-data is available I would call Sound_WriteFrame() and pile up more data to be played.</p>
  
  <p>The data is raw, with no headers, so when I call Sound_Open() I pass this information to let GStreamer know what kind of data that will arrive.</p>
  
  <p>This code does not work - Frankly I have no idea what I am <em>doing</em>, I find GStreamer a bit difficult to work with, I would hope that could change eventually.</p>
  
  <p>I am using GStreamer 1.0. Help is appreciated.</p>
  
  <pre><code>#include &lt;gstreamer-1.0/gst/gst.h&gt;
  #include &lt;gstreamer-1.0/gst/gstelement.h&gt;
  #include &lt;gtk/gtk.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  typedef struct _sound_t {
      GstElement *source, *sink, *pipeline;
      GMemoryInputStream *giostream;
      GstPad *sourcepad;
      GstCaps *gcaps;
      int bDeviceOpen;
  } SOUND_CTX;
  
  int Sound_Close(SOUND_CTX *p){
      printf("Closing\n");
      gst_element_set_state(p-&gt;pipeline, GST_STATE_NULL);
      return 1;
  }
  
  void Sound_SetState(SOUND_CTX *p, GstState state){
      GstStateChangeReturn r = gst_element_set_state(p-&gt;pipeline, state);
      switch(r){
          case GST_STATE_CHANGE_FAILURE: printf("GST_STATE_CHANGE_FAILURE\n"); break;
          case GST_STATE_CHANGE_SUCCESS: printf("GST_STATE_CHANGE_SUCCESS\n"); break;
          case GST_STATE_CHANGE_ASYNC: printf("GST_STATE_CHANGE_ASYNC\n"); break;
          case GST_STATE_CHANGE_NO_PREROLL: printf("GST_STATE_CHANGE_NO_PREROLL\n"); break;
          default: printf("Unknown state\n"); break;
      }
      return;
  }
  
  int Sound_Open(SOUND_CTX *p, int nSamplesPerSec, int nChannels){
  
      p-&gt;source = gst_element_factory_make("giostreamsrc", "source");
      p-&gt;giostream = G_MEMORY_INPUT_STREAM(g_memory_input_stream_new());
      g_object_set(G_OBJECT(p-&gt;source), "stream", G_INPUT_STREAM(p-&gt;giostream), NULL);
      p-&gt;sourcepad = gst_element_get_static_pad(p-&gt;source, "src");
  
      p-&gt;gcaps = gst_caps_new_simple(
          "audio/x-raw",
          "rate", G_TYPE_INT, nSamplesPerSec,
          "channels", G_TYPE_INT, nChannels,
          "width", G_TYPE_INT, 16,
          "depth", G_TYPE_INT, 16,
          "signed", G_TYPE_BOOLEAN, TRUE,
          NULL
      );
  
      gst_pad_set_caps(p-&gt;sourcepad, p-&gt;gcaps);
      gst_object_unref(p-&gt;sourcepad);
  
      p-&gt;sink = gst_element_factory_make("alsasink", "sink");
      p-&gt;pipeline = gst_pipeline_new("pipeline_name");
      gst_bin_add_many(GST_BIN(p-&gt;pipeline), p-&gt;source, p-&gt;sink, NULL);
      gst_element_link_many(p-&gt;source, p-&gt;sink, NULL);
  
      Sound_SetState(p, GST_STATE_PLAYING);
  
      return 1;
  }
  
  int Sound_WriteFrame(SOUND_CTX *p, void *lpData, unsigned int size){
      g_memory_input_stream_add_data(
          G_MEMORY_INPUT_STREAM(p-&gt;giostream),
          lpData, size, NULL
      );
      return 0;
  }
  
  int timer_callback(const void *data){
      g_main_loop_quit((GMainLoop *)data);
      return FALSE;
  }
  
  
  
  int main(int argc, char *argv[]){
      gst_init(&amp;argc, &amp;argv);
      GMainLoop *loop = NULL;
      SOUND_CTX a;
      memset(&amp;a, 0x00, sizeof(SOUND_CTX));
      if(Sound_Open(&amp;a, 44100, 2)){
          FILE *handle;
          unsigned char tmp[4096];
          if((handle = fopen("test.pcm", "rb")) != NULL){
              while(fread(tmp, 1, sizeof(tmp), handle) == sizeof(tmp)){
                  Sound_WriteFrame(&amp;a, tmp, sizeof(tmp));
              }
              fclose(handle);
          }
      }
  
      loop = g_main_loop_new(NULL, FALSE);
      g_timeout_add(5500, (GSourceFunc)timer_callback, loop);
      g_main_loop_run(loop);
      Sound_Close(&amp;a);
      g_main_loop_unref(loop);
  
      return 0;
  }
  </code></pre>
  
  <p>Ok, so here is an updated source, there is however no sound coming out of the speakers</p>
  
  <pre><code>#include &lt;gstreamer-1.0/gst/gst.h&gt;
  #include &lt;gstreamer-1.0/gst/gstelement.h&gt;
  #include &lt;gstreamer-1.0/gst/app/gstappsrc.h&gt;
  #include &lt;gtk/gtk.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  typedef struct _sound_t {
      GstElement *sink, *pipeline;
      GstAppSrc *src;
      GstCaps *pcm_caps;
  } SOUND_CTX;
  
  int Sound_Close(SOUND_CTX *p){
      printf("Closing\n");
      gst_element_set_state(p-&gt;pipeline, GST_STATE_NULL);
      return 1;
  }
  
  void Sound_SetState(SOUND_CTX *p, GstState state){
      GstStateChangeReturn r = gst_element_set_state(p-&gt;pipeline, state);
      switch(r){
          case GST_STATE_CHANGE_FAILURE: printf("GST_STATE_CHANGE_FAILURE\n"); break;
          case GST_STATE_CHANGE_SUCCESS: printf("GST_STATE_CHANGE_SUCCESS\n"); break;
          case GST_STATE_CHANGE_ASYNC: printf("GST_STATE_CHANGE_ASYNC\n"); break;
          case GST_STATE_CHANGE_NO_PREROLL: printf("GST_STATE_CHANGE_NO_PREROLL\n"); break;
          default: printf("Unknown state\n"); break;
      }
      return;
  }
  
  int Sound_Open(SOUND_CTX *p, int nSamplesPerSec, int nChannels){
  
      p-&gt;pipeline = gst_pipeline_new("pipeline_name");
      p-&gt;sink = gst_element_factory_make("alsasink", "sink");
  
      p-&gt;src = (GstAppSrc*) gst_element_factory_make("appsrc", "source");
      gst_app_src_set_stream_type(p-&gt;src, GST_APP_STREAM_TYPE_STREAM);
  
      // I am hardcoding the format, channels, and rate for now
      p-&gt;pcm_caps = gst_caps_from_string("audio/x-raw,format=S16LE,rate=44100,channels=2");
      gst_app_src_set_caps(p-&gt;src, p-&gt;pcm_caps);
  
      gst_bin_add_many(GST_BIN(p-&gt;pipeline), (GstElement*)p-&gt;src, p-&gt;sink, NULL);
      gst_element_link_many((GstElement*)p-&gt;src, p-&gt;sink, NULL);
  
      Sound_SetState(p, GST_STATE_PLAYING);
  
      return 1;
  }
  
  int Sound_WriteFrame(SOUND_CTX *p, void *lpData, unsigned int size){
      GstBuffer *buf = NULL;
      void *lpHeapData = NULL;
      if((lpHeapData = g_malloc(size)) == NULL) return 0;
      memcpy(lpHeapData, lpData, size);
      buf = gst_buffer_new_wrapped(lpHeapData, size);
      if(buf == NULL){
          g_free(lpHeapData);
          return 0;
      }
      gst_app_src_push_buffer(p-&gt;src, buf);
      return 0;
  }
  
  int timer_callback(const void *data){
      g_main_loop_quit((GMainLoop *)data);
      return FALSE;
  }
  
  
  
  int main(int argc, char *argv[]){
      gst_init(&amp;argc, &amp;argv);
      GMainLoop *loop = NULL;
      SOUND_CTX a;
      memset(&amp;a, 0x00, sizeof(SOUND_CTX));
      if(Sound_Open(&amp;a, 44100, 2)){
          FILE *handle;
          unsigned char tmp[4096];
          if((handle = fopen("test.pcm", "rb")) != NULL){
              while(fread(tmp, 1, sizeof(tmp), handle) == sizeof(tmp)){
                  Sound_WriteFrame(&amp;a, tmp, sizeof(tmp));
              }
              fclose(handle);
          }
      }
  
      loop = g_main_loop_new(NULL, FALSE);
      g_timeout_add(5500, (GSourceFunc)timer_callback, loop);
      g_main_loop_run(loop);
      Sound_Close(&amp;a);
      g_main_loop_unref(loop);
  
      return 0;
  }
  </code></pre>