
<!-- ############ chapter ############# -->

<chapter id="chapter-other-sink" xreflabel="Writing a Sink">
  <title>Writing a Sink</title>
  <para>
    Sinks are output elements that, opposite to sources, have no source
    pads and one or more (usually one) sink pad. They can be sound card
    outputs, disk writers, etc. This chapter will discuss the basic
    implementation of sink elements.
  </para>

  <sect1 id="other-sink-processing" xreflabel="Data processing, events, synchronization and clocks">
    <title>Data processing, events, synchronization and clocks</title>
    <para>
      Except for corner cases, sink elements will be <function>_chain
      ()</function>-based elements. The concept of such elements has
      been discussed before in detail, so that will be skipped here. What
      is very important in sink elements, specifically in real-time audio
      and video sources (such as <classname>osssink</classname> or
      <classname>ximagesink</classname>), is event handling in the
      <function>_chain ()</function>-function, because most elements rely
      on EOS-handling of the sink element, and because A/V synchronization
      can only be perfect if the element takes this into account.
    </para>
    <para>
      How to achieve synchronization between streams depends on whether
      you're a clock-providing or a clock-receiving element. If you're
      the clock provider, you can do with time whatever you want. Correct
      handling would mean that you check whether the end of the previous
      buffer (if any) and the start of the current buffer are the same.
      If so, there's no gap between the two and you can continue playing
      right away. If there is a gap, then you'll need to wait for your
      clock to reach that time. How to do that depends on the element
      type. In the case of audio output elements, you would output silence
      for a while. In the case of video, you would show background color.
      In case of subtitles, show no subtitles at all.
    </para>
    <para>
      In the case that the provided clock and the received clock are not
      the same (or in the case where your element provides no clock, which
      is the same), you simply wait for the clock to reach the timestamp of
      the current buffer and then you handle the data in it.
    </para>
    <para>
      A simple data handling function would look like this:
    </para>
    <programlisting>
static void
gst_my_sink_chain (GstPad  *pad,
		   GstData *data)
{
  GstMySink *sink = GST_MY_SINK (gst_pad_get_parent (pad));
  GstBuffer *buf;
  GstClockTime time;

  /* only needed if the element is GST_EVENT_AWARE */
  if (GST_IS_EVENT (data)) {
    GstEvent *event = GST_EVENT (data);

    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_EOS:
        [ if your element provides a clock, disable (inactivate) it here ]
        /* pass-through */

      default:
        /* the default handler handles discontinuities, even if your
         * element provides a clock! */
        gst_pad_event_default (pad, event);
        break;
    }

    return;
  }

  buf = GST_BUFFER (data);
  if (GST_BUFFER_TIME_IS_VALID (buf))
    time = GST_BUFFER_TIMESTAMP (buf);
  else
    time = sink->expected_next_time;

  /* Synchronization - the property is only useful in case the
   * element has the option of not syncing. So it is not useful
   * for hardware-sync (clock-providing) elements. */
  if (sink->sync) {
    /* This check is only needed if you provide a clock. Else,
     * you can always execute the 'else' clause. */
    if (sink->provided_clock == sink->received_clock) {
      /* GST_SECOND / 10 is 0,1 sec, it's an arbitrary value. The
       * casts are needed because else it'll be unsigned and we
       * won't detect negative values. */
      if (llabs ((gint64) sink->expected_next_time - (gint64) time) >
            (GST_SECOND / 10)) {
        /* so are we ahead or behind? */
        if (time > sink->expected_time) {
          /* we need to wait a while... In case of audio, output
           * silence. In case of video, output background color.
           * In case of subtitles, display nothing. */
          [..]
        } else {
          /* Drop data. */
          [..]
        }
      }
    } else {
      /* You could do more sophisticated things here, but we'll
       * keep it simple for the purpose of the example. */
      gst_element_wait (GST_ELEMENT (sink), time);
    }
  }

  /* And now handle the data. */
[..]
}
    </programlisting>
  </sect1>

  <sect1 id="other-sink-buffers" xreflabel="Special memory">
    <title>Special memory</title>
    <para>
      Like source elements, sink elements can sometimes provide externally
      allocated (such as X-provided or DMA'able) memory to elements earlier
      in the pipeline, and thereby prevent the need for
      <function>memcpy ()</function> for incoming data. We do this by
      providing a pad-allocate-buffer function.
    </para>
    <programlisting>
static GstBuffer *	gst_my_sink_buffer_allocate	(GstPad *pad,
							 guint64 offset,
							 guint   size);

static void
gst_my_sink_init (GstMySink *sink)
{
[..]
  gst_pad_set_bufferalloc_function (sink->sinkpad,
                                    gst_my_sink_buffer_allocate);
}

static void
gst_my_sink_buffer_free (GstBuffer *buf)
{
  GstMySink *sink = GST_MY_SINK (GST_BUFFER_PRIVATE (buf));

  /* Do whatever is needed here. */
[..]
}

static GstBuffer *
gst_my_sink_buffer_allocate (GstPad *pad,
			     guint64 offset,
			     guint   size)
{
  GstBuffer *buf = gst_buffer_new ();

  /* So here it's up to you to wrap your private buffers and
   * return that. */
  GST_BUFFER_FREE_DATA_FUNC (buf) = gst_my_sink_buffer_free;
  GST_BUFFER_PRIVATE (buf) = sink;
  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
[..]

  return buf;
}
    </programlisting>
  </sect1>
</chapter>
