Example #1
0
static GstFlowReturn
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstUDPSrc *udpsrc;
  GstBuffer *outbuf;
  gsize offset;
  gssize readsize;
  gssize res;
  gboolean try_again;
  GError *err = NULL;

  udpsrc = GST_UDPSRC_CAST (psrc);

retry:
  /* quick check, avoid going in select when we already have data */
  readsize = g_socket_get_available_bytes (udpsrc->used_socket);
  if (readsize > 0)
    goto no_select;

  do {
    gint64 timeout;

    try_again = FALSE;

    if (udpsrc->timeout)
      timeout = udpsrc->timeout / 1000;
    else
      timeout = -1;

    GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GUINT64_FORMAT,
        timeout);

    if (!g_socket_condition_timed_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
            timeout, udpsrc->cancellable, &err)) {
      if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
          || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
        goto stopped;
      } else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
        g_clear_error (&err);
        /* timeout, post element message */
        gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
            gst_message_new_element (GST_OBJECT_CAST (udpsrc),
                gst_structure_new ("GstUDPSrcTimeout",
                    "timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
      } else {
        goto select_error;
      }

      try_again = TRUE;
    }
  } while (G_UNLIKELY (try_again));

  /* ask how much is available for reading on the socket, this should be exactly
   * one UDP packet. We will check the return value, though, because in some
   * case it can return 0 and we don't want a 0 sized buffer. */
  readsize = g_socket_get_available_bytes (udpsrc->used_socket);
  if (G_UNLIKELY (readsize < 0))
    goto get_available_error;

  /* If we get here and the readsize is zero, then either select was woken up
   * by activity that is not a read, or a poll error occurred, or a UDP packet
   * was received that has no data. Since we cannot identify which case it is,
   * we handle all of them. This could possibly lead to a UDP packet getting
   * lost, but since UDP is not reliable, we can accept this. */
  if (G_UNLIKELY (!readsize)) {
    /* try to read a packet (and it will be ignored),
     * in case a packet with no data arrived */
    res =
        g_socket_receive_from (udpsrc->used_socket, NULL, NULL,
        0, udpsrc->cancellable, &err);
    if (G_UNLIKELY (res < 0))
      goto receive_error;

    /* poll again */
    goto retry;
  }

no_select:
  GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize);

  /* sanity check value from _get_available_bytes(), which might be as
   * large as the kernel-side buffer on some operating systems */
  if (g_socket_get_family (udpsrc->used_socket) == G_SOCKET_FAMILY_IPV4)
    readsize = MIN (MAX_IPV4_UDP_PACKET_SIZE, readsize);

  ret = gst_pad_alloc_buffer (GST_BASE_SRC (udpsrc)->srcpad,
    GST_BUFFER_OFFSET_NONE, readsize, NULL, &outbuf);
  if (GST_FLOW_OK != ret)
    goto alloc_failed;

  offset = 0;

  res =
      g_socket_receive_from (udpsrc->used_socket, NULL,
                  (gchar *) GST_BUFFER_DATA (outbuf),
                  GST_BUFFER_SIZE (outbuf),
                  udpsrc->cancellable, &err);

  if (G_UNLIKELY (res < 0)) {
    /* EHOSTUNREACH for a UDP socket means that a packet sent with udpsink
     * generated a "port unreachable" ICMP response. We ignore that and try
     * again. */
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE)) {
      gst_buffer_unref (outbuf);
      outbuf = NULL;
      g_clear_error (&err);
      goto retry;
    }
    goto receive_error;
  }

  /* patch offset and size when stripping off the headers */
  if (G_UNLIKELY (udpsrc->skip_first_bytes != 0)) {
    if (G_UNLIKELY (readsize < udpsrc->skip_first_bytes))
      goto skip_error;

    offset += udpsrc->skip_first_bytes;
    res -= udpsrc->skip_first_bytes;
  }

  GST_BUFFER_OFFSET (outbuf) = offset;
  GST_BUFFER_SIZE (outbuf) = res;

  GST_LOG_OBJECT (udpsrc, "read %d bytes", (int) readsize);

  *buf = GST_BUFFER_CAST (outbuf);

  return ret;

  /* ERRORS */
select_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("select error: %s", err->message));
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
stopped:
  {
    GST_DEBUG ("stop called");
    g_clear_error (&err);
    return GST_FLOW_WRONG_STATE;
  }
get_available_error:
  {
    GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
        ("get available bytes failed"));
    return GST_FLOW_ERROR;
  }
alloc_failed:
  {
    GST_DEBUG ("Allocation failed");
    return ret;
  }
receive_error:
  {
    gst_buffer_unref (outbuf);

    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) ||
        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      g_clear_error (&err);
      return GST_FLOW_WRONG_STATE;
    } else {
      GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
          ("receive error %" G_GSSIZE_FORMAT ": %s", res, err->message));
      g_clear_error (&err);
      return GST_FLOW_ERROR;
    }
  }
skip_error:
  {
    gst_buffer_unref (outbuf);

    GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
        ("UDP buffer to small to skip header"));
    return GST_FLOW_ERROR;
  }
}
Example #2
0
static GstFlowReturn
gst_tcp_mix_src_pad_read (GstTCPMixSrcPad * pad, GstBuffer ** outbuf)
{
  GstTCPMixSrc *src = GST_TCP_MIX_SRC (GST_PAD_PARENT (pad));
  gssize avail, receivedBytes;
  GstMapInfo map;
  GError *err = NULL;

  /* if we have a client, wait for read */
  GST_LOG_OBJECT (pad, "asked for a buffer");

  if (!pad->client) {
    if (src->mode == MODE_LOOP)
      goto loop_read;
    else
      goto no_client;
  }

  /* read the buffer header */

read_available_bytes:
  avail = g_socket_get_available_bytes (pad->client);
  if (avail < 0) {
    goto socket_get_available_bytes_error;
  } else if (avail == 0) {
    GIOCondition condition;

    if (!g_socket_condition_wait (pad->client,
            G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, pad->cancellable, &err))
      goto socket_condition_wait_error;

    condition = g_socket_condition_check (pad->client,
        G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP);

    if ((condition & G_IO_ERR))
      goto socket_condition_error;
    else if ((condition & G_IO_HUP))
      goto socket_condition_hup;

    avail = g_socket_get_available_bytes (pad->client);
    if (avail < 0)
      goto socket_get_available_bytes_error;
  }

  if (0 < avail) {
    gsize readBytes = MIN (avail, MAX_READ_SIZE);
    *outbuf = gst_buffer_new_and_alloc (readBytes);
    gst_buffer_map (*outbuf, &map, GST_MAP_READWRITE);
    receivedBytes = g_socket_receive (pad->client, (gchar *) map.data,
        readBytes, pad->cancellable, &err);
  } else {
    /* Connection closed */
    receivedBytes = 0;
    *outbuf = NULL;
  }

  if (receivedBytes == 0)
    goto socket_connection_closed;
  else if (receivedBytes < 0)
    goto socket_receive_error;

  gst_buffer_unmap (*outbuf, &map);
  gst_buffer_resize (*outbuf, 0, receivedBytes);

#if 0
  GST_LOG_OBJECT (pad,
      "Returning buffer from _get of size %" G_GSIZE_FORMAT
      ", ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
      ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
      gst_buffer_get_size (*outbuf),
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
      GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
#endif

  g_clear_error (&err);

  return GST_FLOW_OK;

  /* Handling Errors */
no_client:
  {
    GST_ELEMENT_ERROR (pad, RESOURCE, READ, (NULL),
        ("No client socket (%s)", GST_PAD_NAME (pad)));

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_ERROR;
  }

socket_get_available_bytes_error:
  {
    GST_ELEMENT_ERROR (pad, RESOURCE, READ, (NULL),
        ("Failed to get available bytes from socket"));

    gst_tcp_mix_src_pad_reset (pad);

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_ERROR;
  }

socket_condition_wait_error:
  {
    GST_ELEMENT_ERROR (pad, RESOURCE, READ, (NULL),
        ("Select failed: %s", err->message));
    g_clear_error (&err);

    gst_tcp_mix_src_pad_reset (pad);

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_ERROR;
  }

socket_condition_error:
  {
    GST_ELEMENT_ERROR (pad, RESOURCE, READ, (NULL), ("Socket in error state"));
    *outbuf = NULL;

    gst_tcp_mix_src_pad_reset (pad);

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_ERROR;
  }

socket_condition_hup:
  {
    GST_DEBUG_OBJECT (pad, "Connection closed");
    *outbuf = NULL;

    gst_tcp_mix_src_pad_reset (pad);

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_EOS;
  }

socket_connection_closed:
  {
    GST_DEBUG_OBJECT (pad, "Connection closed");
    if (*outbuf) {
      gst_buffer_unmap (*outbuf, &map);
      gst_buffer_unref (*outbuf);
    }
    *outbuf = NULL;

    gst_tcp_mix_src_pad_reset (pad);

    if (src->mode == MODE_LOOP)
      goto loop_read;
    return GST_FLOW_EOS;
  }

socket_receive_error:
  {
    gst_buffer_unmap (*outbuf, &map);
    gst_buffer_unref (*outbuf);
    *outbuf = NULL;

    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      GST_DEBUG_OBJECT (pad, "Cancelled reading from socket");

      if (src->mode == MODE_LOOP)
        goto loop_read;
      return GST_FLOW_FLUSHING;
    } else {
      GST_ELEMENT_ERROR (pad, RESOURCE, READ, (NULL),
          ("Failed to read from socket: %s", err->message));

      if (src->mode == MODE_LOOP)
        goto loop_read;
      return GST_FLOW_ERROR;
    }
  }

loop_read:
  {
#if 0
    GstEvent *event = gst_event_new_flush_start ();

    if (!gst_pad_push_event (pad, event)) {
      GST_ERROR_OBJECT (src, "Failed to flush data on %s.%s",
          GST_ELEMENT_NAME (src), GST_PAD_NAME (pad));
    }
#endif

#if 0
    GST_DEBUG_OBJECT (pad, "Looping");
#endif

    if (src->fill == FILL_NONE) {
      gst_tcp_mix_src_pad_wait_for_client (pad);
      goto read_available_bytes;
    }

    enum
    { buffer_size = 1024 };
    *outbuf = gst_buffer_new_and_alloc (buffer_size);

    switch (src->fill) {
      case FILL_ZERO:
        break;
      case FILL_RAND:
      {
        guchar *p;
        gst_buffer_map (*outbuf, &map, GST_MAP_READWRITE);
        for (p = map.data; p < map.data + buffer_size; p += 4) {
          *((int *) p) = rand ();
        }
      } break;
    }
    return GST_FLOW_OK;
  }
}
Example #3
0
static GstFlowReturn
gst_tcp_server_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
  GstTCPServerSrc *src;
  GstFlowReturn ret = GST_FLOW_OK;
  gssize rret, avail;
  gsize read;
  GError *err = NULL;
  GstMapInfo map;

  src = GST_TCP_SERVER_SRC (psrc);

  if (!GST_OBJECT_FLAG_IS_SET (src, GST_TCP_SERVER_SRC_OPEN))
    goto wrong_state;

  if (!src->client_socket) {
    /* wait on server socket for connections */
    src->client_socket =
        g_socket_accept (src->server_socket, src->cancellable, &err);
    if (!src->client_socket)
      goto accept_error;
    /* now read from the socket. */
  }

  /* if we have a client, wait for read */
  GST_LOG_OBJECT (src, "asked for a buffer");

  /* read the buffer header */
  avail = g_socket_get_available_bytes (src->client_socket);
  if (avail < 0) {
    goto get_available_error;
  } else if (avail == 0) {
    GIOCondition condition;

    if (!g_socket_condition_wait (src->client_socket,
            G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, src->cancellable, &err))
      goto select_error;

    condition =
        g_socket_condition_check (src->client_socket,
        G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP);

    if ((condition & G_IO_ERR)) {
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Socket in error state"));
      *outbuf = NULL;
      ret = GST_FLOW_ERROR;
      goto done;
    } else if ((condition & G_IO_HUP)) {
      GST_DEBUG_OBJECT (src, "Connection closed");
      *outbuf = NULL;
      ret = GST_FLOW_EOS;
      goto done;
    }
    avail = g_socket_get_available_bytes (src->client_socket);
    if (avail < 0)
      goto get_available_error;
  }

  if (avail > 0) {
    read = MIN (avail, MAX_READ_SIZE);
    *outbuf = gst_buffer_new_and_alloc (read);
    gst_buffer_map (*outbuf, &map, GST_MAP_READWRITE);
    rret =
        g_socket_receive (src->client_socket, (gchar *) map.data, read,
        src->cancellable, &err);
  } else {
    /* Connection closed */
    rret = 0;
    *outbuf = NULL;
    read = 0;
  }

  if (rret == 0) {
    GST_DEBUG_OBJECT (src, "Connection closed");
    ret = GST_FLOW_EOS;
    if (*outbuf) {
      gst_buffer_unmap (*outbuf, &map);
      gst_buffer_unref (*outbuf);
    }
    *outbuf = NULL;
  } else if (rret < 0) {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      ret = GST_FLOW_FLUSHING;
      GST_DEBUG_OBJECT (src, "Cancelled reading from socket");
    } else {
      ret = GST_FLOW_ERROR;
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Failed to read from socket: %s", err->message));
    }
    gst_buffer_unmap (*outbuf, &map);
    gst_buffer_unref (*outbuf);
    *outbuf = NULL;
  } else {
    ret = GST_FLOW_OK;
    gst_buffer_unmap (*outbuf, &map);
    gst_buffer_resize (*outbuf, 0, rret);

    GST_LOG_OBJECT (src,
        "Returning buffer from _get of size %" G_GSIZE_FORMAT ", ts %"
        GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
        ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
        gst_buffer_get_size (*outbuf),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
        GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
  }
  g_clear_error (&err);

done:
  return ret;

wrong_state:
  {
    GST_DEBUG_OBJECT (src, "connection to closed, cannot read data");
    return GST_FLOW_FLUSHING;
  }
accept_error:
  {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      GST_DEBUG_OBJECT (src, "Cancelled accepting of client");
    } else {
      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
          ("Failed to accept client: %s", err->message));
    }
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
select_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("Select failed: %s", err->message));
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
get_available_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("Failed to get available bytes from socket"));
    return GST_FLOW_ERROR;
  }
}