static void
test_io_stream_properties (NiceAddress *addr)
{
  NiceAgent *agent;
  guint stream_id;
  GIOStream *io_stream;
  GInputStream *input_stream;
  GOutputStream *output_stream;

  agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245);
  nice_agent_add_local_address (agent, addr);

  stream_id = nice_agent_add_stream (agent, 1);

  /* Try building an I/O stream around it. */
  io_stream = nice_agent_get_io_stream (agent, stream_id, 1);
  g_assert (G_IS_IO_STREAM (io_stream));
  g_assert (NICE_IS_IO_STREAM (io_stream));

  /* Check various initial properties. */
  g_assert (!g_io_stream_is_closed (G_IO_STREAM (io_stream)));
  g_assert (!g_io_stream_has_pending (G_IO_STREAM (io_stream)));

  /* Check the input stream’s properties. */
  input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_INPUT_STREAM (input_stream));
  g_assert (NICE_IS_INPUT_STREAM (input_stream));

  g_assert (!g_input_stream_is_closed (input_stream));
  g_assert (!g_input_stream_has_pending (input_stream));

  /* Check the output stream’s properties. */
  output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_OUTPUT_STREAM (output_stream));
  g_assert (NICE_IS_OUTPUT_STREAM (output_stream));

  g_assert (!g_output_stream_is_closing (output_stream));
  g_assert (!g_output_stream_is_closed (output_stream));
  g_assert (!g_output_stream_has_pending (output_stream));

  /* Remove the component and check that the I/O streams close. */
  nice_agent_remove_stream (agent, stream_id);

  g_assert (g_io_stream_is_closed (G_IO_STREAM (io_stream)));
  g_assert (g_input_stream_is_closed (input_stream));
  g_assert (g_output_stream_is_closed (output_stream));

  g_object_unref (io_stream);
  g_object_unref (agent);
}
static GSource *
nice_output_stream_create_source (GPollableOutputStream *stream,
    GCancellable *cancellable)
{
  NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
  GSource *component_source = NULL;
  NiceComponent *component = NULL;
  NiceStream *_stream = NULL;
  NiceAgent *agent;  /* owned */

  component_source = g_pollable_source_new (G_OBJECT (stream));

  if (cancellable) {
    GSource *cancellable_source = g_cancellable_source_new (cancellable);

    g_source_set_dummy_callback (cancellable_source);
    g_source_add_child_source (component_source, cancellable_source);
    g_source_unref (cancellable_source);
  }

  /* Closed streams cannot have sources. */
  if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream)))
    return component_source;

  /* Has the agent disappeared? */
  agent = g_weak_ref_get (&priv->agent_ref);
  if (agent == NULL)
    return component_source;

  agent_lock ();

  /* Grab the socket for this component. */
  if (!agent_find_component (agent, priv->stream_id, priv->component_id,
          &_stream, &component)) {
    g_warning ("Could not find component %u in stream %u", priv->component_id,
        priv->stream_id);
    goto done;
  }

   if (component->tcp_writable_cancellable) {
    GSource *cancellable_source =
        g_cancellable_source_new (component->tcp_writable_cancellable);

    g_source_set_dummy_callback (cancellable_source);
    g_source_add_child_source (component_source, cancellable_source);
    g_source_unref (cancellable_source);
  }

done:
  agent_unlock ();

  g_object_unref (agent);

  return component_source;
}
static gboolean
nice_output_stream_is_writable (GPollableOutputStream *stream)
{
  NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
  NiceComponent *component = NULL;
  NiceStream *_stream = NULL;
  gboolean retval = FALSE;
  NiceAgent *agent;  /* owned */

  /* Closed streams are not writeable. */
  if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream)))
    return FALSE;

  /* Has the agent disappeared? */
  agent = g_weak_ref_get (&priv->agent_ref);
  if (agent == NULL)
    return FALSE;

  agent_lock ();

  if (!agent_find_component (agent, priv->stream_id, priv->component_id,
          &_stream, &component)) {
    g_warning ("Could not find component %u in stream %u", priv->component_id,
        priv->stream_id);
    goto done;
  }
  if (component->selected_pair.local != NULL) {
    NiceSocket *sockptr = component->selected_pair.local->sockptr;

    /* If it’s a reliable agent, see if there’s any space in the pseudo-TCP
     * output buffer. */
    if (!nice_socket_is_reliable (sockptr)) {
      retval = pseudo_tcp_socket_can_send (component->tcp);
    } else {
      retval = (g_socket_condition_check (sockptr->fileno, G_IO_OUT) != 0);
    }
  }

done:
  agent_unlock ();

  g_object_unref (agent);

  return retval;
}
static gssize
nice_output_stream_write_nonblocking (GPollableOutputStream *stream,
    const void *buffer, gsize count, GError **error)
{
  NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv;
  NiceAgent *agent;  /* owned */
  gint n_sent;

  /* Closed streams are not writeable. */
  if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream))) {
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
        "Stream is closed.");
    return -1;
  }

  /* Has the agent disappeared? */
  agent = g_weak_ref_get (&priv->agent_ref);
  if (agent == NULL) {
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
        "Stream is closed due to the NiceAgent being finalised.");
    return -1;
  }

  if (count == 0) {
    n_sent = 0;
    goto done;
  }

  n_sent = nice_agent_send (agent, priv->stream_id, priv->component_id,
      count, buffer);

  if (n_sent == -1)
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
        g_strerror (EAGAIN));

 done:

  g_object_unref (agent);

  return n_sent;
}
static void
soup_cache_input_stream_write_next_buffer (SoupCacheInputStream *istream)
{
	SoupCacheInputStreamPrivate *priv = istream->priv;
	SoupBuffer *buffer = g_queue_pop_head (priv->buffer_queue);
	int priority;

	g_assert (priv->output_stream && !g_output_stream_is_closed (priv->output_stream));

	g_clear_pointer (&priv->current_writing_buffer, soup_buffer_free);
	priv->current_writing_buffer = buffer;

	if (priv->buffer_queue->length > 10)
		priority = G_PRIORITY_DEFAULT;
	else
		priority = G_PRIORITY_LOW;

	g_output_stream_write_async (priv->output_stream, buffer->data, buffer->length,
				     priority, priv->cancellable,
				     (GAsyncReadyCallback) write_ready_cb,
				     g_object_ref (istream));
}
static void
nice_output_stream_dispose (GObject *object)
{
  NiceOutputStream *self = NICE_OUTPUT_STREAM (object);
  NiceAgent *agent;

  /* Ensure the stream is closed first, otherwise the agent can’t be found in
   * the close handler called by the parent implementation. */
  if (!g_output_stream_is_closed (G_OUTPUT_STREAM (object)))
    g_output_stream_close (G_OUTPUT_STREAM (object), NULL, NULL);

  agent = g_weak_ref_get (&self->priv->agent_ref);
  if (agent != NULL) {
    g_signal_handlers_disconnect_by_func (agent, streams_removed_cb, self);
    g_object_unref (agent);
  }

  g_weak_ref_clear (&self->priv->agent_ref);

  g_clear_object (&self->priv->closed_cancellable);

  G_OBJECT_CLASS (nice_output_stream_parent_class)->dispose (object);
}
static gboolean
gst_gio_base_sink_start (GstBaseSink * base_sink)
{
  GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
  GstGioBaseSinkClass *gbsink_class = GST_GIO_BASE_SINK_GET_CLASS (sink);

  sink->position = 0;

  /* FIXME: This will likely block */
  sink->stream = gbsink_class->get_stream (sink);
  if (G_UNLIKELY (!G_IS_OUTPUT_STREAM (sink->stream))) {
    GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
        ("No output stream provided by subclass"));
    return FALSE;
  } else if (G_UNLIKELY (g_output_stream_is_closed (sink->stream))) {
    GST_ELEMENT_ERROR (sink, LIBRARY, FAILED, (NULL),
        ("Output stream is already closed"));
    return FALSE;
  }

  GST_DEBUG_OBJECT (sink, "started sink");

  return TRUE;
}
static gssize
nice_output_stream_write (GOutputStream *stream, const void *buffer, gsize count,
    GCancellable *cancellable, GError **error)
{
  NiceOutputStream *self = NICE_OUTPUT_STREAM (stream);
  const gchar* buf = buffer;
  gssize len = 0;
  gint n_sent;
  NiceAgent *agent = NULL;  /* owned */
  gulong cancel_id = 0, closed_cancel_id, writeable_id;
  WriteData *write_data;

  /* Closed streams are not writeable. */
  if (g_output_stream_is_closed (stream)) {
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
        "Stream is closed.");
    return -1;
  }

  /* Has the agent disappeared? */
  agent = g_weak_ref_get (&self->priv->agent_ref);
  if (agent == NULL) {
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
        "Stream is closed due to the NiceAgent being finalised.");
    return -1;
  }

  if (count == 0) {
    g_object_unref (agent);
    return 0;
  }

  /* FIXME: nice_agent_send() is non-blocking, which is a bit unexpected
   * since nice_agent_recv() is blocking. Currently this uses a fairly dodgy
   * GCond solution; would be much better for nice_agent_send() to block
   * properly in the main loop. */
  write_data = g_slice_new0 (WriteData);
  write_data->ref_count = 1;
  g_mutex_init (&write_data->mutex);
  g_cond_init (&write_data->cond);

  if (cancellable != NULL) {
    cancel_id = g_cancellable_connect (cancellable,
        (GCallback) write_cancelled_cb, write_data_ref (write_data),
        (GDestroyNotify) write_data_unref);
  }

  closed_cancel_id = g_cancellable_connect (self->priv->closed_cancellable,
      (GCallback) write_cancelled_cb, write_data_ref (write_data),
      (GDestroyNotify) write_data_unref);

  g_mutex_lock (&write_data->mutex);

  writeable_id = g_signal_connect_data (G_OBJECT (agent),
      "reliable-transport-writable",
      (GCallback) reliable_transport_writeable_cb, write_data_ref (write_data),
      (GClosureNotify) write_data_unref, 0);


  do {
    /* Have to unlock while calling into the agent because
     * it will take the agent lock which will cause a deadlock if one of
     * the callbacks is called.
     */
    if (g_cancellable_is_cancelled (cancellable) ||
        g_cancellable_is_cancelled (self->priv->closed_cancellable))
      break;

    write_data->writable = FALSE;
    g_mutex_unlock (&write_data->mutex);

    n_sent = nice_agent_send (agent, self->priv->stream_id,
        self->priv->component_id, count - len, buf + len);

    g_mutex_lock (&write_data->mutex);

    if (n_sent <= 0) {
      if (!write_data->writable && !write_data->cancelled)
        g_cond_wait (&write_data->cond, &write_data->mutex);
    } else if (n_sent > 0) {
      /* Success. */
      len += n_sent;
    }
  } while ((gsize) len < count);

  g_signal_handler_disconnect (G_OBJECT (agent), writeable_id);
  g_mutex_unlock (&write_data->mutex);

  if (cancel_id)
    g_cancellable_disconnect (cancellable, cancel_id);
  g_cancellable_disconnect (self->priv->closed_cancellable, closed_cancel_id);

  if (len == 0) {
    len = -1;
    if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
      if (g_cancellable_is_cancelled (self->priv->closed_cancellable))
        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
            "Stream has been removed from agent");
    }
  }

  write_data_unref (write_data);

  g_object_unref (agent);
  g_assert (len != 0);

  return len;
}
static VALUE
rg_closed_p(VALUE self)
{
        return CBOOL2RVAL(g_output_stream_is_closed(_SELF(self)));
}